commit 4ae617c86daa85d9e3cded5bd5f5ec7b3e34d80d Author: Kamil Rytarowski Date: Thu Dec 5 01:35:54 2019 +0100 Implement PT_GET_THREAD_AREA and PT_SET_THREAD_AREA diff --git a/sys/compat/netbsd32/netbsd32_ptrace.c b/sys/compat/netbsd32/netbsd32_ptrace.c index 1741b852051c..6a9a24cca005 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_thread_area(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_thread_area(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_thread_area = netbsd32_copyin_thread_area, + .ptm_copyout_thread_area = netbsd32_copyout_thread_area, .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..509b173e42fa 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_thread_area(void *private, void *addr) +{ + + return copyin(addr, private, sizeof(void *)); +} + +static int +ptrace_copyout_thread_area(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_thread_area = ptrace_copyin_thread_area, + .ptm_copyout_thread_area = ptrace_copyout_thread_area, .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..2fdd61b8efed 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_THREAD_AREA: + case PT_GET_THREAD_AREA: #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_THREAD_AREA: + case PT_GET_THREAD_AREA: #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif @@ -617,6 +621,48 @@ ptrace_set_siginfo(struct proc *t, struct lwp **lt, struct ptrace_methods *ptm, return 0; } +static int +ptrace_get_thread_area(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; + + private = &(*lt)->l_private; + + error = ptm->ptm_copyout_thread_area(private, addr); + if (error) + return error; + + DPRINTF(("%s: addr=%p lwp=%d\n", __func__, addr, data)); + return 0; +} + +static int +ptrace_set_thread_area(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_thread_area(&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 +1465,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_THREAD_AREA: + error = ptrace_set_thread_area(t, <, ptm, addr, data); + break; + + case PT_GET_THREAD_AREA: + error = ptrace_get_thread_area(t, <, ptm, addr, data); + break; + #ifdef PT_REGISTERS case_PT_SETREGS case_PT_GETREGS diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index b531fa33a4bc..ce65b25a993f 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -58,6 +58,8 @@ #define PT_RESUME 21 /* allow execution of the LWP */ #define PT_SUSPEND 22 /* prevent execution of the LWP */ #define PT_STOP 23 /* stop the child process */ +#define PT_SET_THREAD_AREA 24 /* set thread private area pointer */ +#define PT_GET_THREAD_AREA 25 /* get thread private area pointer */ #define PT_FIRSTMACH 32 /* for machine-specific requests */ #include /* machine-specific requests, if any */ @@ -85,7 +87,10 @@ /* 19 */ "PT_SET_SIGINFO", \ /* 20 */ "PT_GET_SIGINFO", \ /* 21 */ "PT_RESUME", \ -/* 22 */ "PT_SUSPEND", +/* 22 */ "PT_SUSPEND", \ +/* 23 */ "PT_STOP", \ +/* 24 */ "PT_SET_THREAD_AREA", \ +/* 25 */ "PT_GET_THREAD_AREA" /* PT_{G,S}EVENT_MASK */ typedef struct ptrace_event { @@ -188,6 +193,8 @@ struct ptrace_methods { int (*ptm_copyout_piod)(const struct ptrace_io_desc *, void *, size_t); int (*ptm_copyin_siginfo)(struct ptrace_siginfo *, const void *, size_t); int (*ptm_copyout_siginfo)(const struct ptrace_siginfo *, void *, size_t); + int (*ptm_copyin_thread_area)(void *, void *); + int (*ptm_copyout_thread_area)(const void *, void *); int (*ptm_doregs)(struct lwp *, struct lwp *, struct uio *); int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *); int (*ptm_dodbregs)(struct lwp *, struct lwp *, struct uio *); diff --git a/tests/lib/libc/sys/t_ptrace_wait.c b/tests/lib/libc/sys/t_ptrace_wait.c index 76088a3e60d8..043ee0b74c80 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,27 +4848,47 @@ 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((int)__arraycount(t) >= threads); + memset(tcb, 0, sizeof(tcb)); + DPRINTF("Before forking process PID=%d\n", getpid()); SYSCALL_REQUIRE((child = fork()) != -1); if (child == 0) { 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, "thread_area") != NULL) { + DPRINTF("Retrieved thread area &pointer: %p\n", + &private); + + DPRINTF("Call GET_THREAD_AREA for the child %d.%d\n", + child, lwp.pl_lwpid); + SYSCALL_REQUIRE( + ptrace(PT_GET_THREAD_AREA, 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_thread_area") == 0) { + DPRINTF("Call GET_THREAD_AREA for %d.%d\n", + child, lwp.pl_lwpid); + SYSCALL_REQUIRE( + ptrace(PT_SET_THREAD_AREA, 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_thread_area0, 0, "get_thread_area") +TRACEME_LWPINFO(get_thread_area1, 1, "get_thread_area") +TRACEME_LWPINFO(get_thread_area2, 2, "get_thread_area") +TRACEME_LWPINFO(get_thread_area3, 3, "get_thread_area") + +TRACEME_LWPINFO(set_thread_area0, 0, "set_thread_area") +TRACEME_LWPINFO(set_thread_area1, 1, "set_thread_area") +TRACEME_LWPINFO(set_thread_area2, 2, "set_thread_area") +TRACEME_LWPINFO(set_thread_area3, 3, "set_thread_area") /// ---------------------------------------------------------------------------- @@ -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_thread_area0); + ATF_TP_ADD_TC(tp, get_thread_area1); + ATF_TP_ADD_TC(tp, get_thread_area2); + ATF_TP_ADD_TC(tp, get_thread_area3); + + ATF_TP_ADD_TC(tp, set_thread_area0); + ATF_TP_ADD_TC(tp, set_thread_area1); + ATF_TP_ADD_TC(tp, set_thread_area2); + ATF_TP_ADD_TC(tp, set_thread_area3); + 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);