Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2446,6 +2446,7 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); + __sanitizer_iovec local_iovec; if (data) { if (request == ptrace_setregs) @@ -2456,9 +2457,15 @@ COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); else if (request == ptrace_setsiginfo) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); - else if (request == ptrace_setregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; - COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len); + // Some kernel might zero the iovec::iov_base in case of invalid + // write access. In this case copy the invalid address for further + // inspection. + else if (request == ptrace_setregset || request == ptrace_getregset) { + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); + local_iovec = *iovec; + if (request == ptrace_setregset) + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len); } } @@ -2481,8 +2488,10 @@ else if (request == ptrace_geteventmsg) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); else if (request == ptrace_getregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len); + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, + local_iovec.iov_len); } } return res; Index: test/asan/TestCases/Linux/ptrace.cc =================================================================== --- test/asan/TestCases/Linux/ptrace.cc +++ test/asan/TestCases/Linux/ptrace.cc @@ -3,7 +3,6 @@ // // RUN: %clangxx_asan -O0 %s -o %t && %run %t // RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// REQUIRES: x86_64-supported-target,i386-supported-target #include #include @@ -12,6 +11,52 @@ #include #include #include +#include // for iovec +#include // for NT_PRSTATUS + +#if defined(__i386__) || defined(__x86_64__) +typedef user_regs_struct regs_struct; +typedef user_fpregs_struct fpregs_struct; +#if defined(__i386__) +#define REG_IP eip +#else +#define REG_IP rip +#endif +#define PRINT_REG_PC(__regs) printf ("%lx\n", (unsigned long) (__regs.REG_IP)) +#define PRINT_REG_FP(__fpregs) printf ("%lx\n", (unsigned long) (__fpregs.cwd)) +#define __PTRACE_FPREQUEST PTRACE_GETFPREGS + +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +typedef struct user_fpsimd_state fpregs_struct; +#define PRINT_REG_PC(__regs) printf ("%x\n", (unsigned) (__regs.pc)) +#define PRINT_REG_FP(__fpregs) printf ("%x\n", (unsigned) (__fpregs.fpsr)) +#define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__powerpc64__) +typedef struct pt_regs regs_struct; +typedef elf_fpregset_t fpregs_struct; +#define PRINT_REG_PC(__regs) printf ("%lx\n", (unsigned long) (__regs.nip)) +#define PRINT_REG_FP(__fpregs) printf ("%lx\n", (elf_greg_t)fpregs[32]) +#define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__mips64) +typedef struct pt_regs regs_struct; +typedef elf_fpregset_t fpregs_struct; +#define PRINT_REG_PC(__regs) printf ("%lx\n", (unsigned long) (__regs.cp0_epc)) +#define PRINT_REG_FP(__fpregs) printf ("%lx\n", (elf_greg_t) (__fpregs[32])) +#define __PTRACE_FPREQUEST PTRACE_GETFPREGS + +#elif defined(__arm__) +# include +# include +typedef struct pt_regs regs_struct; +typedef char fpregs_struct[ARM_VFPREGS_SIZE]; +#define PRINT_REG_PC(__regs) printf ("%x\n", (unsigned) (__regs.ARM_pc)) +#define PRINT_REG_FP(__fpregs) printf ("%x\n", (unsigned) (__fpregs + 32 * 8)) +#define __PTRACE_FPREQUEST PTRACE_GETVFPREGS +#endif + int main(void) { pid_t pid; @@ -21,28 +66,48 @@ execl("/bin/true", "true", NULL); } else { wait(NULL); - user_regs_struct regs; + regs_struct regs; + regs_struct* volatile pregs = ®s; +#ifdef ARCH_IOVEC_FOR_GETREGSET + struct iovec regset_io; +#endif int res; - user_regs_struct * volatile pregs = ®s; + #ifdef POSITIVE ++pregs; #endif - res = ptrace(PTRACE_GETREGS, pid, NULL, pregs); + +#ifdef ARCH_IOVEC_FOR_GETREGSET +# define __PTRACE_REQUEST PTRACE_GETREGSET +# define __PTRACE_ARGS (void*)NT_PRSTATUS, (void*)®set_io + regset_io.iov_base = pregs; + regset_io.iov_len = sizeof(regs_struct); +#else +# define __PTRACE_REQUEST PTRACE_GETREGS +# define __PTRACE_ARGS NULL, pregs +#endif + res = ptrace((enum __ptrace_request)__PTRACE_REQUEST, pid, __PTRACE_ARGS); // CHECK: AddressSanitizer: stack-buffer-overflow // CHECK: {{.*ptrace.cc:}}[[@LINE-2]] assert(!res); -#ifdef __x86_64__ - printf("%lx\n", (unsigned long)regs.rip); + PRINT_REG_PC(regs); + + fpregs_struct fpregs; +#ifdef ARCH_IOVEC_FOR_GETREGSET +# define __PTRACE_FPREQUEST PTRACE_GETREGSET +# define __PTRACE_FPARGS (void*)NT_PRSTATUS, (void*)®set_io + regset_io.iov_base = &fpregs; + regset_io.iov_len = sizeof(fpregs_struct); + res = ptrace((enum __ptrace_request)PTRACE_GETREGSET, pid, (void*)NT_FPREGSET, + (void*)®set_io); #else - printf("%lx\n", regs.eip); +# define __PTRACE_FPARGS NULL, &fpregs #endif - - user_fpregs_struct fpregs; - res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs); + res = ptrace((enum __ptrace_request)__PTRACE_FPREQUEST, pid, __PTRACE_FPARGS); assert(!res); - printf("%lx\n", (unsigned long)fpregs.cwd); + PRINT_REG_FP(fpregs); -#ifndef __x86_64__ +#ifdef __i386__ user_fpxregs_struct fpxregs; res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs); assert(!res);