Home | History | Annotate | Download | only in ptrace
      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 (at) 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 
    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() */
    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 */
    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  */
    264 void cleanup(void)
    265 {
    266 
    267 }
    268 
    269 /*
    270  * child_handler() - Signal handler for child
    271  */
    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  */
    284 void parent_handler(void)
    285 {
    286 
    287 	got_signal = 1;
    288 }
    289