1 /*
2 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 *
16 */
17 /**********************************************************
18 *
19 * TEST IDENTIFIER : ptrace01
20 *
21 * EXECUTED BY : anyone
22 *
23 * TEST TITLE : functionality test for ptrace(2)
24 *
25 * TEST CASE TOTAL : 2
26 *
27 * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com>
28 *
29 * SIGNALS
30 * Uses SIGUSR1 to pause before test if option set.
31 * (See the parse_opts(3) man page).
32 *
33 * DESCRIPTION
34 * This test case tests the functionality of ptrace() for
35 * PTRACE_TRACEME & PTRACE_KILL requests.
36 * Here, we fork a child & the child does ptrace(PTRACE_TRACEME, ...).
37 * Then a signal is delivered to the child & verified that parent
38 * is notified via wait(). then parent does ptrace(PTRACE_KILL, ..)
39 * to kill the child. Again parent wait() for child to finish.
40 * If child finished abnormally, test passes.
41 * We test two cases
42 * 1) By telling child to ignore SIGUSR2 signal
43 * 2) By installing a signal handler for child for SIGUSR2
44 * In both cases, child should stop & notify parent on reception
45 * of SIGUSR2
46 *
47 * Setup:
48 * Setup signal handling.
49 * Pause for SIGUSR1 if option specified.
50 *
51 * Test:
52 * Loop if the proper options are given.
53 * setup signal handler for SIGUSR2 signal
54 * fork a child
55 *
56 * CHILD:
57 * setup signal handler for SIGUSR2 signal
58 * call ptrace() with PTRACE_TRACEME request
59 * send SIGUSR2 signal to self
60 * PARENT:
61 * wait() for child.
62 * if parent is notified when child gets a signal through wait(),
63 * then
64 * do ptrace(PTRACE_KILL, ..) on child
65 * wait() for child to finish,
66 * if child exited abnormaly,
67 * TEST passed
68 * else
69 * TEST failed
70 * else
71 * TEST failed
72 *
73 * Cleanup:
74 * Print errno log and/or timing stats if options given
75 *
76 * USAGE: <for command-line>
77 * ptrace01 [-c n] [-e] [-i n] [-I x] [-P x] [-t] [-h] [-f] [-p]
78 * where, -c n : Run n copies concurrently.
79 * -e : Turn on errno logging.
80 * -h : Show help screen
81 * -f : Turn off functional testing
82 * -i n : Execute test n times.
83 * -I x : Execute test for x seconds.
84 * -p : Pause for SIGUSR1 before starting
85 * -P x : Pause for x seconds between iterations.
86 * -t : Turn on syscall timing.
87 *
88 ****************************************************************/
89
90 #include <errno.h>
91 #include <signal.h>
92 #include <sys/wait.h>
93
94 #include <config.h>
95 #include "ptrace.h"
96
97 #include "test.h"
98
99 static void do_child(void);
100 static void setup(void);
101 static void cleanup(void);
102 static void child_handler();
103 static void parent_handler();
104
105 static int got_signal = 0;
106
107 char *TCID = "ptrace01";
108 static int i; /* loop test case counter, shared with do_child */
109
110 int TST_TOTAL = 2;
111
main(int ac,char ** av)112 int main(int ac, char **av)
113 {
114
115 int lc;
116 pid_t child_pid;
117 int status;
118 struct sigaction parent_act;
119
120 tst_parse_opts(ac, av, NULL, NULL);
121 #ifdef UCLINUX
122 maybe_run_child(&do_child, "d", &i);
123 #endif
124
125 setup();
126
127 for (lc = 0; TEST_LOOPING(lc); lc++) {
128
129 tst_count = 0;
130
131 for (i = 0; i < TST_TOTAL; ++i) {
132 got_signal = 0;
133
134 /* Setup signal handler for parent */
135 if (i == 1) {
136 parent_act.sa_handler = parent_handler;
137 parent_act.sa_flags = SA_RESTART;
138 sigemptyset(&parent_act.sa_mask);
139
140 if ((sigaction(SIGUSR2, &parent_act, NULL))
141 == -1) {
142 tst_resm(TWARN, "sigaction() failed"
143 " in parent");
144 continue;
145 }
146 }
147
148 switch (child_pid = FORK_OR_VFORK()) {
149
150 case -1:
151 /* fork() failed */
152 tst_resm(TFAIL, "fork() failed");
153 continue;
154
155 case 0:
156 /* Child */
157 #ifdef UCLINUX
158 if (self_exec(av[0], "d", i) < 0) {
159 tst_resm(TFAIL, "self_exec failed");
160 continue;
161 }
162 #else
163 do_child();
164 #endif
165
166 default:
167 /* Parent */
168 if ((waitpid(child_pid, &status, 0)) < 0) {
169 tst_resm(TFAIL, "waitpid() failed");
170 continue;
171 }
172
173 /*
174 * Check the exit status of child. If (it exits
175 * normally with exit value 1) OR (child came
176 * through signal handler), Test Failed
177 */
178
179 if (((WIFEXITED(status)) &&
180 (WEXITSTATUS(status))) ||
181 (got_signal == 1)) {
182 tst_resm(TFAIL, "Test Failed");
183 continue;
184 } else {
185 /* Kill child */
186 if ((ptrace(PTRACE_KILL, child_pid,
187 0, 0)) == -1) {
188 tst_resm(TFAIL, "Test Failed:"
189 " Parent was not able to kill"
190 " child");
191 continue;
192 }
193 }
194
195 if ((waitpid(child_pid, &status, 0)) < 0) {
196 tst_resm(TFAIL, "waitpid() failed");
197 continue;
198 }
199
200 if (WIFEXITED(status)) {
201 /* Child exits normally */
202 tst_resm(TFAIL, "Test failed");
203 } else {
204 tst_resm(TPASS, "Test Passed");
205 }
206
207 }
208 }
209 }
210
211 /* cleanup and exit */
212 cleanup();
213 tst_exit();
214
215 }
216
217 /* do_child() */
do_child(void)218 void do_child(void)
219 {
220 struct sigaction child_act;
221
222 /* Setup signal handler for child */
223 if (i == 0) {
224 child_act.sa_handler = SIG_IGN;
225 } else {
226 child_act.sa_handler = child_handler;
227 }
228 child_act.sa_flags = SA_RESTART;
229 sigemptyset(&child_act.sa_mask);
230
231 if ((sigaction(SIGUSR2, &child_act, NULL)) == -1) {
232 tst_resm(TWARN, "sigaction() failed in child");
233 exit(1);
234 }
235
236 if ((ptrace(PTRACE_TRACEME, 0, 0, 0)) == -1) {
237 tst_resm(TWARN, "ptrace() failed in child");
238 exit(1);
239 }
240 /* ensure that child bypasses signal handler */
241 if ((kill(getpid(), SIGUSR2)) == -1) {
242 tst_resm(TWARN, "kill() failed in child");
243 exit(1);
244 }
245 exit(1);
246 }
247
248 /* setup() - performs all ONE TIME setup for this test */
setup(void)249 void setup(void)
250 {
251
252 tst_sig(FORK, DEF_HANDLER, cleanup);
253
254 TEST_PAUSE;
255
256 }
257
258 /*
259 *cleanup() - performs all ONE TIME cleanup for this test at
260 * completion or premature exit.
261 */
cleanup(void)262 void cleanup(void)
263 {
264
265 }
266
267 /*
268 * child_handler() - Signal handler for child
269 */
child_handler(void)270 void child_handler(void)
271 {
272
273 if ((kill(getppid(), SIGUSR2)) == -1) {
274 tst_resm(TWARN, "kill() failed in child_handler()");
275 exit(1);
276 }
277 }
278
279 /*
280 * parent_handler() - Signal handler for parent
281 */
parent_handler(void)282 void parent_handler(void)
283 {
284
285 got_signal = 1;
286 }
287