1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved.
4 * Copyright (c) 2019 SUSE LLC
5 *
6 * Author: Saji Kumar.V.R <saji.kumar@wipro.com>
7 * Ported to new library: Jorik Cronenberg <jcronenberg@suse.de>
8 *
9 * Test the functionality of ptrace() for PTRACE_TRACEME in combination with
10 * PTRACE_KILL and PTRACE_CONT requests.
11 * Forked child does ptrace(PTRACE_TRACEME, ...).
12 * Then a signal is delivered to the child and verified that parent
13 * is notified via wait().
14 * Afterwards parent does ptrace(PTRACE_KILL, ..)/ptrace(PTRACE_CONT, ..)
15 * and then parent does wait() for child to finish.
16 * Test passes if child exits with SIGKILL for PTRACE_KILL.
17 * Test passes if child exits normally for PTRACE_CONT.
18 *
19 * Testing two cases for each:
20 * 1) child ignore SIGUSR2 signal
21 * 2) using a signal handler for child for SIGUSR2
22 * In both cases, child should stop & notify parent on reception of SIGUSR2.
23 */
24
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <sys/wait.h>
29 #include <config.h>
30 #include "ptrace.h"
31 #include "tst_test.h"
32
33 static struct tcase {
34 int handler;
35 int request;
36 int exp_wifexited;
37 int exp_wtermsig;
38 char *message;
39 } tcases[] = {
40 {0, PTRACE_KILL, 0, 9, "Testing PTRACE_KILL without child handler"},
41 {1, PTRACE_KILL, 0, 9, "Testing PTRACE_KILL with child handler"},
42 {0, PTRACE_CONT, 1, 0, "Testing PTRACE_CONT without child handler"},
43 {1, PTRACE_CONT, 1, 0, "Testing PTRACE_CONT with child handler"},
44 };
45
46 static volatile int got_signal;
47
child_handler(int sig LTP_ATTRIBUTE_UNUSED)48 static void child_handler(int sig LTP_ATTRIBUTE_UNUSED)
49 {
50 SAFE_KILL(getppid(), SIGUSR2);
51 }
52
parent_handler(int sig LTP_ATTRIBUTE_UNUSED)53 static void parent_handler(int sig LTP_ATTRIBUTE_UNUSED)
54 {
55 got_signal = 1;
56 }
57
do_child(unsigned int i)58 static void do_child(unsigned int i)
59 {
60 struct sigaction child_act;
61
62 if (i == 0)
63 child_act.sa_handler = SIG_IGN;
64 else
65 child_act.sa_handler = child_handler;
66
67 child_act.sa_flags = SA_RESTART;
68 sigemptyset(&child_act.sa_mask);
69
70 SAFE_SIGACTION(SIGUSR2, &child_act, NULL);
71
72 if ((ptrace(PTRACE_TRACEME, 0, 0, 0)) == -1) {
73 tst_res(TWARN, "ptrace() failed in child");
74 exit(1);
75 }
76 SAFE_KILL(getpid(), SIGUSR2);
77 exit(1);
78 }
79
run(unsigned int i)80 static void run(unsigned int i)
81 {
82 struct tcase *tc = &tcases[i];
83 pid_t child_pid;
84 int status;
85 struct sigaction parent_act;
86
87 got_signal = 0;
88
89 tst_res(TINFO, "%s", tc->message);
90
91 if (tc->handler == 1) {
92 parent_act.sa_handler = parent_handler;
93 parent_act.sa_flags = SA_RESTART;
94 sigemptyset(&parent_act.sa_mask);
95 SAFE_SIGACTION(SIGUSR2, &parent_act, NULL);
96 }
97
98 child_pid = SAFE_FORK();
99
100 if (!child_pid)
101 do_child(tc->handler);
102
103 SAFE_WAITPID(child_pid, &status, 0);
104
105 if (((WIFEXITED(status)) && (WEXITSTATUS(status)))
106 || (got_signal == 1))
107 tst_res(TFAIL, "Test Failed");
108 else if ((ptrace(tc->request, child_pid, 0, 0)) == -1)
109 tst_res(TFAIL | TERRNO, "ptrace(%i, %i, 0, 0) failed",
110 tc->request, child_pid);
111
112 SAFE_WAITPID(child_pid, &status, 0);
113
114 if ((tc->request == PTRACE_CONT &&
115 WIFEXITED(status) && WEXITSTATUS(status) == tc->exp_wifexited) ||
116 (tc->request == PTRACE_KILL &&
117 WIFSIGNALED(status) && WTERMSIG(status) == tc->exp_wtermsig)) {
118 tst_res(TPASS, "Child %s as expected", tst_strstatus(status));
119 } else {
120 tst_res(TFAIL, "Child %s unexpectedly", tst_strstatus(status));
121 }
122
123 }
124
125 static struct tst_test test = {
126 .test = run,
127 .tcnt = ARRAY_SIZE(tcases),
128 .forks_child = 1,
129 };
130