Skip to content

Commit 587eaef

Browse files
authored
[sanitizer_common] Handle ptrace on Linux/sparc64 (#109310)
When ASan testing is enabled on SPARC as per PR #107405, the ``` AddressSanitizer-sparc-linux :: TestCases/Linux/ptrace.cpp ``` `FAIL`s on Linux/sparc64. This happens because the `ptrace` interceptor has no support for that target at all. This patch adds the missing parts and accounts for a couple of issues specific to this target: - In some cases, SPARC just needs to be included in the list of supported targets. - Besides, the types used by the `PTRACE_GETREGS` and `PTRACE_GETFPREGS` requests need to be filled in. - `ptrace` has a weird quirk on this target: for a couple of requests, the meaning of the `data` and `addr` args is reversed. All of the `Linux/ptrace.cpp` test and the interceptor, pre-syscall and post-syscall hooks need to account for that swap in their checks. Tested on `sparc64-unknown-linux-gnu` and `x86_64-pc-linux-gnu`.
1 parent 412d59f commit 587eaef

6 files changed

+109
-57
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

+26-18
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "sanitizer_errno.h"
4242
#include "sanitizer_placement_new.h"
4343
#include "sanitizer_platform_interceptors.h"
44+
#include "sanitizer_platform_limits_posix.h"
4445
#include "sanitizer_symbolizer.h"
4546
#include "sanitizer_tls_get_addr.h"
4647

@@ -3473,23 +3474,27 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
34733474
COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
34743475
__sanitizer_iovec local_iovec;
34753476

3476-
if (data) {
3477+
void *data_arg = ptrace_data_arg(request, addr, data);
3478+
if (data_arg) {
34773479
if (request == ptrace_setregs) {
3478-
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
3480+
COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, struct_user_regs_struct_sz);
34793481
} else if (request == ptrace_setfpregs) {
3480-
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
3482+
COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
3483+
struct_user_fpregs_struct_sz);
34813484
} else if (request == ptrace_setfpxregs) {
3482-
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
3485+
COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
3486+
struct_user_fpxregs_struct_sz);
34833487
} else if (request == ptrace_setvfpregs) {
3484-
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
3488+
COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
3489+
struct_user_vfpregs_struct_sz);
34853490
} else if (request == ptrace_setsiginfo) {
3486-
COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
3491+
COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, siginfo_t_sz);
34873492

3488-
// Some kernel might zero the iovec::iov_base in case of invalid
3489-
// write access. In this case copy the invalid address for further
3490-
// inspection.
3493+
// Some kernel might zero the iovec::iov_base in case of invalid
3494+
// write access. In this case copy the invalid address for further
3495+
// inspection.
34913496
} else if (request == ptrace_setregset || request == ptrace_getregset) {
3492-
__sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
3497+
__sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg;
34933498
COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec));
34943499
local_iovec = *iovec;
34953500
if (request == ptrace_setregset)
@@ -3502,23 +3507,26 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
35023507
// https://github.com/google/sanitizers/issues/321.
35033508
uptr res = REAL(ptrace)(request, pid, addr, data);
35043509

3505-
if (!res && data) {
3510+
if (!res && data_arg) {
35063511
// Note that PEEK* requests assign different meaning to the return value.
35073512
// This function does not handle them (nor does it need to).
35083513
if (request == ptrace_getregs) {
3509-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
3514+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, struct_user_regs_struct_sz);
35103515
} else if (request == ptrace_getfpregs) {
3511-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
3516+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
3517+
struct_user_fpregs_struct_sz);
35123518
} else if (request == ptrace_getfpxregs) {
3513-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
3519+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
3520+
struct_user_fpxregs_struct_sz);
35143521
} else if (request == ptrace_getvfpregs) {
3515-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
3522+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
3523+
struct_user_vfpregs_struct_sz);
35163524
} else if (request == ptrace_getsiginfo) {
3517-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
3525+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, siginfo_t_sz);
35183526
} else if (request == ptrace_geteventmsg) {
3519-
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
3527+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, sizeof(unsigned long));
35203528
} else if (request == ptrace_getregset) {
3521-
__sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
3529+
__sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg;
35223530
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec));
35233531
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base,
35243532
local_iovec.iov_len);

compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc

+18-15
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#if SANITIZER_LINUX
4949

5050
# include "sanitizer_libc.h"
51+
# include "sanitizer_platform_limits_posix.h"
5152

5253
# define PRE_SYSCALL(name) \
5354
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
@@ -2530,18 +2531,19 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
25302531
# if !SANITIZER_ANDROID && \
25312532
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
25322533
defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
2533-
defined(__loongarch__) || SANITIZER_RISCV64)
2534-
if (data) {
2534+
defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__))
2535+
long data_arg = ptrace_data_arg(request, addr, data);
2536+
if (data_arg) {
25352537
if (request == ptrace_setregs) {
2536-
PRE_READ((void *)data, struct_user_regs_struct_sz);
2538+
PRE_READ((void *)data_arg, struct_user_regs_struct_sz);
25372539
} else if (request == ptrace_setfpregs) {
2538-
PRE_READ((void *)data, struct_user_fpregs_struct_sz);
2540+
PRE_READ((void *)data_arg, struct_user_fpregs_struct_sz);
25392541
} else if (request == ptrace_setfpxregs) {
2540-
PRE_READ((void *)data, struct_user_fpxregs_struct_sz);
2542+
PRE_READ((void *)data_arg, struct_user_fpxregs_struct_sz);
25412543
} else if (request == ptrace_setsiginfo) {
2542-
PRE_READ((void *)data, siginfo_t_sz);
2544+
PRE_READ((void *)data_arg, siginfo_t_sz);
25432545
} else if (request == ptrace_setregset) {
2544-
__sanitizer_iovec *iov = (__sanitizer_iovec *)data;
2546+
__sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg;
25452547
PRE_READ(iov->iov_base, iov->iov_len);
25462548
}
25472549
}
@@ -2552,25 +2554,26 @@ POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
25522554
# if !SANITIZER_ANDROID && \
25532555
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
25542556
defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
2555-
defined(__loongarch__) || SANITIZER_RISCV64)
2556-
if (res >= 0 && data) {
2557+
defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__))
2558+
long data_arg = ptrace_data_arg(request, addr, data);
2559+
if (res >= 0 && data_arg) {
25572560
// Note that this is different from the interceptor in
25582561
// sanitizer_common_interceptors.inc.
25592562
// PEEK* requests return resulting values through data pointer.
25602563
if (request == ptrace_getregs) {
2561-
POST_WRITE((void *)data, struct_user_regs_struct_sz);
2564+
POST_WRITE((void *)data_arg, struct_user_regs_struct_sz);
25622565
} else if (request == ptrace_getfpregs) {
2563-
POST_WRITE((void *)data, struct_user_fpregs_struct_sz);
2566+
POST_WRITE((void *)data_arg, struct_user_fpregs_struct_sz);
25642567
} else if (request == ptrace_getfpxregs) {
2565-
POST_WRITE((void *)data, struct_user_fpxregs_struct_sz);
2568+
POST_WRITE((void *)data_arg, struct_user_fpxregs_struct_sz);
25662569
} else if (request == ptrace_getsiginfo) {
2567-
POST_WRITE((void *)data, siginfo_t_sz);
2570+
POST_WRITE((void *)data_arg, siginfo_t_sz);
25682571
} else if (request == ptrace_getregset) {
2569-
__sanitizer_iovec *iov = (__sanitizer_iovec *)data;
2572+
__sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg;
25702573
POST_WRITE(iov->iov_base, iov->iov_len);
25712574
} else if (request == ptrace_peekdata || request == ptrace_peektext ||
25722575
request == ptrace_peekuser) {
2573-
POST_WRITE((void *)data, sizeof(void *));
2576+
POST_WRITE((void *)data_arg, sizeof(void *));
25742577
}
25752578
}
25762579
# endif

compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@
279279
#if SI_LINUX_NOT_ANDROID && \
280280
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
281281
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
282-
defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
283-
#define SANITIZER_INTERCEPT_PTRACE 1
282+
defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \
283+
defined(__sparc__))
284+
# define SANITIZER_INTERCEPT_PTRACE 1
284285
#else
285286
#define SANITIZER_INTERCEPT_PTRACE 0
286287
#endif

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp

+19-14
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@
9494
#if SANITIZER_LINUX
9595
# include <utime.h>
9696
# include <sys/ptrace.h>
97-
# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
98-
defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64
97+
# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
98+
defined(__hexagon__) || defined(__loongarch__) || SANITIZER_RISCV64 || \
99+
defined(__sparc__)
99100
# include <asm/ptrace.h>
100101
# ifdef __arm__
101102
typedef struct user_fpregs elf_fpregset_t;
@@ -359,11 +360,12 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
359360
const int wordexp_wrde_dooffs = WRDE_DOOFFS;
360361
# endif // !SANITIZER_ANDROID
361362

362-
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
363-
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
364-
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
365-
defined(__s390__) || defined(__loongarch__)|| SANITIZER_RISCV64)
366-
#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
363+
# if SANITIZER_LINUX && !SANITIZER_ANDROID && \
364+
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
365+
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
366+
defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \
367+
defined(__sparc__))
368+
# if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
367369
unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
368370
unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
369371
#elif SANITIZER_RISCV64
@@ -378,19 +380,22 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
378380
#elif defined(__s390__)
379381
unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct);
380382
unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct);
381-
#else
383+
# elif defined(__sparc__)
384+
unsigned struct_user_regs_struct_sz = sizeof(struct sunos_regs);
385+
unsigned struct_user_fpregs_struct_sz = sizeof(struct sunos_fp);
386+
# else
382387
unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
383388
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
384-
#endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__
385-
#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
386-
defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \
387-
defined(__loongarch__) || SANITIZER_RISCV64
389+
# endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__
390+
# if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
391+
defined(__aarch64__) || defined(__arm__) || defined(__s390__) || \
392+
defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__)
388393
unsigned struct_user_fpxregs_struct_sz = 0;
389394
#else
390395
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
391396
#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__
392-
// || __s390__ || __loongarch__
393-
#ifdef __arm__
397+
// || __s390__ || __loongarch__ || SANITIZER_RISCV64 || __sparc__
398+
# ifdef __arm__
394399
unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
395400
#else
396401
unsigned struct_user_vfpregs_struct_sz = 0;

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h

+22-6
Original file line numberDiff line numberDiff line change
@@ -855,10 +855,11 @@ typedef void __sanitizer_FILE;
855855
# define SANITIZER_HAS_STRUCT_FILE 0
856856
#endif
857857

858-
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
859-
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
860-
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
861-
defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
858+
# if SANITIZER_LINUX && !SANITIZER_ANDROID && \
859+
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
860+
defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
861+
defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 || \
862+
defined(__sparc__))
862863
extern unsigned struct_user_regs_struct_sz;
863864
extern unsigned struct_user_fpregs_struct_sz;
864865
extern unsigned struct_user_fpxregs_struct_sz;
@@ -880,9 +881,24 @@ extern int ptrace_setsiginfo;
880881
extern int ptrace_getregset;
881882
extern int ptrace_setregset;
882883
extern int ptrace_geteventmsg;
883-
#endif
884884

885-
#if SANITIZER_LINUX && !SANITIZER_ANDROID
885+
// Helper for the ptrace interceptor.
886+
template <class T>
887+
inline T ptrace_data_arg(int request, T addr, T data) {
888+
# if SANITIZER_LINUX && SANITIZER_SPARC
889+
// As described in ptrace(2), the meanings of addr and data are reversed
890+
// for the PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_GETREGS, and
891+
// PTRACE_GETFPREGS requests on Linux/sparc64.
892+
if (request == ptrace_getregs || request == ptrace_getfpregs ||
893+
request == ptrace_setregs || request == ptrace_setfpregs)
894+
return addr;
895+
else
896+
# endif
897+
return data;
898+
}
899+
# endif
900+
901+
# if SANITIZER_LINUX && !SANITIZER_ANDROID
886902
extern unsigned struct_shminfo_sz;
887903
extern unsigned struct_shm_info_sz;
888904
extern int shmctl_ipc_stat;

compiler-rt/test/asan/TestCases/Linux/ptrace.cpp

+21-2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ typedef __riscv_q_ext_state fpregs_struct;
8181
#define PRINT_REG_PC(__regs) printf("%lx\n", (unsigned long)(__regs.pc))
8282
#define PRINT_REG_FP(__fpregs) printf("%lx\n", (unsigned long)(__fpregs.fcsr))
8383
#define ARCH_IOVEC_FOR_GETREGSET
84+
85+
#elif defined(__sparc__)
86+
typedef sunos_regs regs_struct;
87+
typedef sunos_fp fpregs_struct;
88+
# define PRINT_REG_PC(__regs) printf("%x\n", (unsigned)(__regs.pc))
89+
# define PRINT_REG_FP(__fpregs) printf("%x\n", (unsigned)(__fpregs.fsr))
90+
# define __PTRACE_FPREQUEST PTRACE_GETFPREGS
8491
#endif
8592

8693

@@ -110,7 +117,13 @@ int main(void) {
110117
regset_io.iov_len = sizeof(regs_struct);
111118
#else
112119
# define __PTRACE_REQUEST PTRACE_GETREGS
113-
# define __PTRACE_ARGS NULL, pregs
120+
# ifdef __sparc__
121+
// The meanings of addr and data are reversed for a few requests on
122+
// Linux/sparc64.
123+
# define __PTRACE_ARGS pregs, NULL
124+
# else
125+
# define __PTRACE_ARGS NULL, pregs
126+
# endif
114127
#endif
115128
res = ptrace((enum __ptrace_request)__PTRACE_REQUEST, pid, __PTRACE_ARGS);
116129
// CHECK: AddressSanitizer: stack-buffer-overflow
@@ -127,7 +140,13 @@ int main(void) {
127140
res = ptrace((enum __ptrace_request)PTRACE_GETREGSET, pid, (void*)NT_FPREGSET,
128141
(void*)&regset_io);
129142
#else
130-
# define __PTRACE_FPARGS NULL, &fpregs
143+
// The meanings of addr and data are reversed for a few requests on
144+
// Linux/sparc64.
145+
# ifdef __sparc__
146+
# define __PTRACE_FPARGS &fpregs, NULL
147+
# else
148+
# define __PTRACE_FPARGS NULL, &fpregs
149+
# endif
131150
#endif
132151
res = ptrace((enum __ptrace_request)__PTRACE_FPREQUEST, pid, __PTRACE_FPARGS);
133152
assert(!res);

0 commit comments

Comments
 (0)