1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) Wipro Technologies Ltd, 2002.  All Rights Reserved.
4  * Copyright (c) 2019 Jorik Cronenberg <jcronenberg@suse.de>
5  *
6  * Author: Saji Kumar.V.R <saji.kumar@wipro.com>
7  * Ported to new library: Jorik Cronenberg <jcronenberg@suse.de>
8  *
9  * Test the functionality of ptrace() for PTRACE_TRACEME & PTRACE_KILL requests.
10  * Forked child does ptrace(PTRACE_TRACEME, ...).
11  * Then a signal is delivered to the child and verified that parent
12  * is notified via wait().
13  * After parent does ptrace(PTRACE_KILL, ..) to kill the child
14  * and parent wait() for child to finish.
15  * Test passes if child finished abnormally.
16  *
17  * Testing two cases:
18  * 1) child ignore SIGUSR2 signal
19  * 2) using a signal handler for child for SIGUSR2
20  * In both cases, child should stop & notify parent on reception of SIGUSR2.
21  */
22 
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <sys/wait.h>
27 #include <config.h>
28 #include "ptrace.h"
29 #include "tst_test.h"
30 
31 static volatile int got_signal;
32 
child_handler(int sig LTP_ATTRIBUTE_UNUSED)33 static void child_handler(int sig LTP_ATTRIBUTE_UNUSED)
34 {
35 	SAFE_KILL(getppid(), SIGUSR2);
36 }
37 
parent_handler(int sig LTP_ATTRIBUTE_UNUSED)38 static void parent_handler(int sig LTP_ATTRIBUTE_UNUSED)
39 {
40 	got_signal = 1;
41 }
42 
do_child(unsigned int i)43 static void do_child(unsigned int i)
44 {
45 	struct sigaction child_act;
46 
47 	if (i == 0)
48 		child_act.sa_handler = SIG_IGN;
49 	else
50 		child_act.sa_handler = child_handler;
51 
52 	child_act.sa_flags = SA_RESTART;
53 	sigemptyset(&child_act.sa_mask);
54 
55 	SAFE_SIGACTION(SIGUSR2, &child_act, NULL);
56 
57 	if ((ptrace(PTRACE_TRACEME, 0, 0, 0)) == -1) {
58 		tst_res(TWARN, "ptrace() failed in child");
59 		exit(1);
60 	}
61 	SAFE_KILL(getpid(), SIGUSR2);
62 	exit(1);
63 }
64 
run(unsigned int i)65 static void run(unsigned int i)
66 {
67 	pid_t child_pid;
68 	int status;
69 	struct sigaction parent_act;
70 
71 	got_signal = 0;
72 
73 	if (i == 1) {
74 		parent_act.sa_handler = parent_handler;
75 		parent_act.sa_flags = SA_RESTART;
76 		sigemptyset(&parent_act.sa_mask);
77 		SAFE_SIGACTION(SIGUSR2, &parent_act, NULL);
78 	}
79 
80 	child_pid = SAFE_FORK();
81 
82 	if (!child_pid)
83 		do_child(i);
84 
85 	SAFE_WAITPID(child_pid, &status, 0);
86 
87 	if (((WIFEXITED(status)) && (WEXITSTATUS(status)))
88 		 || (got_signal == 1))
89 		tst_res(TFAIL, "Test Failed");
90 	else if ((ptrace(PTRACE_KILL, child_pid, 0, 0)) == -1)
91 		tst_res(TFAIL | TERRNO, "ptrace(PTRACE_KILL, %i, 0, 0) failed",
92 				child_pid);
93 
94 	SAFE_WAITPID(child_pid, &status, 0);
95 
96 	if (WTERMSIG(status) == 9)
97 		tst_res(TPASS, "Child %s as expected", tst_strstatus(status));
98 	else
99 		tst_res(TFAIL, "Child %s unexpectedly", tst_strstatus(status));
100 
101 }
102 
103 static struct tst_test test = {
104 	.test = run,
105 	.tcnt = 2,
106 	.forks_child = 1,
107 };
108