• 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	: 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