1 /*
2 * Check handling of CLONE_PTRACE'ed processes.
3 *
4 * Copyright (c) 2015-2022 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #include <errno.h>
13 #include <sched.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20
21 static siginfo_t sinfo;
22
23 #ifndef QUIET_ATTACH
24 # define QUIET_ATTACH 0
25 #endif
26 #ifndef QUIET_EXIT
27 # define QUIET_EXIT 0
28 #endif
29
30 static void
31 handler(const int no, siginfo_t *const si, void *const uc)
32 {
33 memcpy(&sinfo, si, sizeof(sinfo));
34 }
35
36 static int
37 child(void *const arg)
38 {
39 for(;;)
40 pause();
41 return 0;
42 }
43
44 #ifdef IA64
45 extern int __clone2(int (*)(void *), void *, size_t, int, void *, ...);
46 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
47 __clone2((fn_), (stack_), (size_), (flags_), (arg_), ## __VA_ARGS__)
48 #else
49 # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
50 clone((fn_), (stack_), (flags_), (arg_), ## __VA_ARGS__)
51 #endif
52
53 int
54 main(void)
55 {
56 const int sig = SIGUSR1;
57 sigset_t mask;
58 sigemptyset(&mask);
59 sigaddset(&mask, sig);
60 if (sigprocmask(SIG_UNBLOCK, &mask, NULL))
61 perror_msg_and_fail("sigprocmask");
62
63 const unsigned long child_stack_size = get_page_size();
64 void *const child_stack =
65 tail_alloc(child_stack_size * 2) + child_stack_size;
66
67 const pid_t pid = do_clone(child, child_stack, child_stack_size,
68 CLONE_PTRACE | SIGCHLD, 0);
69 if (pid < 0)
70 perror_msg_and_fail("clone");
71
72 static const struct sigaction sa = {
73 .sa_sigaction = handler,
74 .sa_flags = SA_SIGINFO
75 };
76 if (sigaction(SIGCHLD, &sa, NULL))
77 perror_msg_and_fail("sigaction");
78
79 kill(pid, sig);
80
81 FILE *const fp = fdopen(3, "a");
82 if (!fp)
83 perror_msg_and_fail("fdopen");
84 #if !QUIET_ATTACH
85 if (fprintf(fp, "%s: Detached unknown pid %d\n",
86 getenv("STRACE_EXE") ?: "strace", pid) < 0)
87 perror_msg_and_fail("fprintf");
88 #endif
89
90 int status;
91 while (wait(&status) != pid) {
92 if (errno != EINTR)
93 perror_msg_and_fail("wait");
94 }
95 if (!WIFSIGNALED(status) || WTERMSIG(status) != sig)
96 error_msg_and_fail("unexpected child exit status %d", status);
97
98 char utm_str[64];
99 char stm_str[64];
100 printf("--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=%d"
101 ", si_uid=%d, si_status=%s, si_utime=%s, si_stime=%s} ---\n"
102 #if !QUIET_EXIT
103 "+++ exited with 0 +++\n"
104 #endif
105 , pid, geteuid(), "SIGUSR1",
106 clock_t_str((unsigned int) sinfo.si_utime, ARRSZ_PAIR(utm_str)),
107 clock_t_str((unsigned int) sinfo.si_stime, ARRSZ_PAIR(stm_str)));
108
109 return 0;
110 }