commit f914d6dc482ff761a8feff2ce9f3ee97fca92e17 Author: Kamil Rytarowski Date: Thu Dec 5 01:35:54 2019 +0100 Implement PT_GET_LWP_PRIVATE and PT_SET_LWP_PRIVATE diff --git a/sys/arch/alpha/include/ptrace.h b/sys/arch/alpha/include/ptrace.h index e7a4aee2c239..0f41f57143b9 100644 --- a/sys/arch/alpha/include/ptrace.h +++ b/sys/arch/alpha/include/ptrace.h @@ -56,3 +56,7 @@ #define PTRACE_BREAKPOINT ((const uint8_t[]) { 0x80, 0x00, 0x00, 0x00 }) #define PTRACE_BREAKPOINT_ASM __asm __volatile("bpt" ::: "memory") #define PTRACE_BREAKPOINT_SIZE 4 + +#ifdef _KERNEL +#define PTRACE_LWP_GETPRIVATE(l) ((struct pcb *)lwp_getpcb(l))->pcb_hw.apcb_unique +#endif diff --git a/sys/arch/hppa/include/ptrace.h b/sys/arch/hppa/include/ptrace.h index 4b59e76a489b..b9933b31f533 100644 --- a/sys/arch/hppa/include/ptrace.h +++ b/sys/arch/hppa/include/ptrace.h @@ -61,3 +61,7 @@ #define PTRACE_BREAKPOINT ((const uint8_t[]) { 0x00, 0x01, 0x00, 0x04 }) #define PTRACE_BREAKPOINT_ASM __asm __volatile("break %0, %1" :: "i" (HPPA_BREAK_KERNEL), "i" (HPPA_BREAK_SS) : "memory") #define PTRACE_BREAKPOINT_SIZE 4 + +#ifdef _KERNEL +#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_regs->tf_cr27 +#endif diff --git a/sys/arch/powerpc/include/ptrace.h b/sys/arch/powerpc/include/ptrace.h index 5098572f1a20..8711f775563f 100644 --- a/sys/arch/powerpc/include/ptrace.h +++ b/sys/arch/powerpc/include/ptrace.h @@ -77,4 +77,8 @@ int procfs_machdep_validvecregs(struct lwp *, struct mount *); #define PTRACE_BREAKPOINT_ASM __asm __volatile("trap") #define PTRACE_BREAKPOINT_SIZE 4 +#ifdef _KERNEL +#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_utf->tf_fixreg[_REG_R2] +#endif + #endif /* _POWERPC_PTRACE_H */ diff --git a/sys/arch/sh3/include/ptrace.h b/sys/arch/sh3/include/ptrace.h index c3cae6d9f5d4..4f6e0958972a 100644 --- a/sys/arch/sh3/include/ptrace.h +++ b/sys/arch/sh3/include/ptrace.h @@ -98,5 +98,6 @@ int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int, void *, int); #endif +#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_regs->tf_gbr #endif /* _KERNEL */ #endif /* !_SH3_PTRACE_H_ */ diff --git a/sys/arch/sparc/include/ptrace.h b/sys/arch/sparc/include/ptrace.h index 53ece3851760..85ca3084a161 100644 --- a/sys/arch/sparc/include/ptrace.h +++ b/sys/arch/sparc/include/ptrace.h @@ -69,3 +69,7 @@ #define PTRACE_BREAKPOINT ((const uint8_t[]) { 0x91, 0xd0, 0x20, 0x01 }) #define PTRACE_BREAKPOINT_ASM __asm __volatile("ta 1") #define PTRACE_BREAKPOINT_SIZE 4 + +#ifdef _KERNEL +#define PTRACE_LWP_GETPRIVATE(l) (l)->l_md.md_tf->tf_global[7] +#endif diff --git a/sys/compat/netbsd32/netbsd32_ptrace.c b/sys/compat/netbsd32/netbsd32_ptrace.c index 1741b852051c..5829b1f91da2 100644 --- a/sys/compat/netbsd32/netbsd32_ptrace.c +++ b/sys/compat/netbsd32/netbsd32_ptrace.c @@ -118,6 +118,30 @@ netbsd32_copyout_siginfo(const struct ptrace_siginfo *psi, void *addr, size_t le return copyout(&psi32, addr, sizeof(psi32)); } +static int +netbsd32_copyin_lwp_private(void *private, void *addr) +{ + void *private64; + netbsd32_pointer_t private32; + + int error = copyin(addr, &private32, sizeof(private32)); + if (error) + return error; + + private64 = NETBSD32PTR64(private32); + memcpy(private, &private64, sizeof(void *)); + return 0; +} + +static int +netbsd32_copyout_lwp_private(const void *private, void *addr) +{ + netbsd32_pointer_t private32; + + NETBSD32PTR32(private32, private); + return copyout(&private32, addr, sizeof(private)); +} + static int netbsd32_doregs(struct lwp *curl /*tracer*/, struct lwp *l /*traced*/, @@ -237,6 +261,8 @@ static struct ptrace_methods netbsd32_ptm = { .ptm_copyout_piod = netbsd32_copyout_piod, .ptm_copyin_siginfo = netbsd32_copyin_siginfo, .ptm_copyout_siginfo = netbsd32_copyout_siginfo, + .ptm_copyin_lwp_private = netbsd32_copyin_lwp_private, + .ptm_copyout_lwp_private = netbsd32_copyout_lwp_private, .ptm_doregs = netbsd32_doregs, .ptm_dofpregs = netbsd32_dofpregs, .ptm_dodbregs = netbsd32_dodbregs diff --git a/sys/kern/sys_ptrace.c b/sys/kern/sys_ptrace.c index 8515b6f4cd14..00edc2bddcc0 100644 --- a/sys/kern/sys_ptrace.c +++ b/sys/kern/sys_ptrace.c @@ -185,11 +185,27 @@ ptrace_copyout_siginfo(const struct ptrace_siginfo *psi, void *addr, size_t len) return copyout(psi, addr, sizeof(*psi)); } +static int +ptrace_copyin_lwp_private(void *private, void *addr) +{ + + return copyin(addr, private, sizeof(void *)); +} + +static int +ptrace_copyout_lwp_private(const void *private, void *addr) +{ + + return copyout(private, addr, sizeof(void *)); +} + static struct ptrace_methods native_ptm = { .ptm_copyin_piod = ptrace_copyin_piod, .ptm_copyout_piod = ptrace_copyout_piod, .ptm_copyin_siginfo = ptrace_copyin_siginfo, .ptm_copyout_siginfo = ptrace_copyout_siginfo, + .ptm_copyin_lwp_private = ptrace_copyin_lwp_private, + .ptm_copyout_lwp_private = ptrace_copyout_lwp_private, .ptm_doregs = process_doregs, .ptm_dofpregs = process_dofpregs, .ptm_dodbregs = process_dodbregs, diff --git a/sys/kern/sys_ptrace_common.c b/sys/kern/sys_ptrace_common.c index d5d83bba51a1..5cd7a9986821 100644 --- a/sys/kern/sys_ptrace_common.c +++ b/sys/kern/sys_ptrace_common.c @@ -261,6 +261,8 @@ ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, case PT_GET_PROCESS_STATE: case PT_SET_SIGINFO: case PT_GET_SIGINFO: + case PT_SET_LWP_PRIVATE: + case PT_GET_LWP_PRIVATE: #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif @@ -463,6 +465,8 @@ ptrace_allowed(struct lwp *l, int req, struct proc *t, struct proc *p, case_PT_SETFPREGS case_PT_GETDBREGS case_PT_SETDBREGS + case PT_SET_LWP_PRIVATE: + case PT_GET_LWP_PRIVATE: #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif @@ -617,6 +621,52 @@ ptrace_set_siginfo(struct proc *t, struct lwp **lt, struct ptrace_methods *ptm, return 0; } +static int +ptrace_get_lwp_private(struct proc *t, struct lwp **lt, + struct ptrace_methods *ptm, void *addr, size_t data) +{ + void *private; + int error; + + if ((error = ptrace_update_lwp(t, lt, data)) != 0) + return error; + +#ifdef PTRACE_LWP_GETPRIVATE + private = &PTRACE_LWP_GETPRIVATE(*lt); +#else + private = &(*lt)->l_private; +#endif + + error = ptm->ptm_copyout_lwp_private(private, addr); + if (error) + return error; + + DPRINTF(("%s: addr=%p lwp=%d\n", __func__, addr, data)); + return 0; +} + +static int +ptrace_set_lwp_private(struct proc *t, struct lwp **lt, + struct ptrace_methods *ptm, void *addr, int data) +{ + void *private; + int error; + + if ((error = ptrace_update_lwp(t, lt, data)) != 0) + return error; + + error = ptm->ptm_copyin_lwp_private(&private, addr); + if (error) + return error; + + error = lwp_setprivate(*lt, private); + if (error) + return error; + + DPRINTF(("%s: addr=%p lwp=%d\n", __func__, addr, data)); + return 0; +} + static int ptrace_get_event_mask(struct proc *t, void *addr, size_t data) { @@ -1419,6 +1469,14 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid, error = ptrace_startstop(t, <, req, addr, data); break; + case PT_SET_LWP_PRIVATE: + error = ptrace_set_lwp_private(t, <, ptm, addr, data); + break; + + case PT_GET_LWP_PRIVATE: + error = ptrace_get_lwp_private(t, <, ptm, addr, data); + break; + #ifdef PT_REGISTERS case_PT_SETREGS case_PT_GETREGS diff --git a/tests/lib/libc/sys/t_ptrace_wait.c b/tests/lib/libc/sys/t_ptrace_wait.c index 76088a3e60d8..61eac6a305de 100644 --- a/tests/lib/libc/sys/t_ptrace_wait.c +++ b/tests/lib/libc/sys/t_ptrace_wait.c @@ -40,6 +40,7 @@ __RCSID("$NetBSD: t_ptrace_wait.c,v 1.141 2019/11/12 18:18:04 kamil Exp $"); #include #include #include +#include #include #include #include @@ -4800,8 +4801,44 @@ PTRACE_KILL(kill3, "killpg(SIGKILL)") /// ---------------------------------------------------------------------------- +static void * +get_private(void) +{ + +#ifdef __HAVE___LWP_GETTCB_FAST + return __lwp_gettcb_fast(); +#elif defined(__HAVE___LWP_GETPRIVATE_FAST) + return __lwp_getprivate_fast(); +#else +#error Unknown code path! +#endif +} + +static pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER; +static volatile size_t lwpinfo_thread_done; + +static void * +lwpinfo_thread(void *arg) +{ + volatile void **tcb; + + tcb = (volatile void **)arg; + + *tcb = get_private(); + DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self()); + + pthread_mutex_lock(&lwpinfo_thread_mtx); + lwpinfo_thread_done++; + pthread_mutex_unlock(&lwpinfo_thread_mtx); + + pthread_cond_signal(&lwpinfo_thread_cnd); + + return infinite_thread(NULL); +} + static void -traceme_lwpinfo(const int threads) +traceme_lwpinfo(const size_t threads, const char *mode) { const int sigval = SIGSTOP; const int sigval2 = SIGINT; @@ -4811,12 +4848,21 @@ traceme_lwpinfo(const int threads) #endif struct ptrace_lwpinfo lwp = {0, 0}; struct ptrace_siginfo info; + void *private; + volatile void *tcb[4]; + bool found; /* Maximum number of supported threads in this test */ - pthread_t t[3]; - int n, rv; + pthread_t t[__arraycount(tcb) - 1]; + size_t n, m; + int rv; + size_t bytes_read; + + struct ptrace_io_desc io; + + ATF_REQUIRE(__arraycount(t) >= threads); - ATF_REQUIRE((int)__arraycount(t) >= threads); + memset(tcb, 0, sizeof(tcb)); DPRINTF("Before forking process PID=%d\n", getpid()); SYSCALL_REQUIRE((child = fork()) != -1); @@ -4824,14 +4870,25 @@ traceme_lwpinfo(const int threads) DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); + tcb[0] = get_private(); + DPRINTF("Storing tcb[0] = %p\n", tcb[0]); + DPRINTF("Before raising %s from child\n", strsignal(sigval)); FORKEE_ASSERT(raise(sigval) == 0); for (n = 0; n < threads; n++) { - rv = pthread_create(&t[n], NULL, infinite_thread, NULL); + rv = pthread_create(&t[n], NULL, lwpinfo_thread, + &tcb[n + 1]); FORKEE_ASSERT(rv == 0); } + pthread_mutex_lock(&lwpinfo_thread_mtx); + while (lwpinfo_thread_done < threads) { + pthread_cond_wait(&lwpinfo_thread_cnd, + &lwpinfo_thread_mtx); + } + pthread_mutex_unlock(&lwpinfo_thread_mtx); + DPRINTF("Before raising %s from child\n", strsignal(sigval2)); FORKEE_ASSERT(raise(sigval2) == 0); @@ -4896,19 +4953,73 @@ traceme_lwpinfo(const int threads) memset(&lwp, 0, sizeof(lwp)); + memset(&io, 0, sizeof(io)); + + bytes_read = 0; + io.piod_op = PIOD_READ_D; + io.piod_len = sizeof(tcb); + + do { + io.piod_addr = (char *)&tcb + bytes_read; + io.piod_offs = io.piod_addr; + + rv = ptrace(PT_IO, child, &io, sizeof(io)); + ATF_REQUIRE(rv != -1 && io.piod_len != 0); + + bytes_read += io.piod_len; + io.piod_len = sizeof(tcb) - bytes_read; + } while (bytes_read < sizeof(tcb)); + for (n = 0; n <= threads; n++) { DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n"); - SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1); + SYSCALL_REQUIRE( + ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1); DPRINTF("LWP=%d\n", lwp.pl_lwpid); DPRINTF("Assert that the thread exists\n"); ATF_REQUIRE(lwp.pl_lwpid > 0); - DPRINTF("Assert that lwp thread %d received expected event\n", - lwp.pl_lwpid); - FORKEE_ASSERT_EQ(lwp.pl_event, info.psi_lwpid == lwp.pl_lwpid ? - PL_EVENT_SIGNAL : PL_EVENT_NONE); + if (strcmp(mode, "lwpinfo") == 0) { + DPRINTF("Assert that lwp thread %d received expected " + "event\n", lwp.pl_lwpid); + FORKEE_ASSERT_EQ(lwp.pl_event, + info.psi_lwpid == lwp.pl_lwpid ? + PL_EVENT_SIGNAL : PL_EVENT_NONE); + } + + if (strstr(mode, "lwp_private") != NULL) { + DPRINTF("Retrieved thread area &pointer: %p\n", + &private); + + DPRINTF("Call GET_LWP_PRIVATE for the child %d.%d\n", + child, lwp.pl_lwpid); + SYSCALL_REQUIRE( + ptrace(PT_GET_LWP_PRIVATE, child, &private, + lwp.pl_lwpid) != -1); + + DPRINTF("Retrieved thread area pointer: %p\n", private); + + found = false; + for (m = 0; m < __arraycount(tcb); m++) { + DPRINTF("Comparing %p and %p\n", + private, tcb[m]); + if (private == tcb[m]) { + found = true; + break; + } + } + ATF_REQUIRE(found == true); + + if (strcmp(mode, "set_lwp_private") == 0) { + DPRINTF("Call GET_LWP_PRIVATE for %d.%d\n", + child, lwp.pl_lwpid); + SYSCALL_REQUIRE( + ptrace(PT_SET_LWP_PRIVATE, child, &private, + lwp.pl_lwpid) != -1); + } + } } + DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n"); SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1); DPRINTF("LWP=%d\n", lwp.pl_lwpid); @@ -4929,25 +5040,35 @@ traceme_lwpinfo(const int threads) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -#define TRACEME_LWPINFO(test, threads) \ +#define TRACEME_LWPINFO(test, threads, mode) \ ATF_TC(test); \ ATF_TC_HEAD(test, tc) \ { \ atf_tc_set_md_var(tc, "descr", \ - "Verify LWPINFO with the child with " #threads \ + "Verify " mode " with the child with " #threads \ " spawned extra threads"); \ } \ \ ATF_TC_BODY(test, tc) \ { \ \ - traceme_lwpinfo(threads); \ + traceme_lwpinfo(threads, mode); \ } -TRACEME_LWPINFO(traceme_lwpinfo0, 0) -TRACEME_LWPINFO(traceme_lwpinfo1, 1) -TRACEME_LWPINFO(traceme_lwpinfo2, 2) -TRACEME_LWPINFO(traceme_lwpinfo3, 3) +TRACEME_LWPINFO(traceme_lwpinfo0, 0, "lwpinfo") +TRACEME_LWPINFO(traceme_lwpinfo1, 1, "lwpinfo") +TRACEME_LWPINFO(traceme_lwpinfo2, 2, "lwpinfo") +TRACEME_LWPINFO(traceme_lwpinfo3, 3, "lwpinfo") + +TRACEME_LWPINFO(get_lwp_private0, 0, "get_lwp_private") +TRACEME_LWPINFO(get_lwp_private1, 1, "get_lwp_private") +TRACEME_LWPINFO(get_lwp_private2, 2, "get_lwp_private") +TRACEME_LWPINFO(get_lwp_private3, 3, "get_lwp_private") + +TRACEME_LWPINFO(set_lwp_private0, 0, "set_lwp_private") +TRACEME_LWPINFO(set_lwp_private1, 1, "set_lwp_private") +TRACEME_LWPINFO(set_lwp_private2, 2, "set_lwp_private") +TRACEME_LWPINFO(set_lwp_private3, 3, "set_lwp_private") /// ---------------------------------------------------------------------------- @@ -8191,6 +8312,16 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, traceme_lwpinfo2); ATF_TP_ADD_TC(tp, traceme_lwpinfo3); + ATF_TP_ADD_TC(tp, get_lwp_private0); + ATF_TP_ADD_TC(tp, get_lwp_private1); + ATF_TP_ADD_TC(tp, get_lwp_private2); + ATF_TP_ADD_TC(tp, get_lwp_private3); + + ATF_TP_ADD_TC(tp, set_lwp_private0); + ATF_TP_ADD_TC(tp, set_lwp_private1); + ATF_TP_ADD_TC(tp, set_lwp_private2); + ATF_TP_ADD_TC(tp, set_lwp_private3); + ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0); ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1); ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);