9 int peek_result, wait_result, status;
13 struct user_regs_struct registers;
17static void* inspect_sibling(
void* argument) {
19 memset(&state->registers, 0xa5,
sizeof(state->registers));
20 memset(&state->info, 0xa5,
sizeof(state->info));
21 state->peek_result = waitid(P_PID, state->child, &state->peek, WSTOPPED | WNOWAIT);
22 state->wait_result = tc_wait(state->child, &state->status, 10000);
24 state->result[0] = ptrace(PTRACE_GETREGS, state->child, (
void*)0, (
void*)&state->registers);
25 state->error[0] = errno;
27 state->result[1] = ptrace(PTRACE_GETSIGINFO, state->child, (
void*)0, (
void*)&state->info);
28 state->error[1] = errno;
30 state->result[2] = ptrace(PTRACE_CONT, state->child, (
void*)0, (
void*)0);
31 state->error[2] = errno;
35static int sibling_denied(
void) {
36 int failed = 0, started = 0;
37 struct tc_child child = TC_CHILD_INIT;
39 struct user_regs_struct first, second;
42 CHECK(tc_spawn(&child, 1) == 0 && tc_send(&child,
'S', SIGUSR1) == 0);
43 CHECK(waitid(P_PID, child.pid, &peek, WSTOPPED | WNOWAIT) == 0);
44 CHECK(peek.si_pid == child.pid && peek.si_code == CLD_TRAPPED && peek.si_status == SIGUSR1);
45 CHECK(ptrace(PTRACE_GETREGS, child.pid, (
void*)0, (
void*)&first) == 0);
46 state.child = child.pid;
47 CHECK(pthread_create(&
sibling, NULL, inspect_sibling, &state) == 0);
49 CHECK(pthread_join(
sibling, NULL) == 0);
51 CHECK(state.peek_result == 0 && state.peek.si_pid == child.pid &&
52 state.peek.si_code == CLD_TRAPPED && state.peek.si_status == SIGUSR1);
53 CHECK(state.wait_result == 0 && WIFSTOPPED(state.status) && WSTOPSIG(state.status) == SIGUSR1);
54 for (
size_t i = 0; i < 3; ++i)
55 CHECK(state.result[i] == -1 && state.error[i] == ESRCH);
56 const unsigned char* bytes = (
const unsigned char*)&state.registers;
57 for (
size_t i = 0; i <
sizeof(state.registers); ++i)
58 CHECK(bytes[i] == 0xa5);
59 bytes = (
const unsigned char*)&state.info;
60 for (
size_t i = 0; i <
sizeof(state.info); ++i)
61 CHECK(bytes[i] == 0xa5);
62 CHECK(ptrace(PTRACE_GETREGS, child.pid, (
void*)0, (
void*)&second) == 0);
63 CHECK(memcmp(&first, &second,
sizeof(first)) == 0);
64 CHECK(waitid(P_PID, child.pid, &peek, WSTOPPED | WNOHANG) == 0 && !peek.si_pid);
65 CHECK(tc_resume(child.pid, PTRACE_CONT, 0) == 0 && tc_receive(child.report,
'A', NULL) == 0);
66 CHECK(tc_finish(&child) == 0);
68 if (started && pthread_join(
sibling, NULL))
76 atomic_uint ready, finish;
80static void* create_then_exit(
void* argument) {
81 struct creator* state = argument;
82 state->result = tc_spawn(&state->child, 1) || tc_stop(&state->child, SIGUSR1);
83 atomic_store(&state->ready, 1);
84 if (!state->result && tc_atomic_wait(&state->finish, 1))
90static int tracer_task_exit(
void) {
91 int failed = 0, started = 0;
92 struct creator state = {.child = TC_CHILD_INIT};
94 struct user_regs_struct registers;
96 CHECK(pthread_create(&
creator, NULL, create_then_exit, &state) == 0);
98 CHECK(tc_atomic_wait(&state.ready, 1) == 0 && state.result == 0);
100 CHECK(ptrace(PTRACE_GETREGS, state.child.pid, (
void*)0, (
void*)®isters) == -1 &&
102 atomic_store(&state.finish, 1);
103 CHECK(pthread_join(
creator, NULL) == 0);
105 CHECK(state.result == 0);
106 CHECK(tc_receive(state.child.report,
'H', &
message) == 0);
109 CHECK(tc_receive(state.child.report,
'A', NULL) == 0);
111 CHECK(ptrace(PTRACE_GETREGS, state.child.pid, (
void*)0, (
void*)®isters) == -1 &&
113 CHECK(tc_finish(&state.child) == 0);
115 atomic_store(&state.finish, 1);
116 if (started && pthread_join(
creator, NULL))
118 tc_close(&state.child);
122int tc_ownership(
void) {
123 return sibling_denied() || tracer_task_exit();