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 : ptrace02
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_CONT 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_CONT, ..)
39 * to make the child to continue. Again parent wait() for child to finish.
40 * If child finished normally, 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_CONT, ..) on child
65 * wait() for child to finish,
66 * if child exited normaly,
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 * ptrace02 [-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 = "ptrace02";
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 /* Restart child */
186 if ((ptrace(PTRACE_CONT, child_pid,
187 0, 0)) == -1) {
188 tst_resm(TFAIL, "Test Failed:"
189 " Parent was not able to do"
190 " ptrace(PTRACE_CONT, ..) on"
191 " child");
192 continue;
193 }
194 }
195
196 if ((waitpid(child_pid, &status, 0)) < 0) {
197 tst_resm(TFAIL, "waitpid() failed");
198 continue;
199 }
200
201 if (WIFEXITED(status)) {
202 /* Child exits normally */
203 tst_resm(TPASS, "Test Passed");
204 } else {
205 tst_resm(TFAIL, "Test Failed");
206 }
207
208 }
209 }
210 }
211
212 /* cleanup and exit */
213 cleanup();
214 tst_exit();
215
216 }
217
218 /* do_child() */
do_child(void)219 void do_child(void)
220 {
221 struct sigaction child_act;
222
223 /* Setup signal handler for child */
224 if (i == 0) {
225 child_act.sa_handler = SIG_IGN;
226 } else {
227 child_act.sa_handler = child_handler;
228 }
229 child_act.sa_flags = SA_RESTART;
230 sigemptyset(&child_act.sa_mask);
231
232 if ((sigaction(SIGUSR2, &child_act, NULL)) == -1) {
233 tst_resm(TWARN, "sigaction() failed in child");
234 exit(1);
235 }
236
237 if ((ptrace(PTRACE_TRACEME, 0, 0, 0)) == -1) {
238 tst_resm(TWARN, "ptrace() failed in child");
239 exit(1);
240 }
241
242 /* ensure that child bypasses signal handler */
243 if ((kill(getpid(), SIGUSR2)) == -1) {
244 tst_resm(TWARN, "kill() failed in child");
245 exit(1);
246 }
247 exit(1);
248 }
249
250 /* setup() - performs all ONE TIME setup for this test */
setup(void)251 void setup(void)
252 {
253
254 tst_sig(FORK, DEF_HANDLER, cleanup);
255
256 TEST_PAUSE;
257
258 }
259
260 /*
261 *cleanup() - performs all ONE TIME cleanup for this test at
262 * completion or premature exit.
263 */
cleanup(void)264 void cleanup(void)
265 {
266
267 }
268
269 /*
270 * child_handler() - Signal handler for child
271 */
child_handler(void)272 void child_handler(void)
273 {
274
275 if ((kill(getppid(), SIGUSR2)) == -1) {
276 tst_resm(TWARN, "kill() failed in child_handler()");
277 exit(1);
278 }
279 }
280
281 /*
282 * parent_handler() - Signal handler for parent
283 */
parent_handler(void)284 void parent_handler(void)
285 {
286
287 got_signal = 1;
288 }
289