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,14 @@ 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) { + local_iovec = *(__sanitizer_iovec *)data; + if (request == ptrace_setregset) + COMMON_INTERCEPTOR_READ_RANGE(ctx, local_iovec.iov_base, + local_iovec.iov_len); } } @@ -2481,8 +2487,8 @@ 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); + 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,7 @@ // // 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 +// REQUIRES: x86_64-supported-target,i386-supported-target,aarch64-supported-target #include #include @@ -12,6 +12,31 @@ #include #include #include +#include // for iovec +#include // for NT_PRSTATUS +#ifdef __aarch64__ +// GLIBC 2.20+ sys/user does not include asm/ptrace.h + #include +#endif + +#if defined(__i386__) || defined(__x86_64__) +typedef user_regs_struct regs_struct; +typedef user_fpregs_struct fpregs_struct; +#if defined(__i386__) +#define REG_PC eip +#else +#define REG_PC rip +#endif +#define REG_FPS cwd + +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +typedef struct user_fpsimd_state fpregs_struct; +#define REG_PC pc +#define REG_FPS fpsr +#define ARCH_IOVEC_FOR_GETREGSET +#endif + int main(void) { pid_t pid; @@ -21,28 +46,43 @@ execl("/bin/true", "true", NULL); } else { wait(NULL); - user_regs_struct regs; + user_pt_regs regs; + user_pt_regs* 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 + +#ifdef ARCH_IOVEC_FOR_GETREGSET + regset_io.iov_base = pregs; + regset_io.iov_len = sizeof(regs_struct); + res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, + (void*)®set_io); +#else res = ptrace(PTRACE_GETREGS, pid, NULL, pregs); +#endif // CHECK: AddressSanitizer: stack-buffer-overflow // CHECK: {{.*ptrace.cc:}}[[@LINE-2]] assert(!res); -#ifdef __x86_64__ - printf("%lx\n", (unsigned long)regs.rip); -#else - printf("%lx\n", regs.eip); -#endif + printf("%lx\n", (unsigned long)regs.REG_PC); - user_fpregs_struct fpregs; + fpregs_struct fpregs; +#ifdef ARCH_IOVEC_FOR_GETREGSET + regset_io.iov_base = &fpregs; + regset_io.iov_len = sizeof(regs_struct); + res = ptrace(PTRACE_GETREGSET, pid, (void*)NT_FPREGSET, + (void*)®set_io); +#else res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs); +#endif assert(!res); - printf("%lx\n", (unsigned long)fpregs.cwd); + printf("%lx\n", (unsigned long)fpregs.REG_FPS); -#ifndef __x86_64__ +#ifdef __i386__ user_fpxregs_struct fpxregs; res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs); assert(!res);