• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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