diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index e09a4a8ae25fd..6458009d1be90 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -41,6 +41,7 @@ #include "sanitizer_errno.h" #include "sanitizer_placement_new.h" #include "sanitizer_platform_interceptors.h" +#include "sanitizer_platform_limits_posix.h" #include "sanitizer_symbolizer.h" #include "sanitizer_tls_get_addr.h" @@ -3430,23 +3431,27 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); __sanitizer_iovec local_iovec; - if (data) { + void *data_arg = ptrace_data_arg(request, addr, data); + if (data_arg) { if (request == ptrace_setregs) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, struct_user_regs_struct_sz); } else if (request == ptrace_setfpregs) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, + struct_user_fpregs_struct_sz); } else if (request == ptrace_setfpxregs) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, + struct_user_fpxregs_struct_sz); } else if (request == ptrace_setvfpregs) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, + struct_user_vfpregs_struct_sz); } else if (request == ptrace_setsiginfo) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, siginfo_t_sz); - // Some kernel might zero the iovec::iov_base in case of invalid - // write access. In this case copy the invalid address for further - // inspection. + // 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; + __sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg; COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); local_iovec = *iovec; if (request == ptrace_setregset) @@ -3459,23 +3464,26 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { // https://github.com/google/sanitizers/issues/321. uptr res = REAL(ptrace)(request, pid, addr, data); - if (!res && data) { + if (!res && data_arg) { // Note that PEEK* requests assign different meaning to the return value. // This function does not handle them (nor does it need to). if (request == ptrace_getregs) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, struct_user_regs_struct_sz); } else if (request == ptrace_getfpregs) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, + struct_user_fpregs_struct_sz); } else if (request == ptrace_getfpxregs) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, + struct_user_fpxregs_struct_sz); } else if (request == ptrace_getvfpregs) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, + struct_user_vfpregs_struct_sz); } else if (request == ptrace_getsiginfo) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, siginfo_t_sz); } else if (request == ptrace_geteventmsg) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, sizeof(unsigned long)); } else if (request == ptrace_getregset) { - __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + __sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, local_iovec.iov_len); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc index 14615f9668dea..29fe4721ba40d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -48,6 +48,7 @@ #if SANITIZER_LINUX # include "sanitizer_libc.h" +# include "sanitizer_platform_limits_posix.h" # define PRE_SYSCALL(name) \ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name @@ -2530,18 +2531,19 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { # if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64) - if (data) { + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__)) + long data_arg = ptrace_data_arg(request, addr, data); + if (data_arg) { if (request == ptrace_setregs) { - PRE_READ((void *)data, struct_user_regs_struct_sz); + PRE_READ((void *)data_arg, struct_user_regs_struct_sz); } else if (request == ptrace_setfpregs) { - PRE_READ((void *)data, struct_user_fpregs_struct_sz); + PRE_READ((void *)data_arg, struct_user_fpregs_struct_sz); } else if (request == ptrace_setfpxregs) { - PRE_READ((void *)data, struct_user_fpxregs_struct_sz); + PRE_READ((void *)data_arg, struct_user_fpxregs_struct_sz); } else if (request == ptrace_setsiginfo) { - PRE_READ((void *)data, siginfo_t_sz); + PRE_READ((void *)data_arg, siginfo_t_sz); } else if (request == ptrace_setregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + __sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg; PRE_READ(iov->iov_base, iov->iov_len); } } @@ -2552,25 +2554,26 @@ POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { # if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64) - if (res >= 0 && data) { + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__)) + long data_arg = ptrace_data_arg(request, addr, data); + if (res >= 0 && data_arg) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. // PEEK* requests return resulting values through data pointer. if (request == ptrace_getregs) { - POST_WRITE((void *)data, struct_user_regs_struct_sz); + POST_WRITE((void *)data_arg, struct_user_regs_struct_sz); } else if (request == ptrace_getfpregs) { - POST_WRITE((void *)data, struct_user_fpregs_struct_sz); + POST_WRITE((void *)data_arg, struct_user_fpregs_struct_sz); } else if (request == ptrace_getfpxregs) { - POST_WRITE((void *)data, struct_user_fpxregs_struct_sz); + POST_WRITE((void *)data_arg, struct_user_fpxregs_struct_sz); } else if (request == ptrace_getsiginfo) { - POST_WRITE((void *)data, siginfo_t_sz); + POST_WRITE((void *)data_arg, siginfo_t_sz); } else if (request == ptrace_getregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; + __sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg; POST_WRITE(iov->iov_base, iov->iov_len); } else if (request == ptrace_peekdata || request == ptrace_peektext || request == ptrace_peekuser) { - POST_WRITE((void *)data, sizeof(void *)); + POST_WRITE((void *)data_arg, sizeof(void *)); } } # endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index e71a6bcd6a837..b1dc1ec204bc8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -279,8 +279,9 @@ #if SI_LINUX_NOT_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64) -#define SANITIZER_INTERCEPT_PTRACE 1 + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sparc__)) +# define SANITIZER_INTERCEPT_PTRACE 1 #else #define SANITIZER_INTERCEPT_PTRACE 0 #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index 6d61d276d77e3..67250de1eed69 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -94,8 +94,9 @@ #if SANITIZER_LINUX # include # include -# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ - defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64 +# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \ + defined(__hexagon__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sparc__) # include # ifdef __arm__ typedef struct user_fpregs elf_fpregset_t; @@ -358,11 +359,12 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); const int wordexp_wrde_dooffs = WRDE_DOOFFS; # endif // !SANITIZER_ANDROID -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__)|| SANITIZER_RISCV64) -#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) +# if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sparc__)) +# if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); #elif SANITIZER_RISCV64 @@ -377,19 +379,22 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); #elif defined(__s390__) unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct); -#else +# elif defined(__sparc__) + unsigned struct_user_regs_struct_sz = sizeof(struct sunos_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(struct sunos_fp); +# else unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); -#endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__ -#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ - defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ - defined(__loongarch__) || SANITIZER_RISCV64 +# endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__ +# if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ + defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \ + defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__) unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); #endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ -// || __s390__ || __loongarch__ -#ifdef __arm__ + // || __s390__ || __loongarch__ || SANITIZER_RISCV64 || __sparc__ +# ifdef __arm__ unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; #else unsigned struct_user_vfpregs_struct_sz = 0; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 34bfef1f7ef45..fcb9dabcea577 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -855,10 +855,11 @@ typedef void __sanitizer_FILE; # define SANITIZER_HAS_STRUCT_FILE 0 #endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ - defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64) +# if SANITIZER_LINUX && !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \ + defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \ + defined(__sparc__)) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; @@ -880,9 +881,24 @@ extern int ptrace_setsiginfo; extern int ptrace_getregset; extern int ptrace_setregset; extern int ptrace_geteventmsg; -#endif -#if SANITIZER_LINUX && !SANITIZER_ANDROID +// Helper for the ptrace interceptor. +template +inline T ptrace_data_arg(int request, T addr, T data) { +# if SANITIZER_LINUX && SANITIZER_SPARC + // As described in ptrace(2), the meanings of addr and data are reversed + // for the PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_GETREGS, and + // PTRACE_GETFPREGS requests on Linux/sparc64. + if (request == ptrace_getregs || request == ptrace_getfpregs || + request == ptrace_setregs || request == ptrace_setfpregs) + return addr; + else +# endif + return data; +} +# endif + +# if SANITIZER_LINUX && !SANITIZER_ANDROID extern unsigned struct_shminfo_sz; extern unsigned struct_shm_info_sz; extern int shmctl_ipc_stat; diff --git a/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp b/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp index e01021ff344c3..edff30e5a4753 100644 --- a/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/ptrace.cpp @@ -81,6 +81,13 @@ typedef __riscv_q_ext_state fpregs_struct; #define PRINT_REG_PC(__regs) printf("%lx\n", (unsigned long)(__regs.pc)) #define PRINT_REG_FP(__fpregs) printf("%lx\n", (unsigned long)(__fpregs.fcsr)) #define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__sparc__) +typedef sunos_regs regs_struct; +typedef sunos_fp fpregs_struct; +# define PRINT_REG_PC(__regs) printf("%x\n", (unsigned)(__regs.pc)) +# define PRINT_REG_FP(__fpregs) printf("%x\n", (unsigned)(__fpregs.fsr)) +# define __PTRACE_FPREQUEST PTRACE_GETFPREGS #endif @@ -110,7 +117,13 @@ int main(void) { regset_io.iov_len = sizeof(regs_struct); #else # define __PTRACE_REQUEST PTRACE_GETREGS -# define __PTRACE_ARGS NULL, pregs +# ifdef __sparc__ + // The meanings of addr and data are reversed for a few requests on + // Linux/sparc64. +# define __PTRACE_ARGS pregs, NULL +# else +# define __PTRACE_ARGS NULL, pregs +# endif #endif res = ptrace((enum __ptrace_request)__PTRACE_REQUEST, pid, __PTRACE_ARGS); // CHECK: AddressSanitizer: stack-buffer-overflow @@ -127,7 +140,13 @@ int main(void) { res = ptrace((enum __ptrace_request)PTRACE_GETREGSET, pid, (void*)NT_FPREGSET, (void*)®set_io); #else -# define __PTRACE_FPARGS NULL, &fpregs + // The meanings of addr and data are reversed for a few requests on + // Linux/sparc64. +# ifdef __sparc__ +# define __PTRACE_FPARGS &fpregs, NULL +# else +# define __PTRACE_FPARGS NULL, &fpregs +# endif #endif res = ptrace((enum __ptrace_request)__PTRACE_FPREQUEST, pid, __PTRACE_FPARGS); assert(!res);