1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * 07/2001 John George
5 * Copyright (c) 2018 Cyril Hrubis <[email protected]>
6 */
7
8 /*\
9 * [Description]
10 *
11 * Check that when a child kills itself with one of the standard signals,
12 * the waiting parent is correctly notified.
13 *
14 * Fork a child that sends given signal to itself using raise() or kill(),
15 * the parent checks that the signal was returned.
16 */
17 #include <stdlib.h>
18 #include <sys/wait.h>
19 #include "tst_test.h"
20
21 static int test_coredump;
22 static struct testcase {
23 int sig;
24 int coredump;
25 } testcase_list[] = {
26 {SIGABRT, 1},
27 {SIGALRM, 0},
28 {SIGBUS, 1},
29 {SIGFPE, 1},
30 {SIGHUP, 0},
31 {SIGILL, 1},
32 {SIGINT, 0},
33 {SIGKILL, 0},
34 {SIGPIPE, 0},
35 {SIGPOLL, 0},
36 {SIGPROF, 0},
37 {SIGQUIT, 1},
38 {SIGSEGV, 1},
39 {SIGSYS, 1},
40 {SIGTERM, 0},
41 {SIGTRAP, 1},
42 {SIGUSR1, 0},
43 {SIGUSR2, 0},
44 {SIGVTALRM, 0},
45 {SIGXCPU, 1},
46 {SIGXFSZ, 1}
47 };
48
child_raise(int sig)49 static void child_raise(int sig)
50 {
51 raise(sig);
52 exit(0);
53 }
54
child_kill(int sig)55 static void child_kill(int sig)
56 {
57 kill(getpid(), sig);
58 exit(0);
59 }
60
61 static struct testvariant {
62 void (*func)(int sig);
63 const char *desc;
64 } variant_list[] = {
65 {child_raise, "raise(sig)"},
66 {child_kill, "kill(getpid(), sig)"}
67 };
68
setup(void)69 static void setup(void)
70 {
71 struct rlimit lim = { 0 };
72
73 /* Disable core dumps */
74 SAFE_GETRLIMIT(RLIMIT_CORE, &lim);
75
76 if (lim.rlim_max) {
77 lim.rlim_cur = getpagesize();
78
79 if (lim.rlim_max > 0 && lim.rlim_max < lim.rlim_cur)
80 lim.rlim_cur = lim.rlim_max;
81
82 SAFE_SETRLIMIT(RLIMIT_CORE, &lim);
83 test_coredump = 1;
84 } else {
85 tst_res(TCONF, "Skipping coredump tests due to low rlimit");
86 }
87
88 tst_res(TINFO, "Testing child: %s", variant_list[tst_variant].desc);
89 }
90
run(unsigned int n)91 static void run(unsigned int n)
92 {
93 pid_t pid;
94 int status;
95 const struct testcase *tc = testcase_list + n;
96
97 if (tc->sig != SIGKILL)
98 SAFE_SIGNAL(tc->sig, SIG_DFL);
99
100 pid = SAFE_FORK();
101 if (!pid)
102 variant_list[tst_variant].func(tc->sig);
103
104 TST_EXP_PID_SILENT(waitpid(pid, &status, 0));
105 if (!TST_PASS)
106 return;
107
108 if (TST_RET != pid) {
109 tst_res(TFAIL, "waitpid() returned wrong pid %li, expected %i",
110 TST_RET, pid);
111 } else {
112 tst_res(TPASS, "waitpid() returned correct pid %i", pid);
113 }
114
115 if (!WIFSIGNALED(status)) {
116 tst_res(TFAIL, "WIFSIGNALED() not set in status (%s)",
117 tst_strstatus(status));
118 return;
119 }
120
121 tst_res(TPASS, "WIFSIGNALED() set in status");
122
123 if (WTERMSIG(status) != tc->sig) {
124 tst_res(TFAIL, "WTERMSIG() != %s but %s", tst_strsig(tc->sig),
125 tst_strsig(WTERMSIG(status)));
126 return;
127 }
128
129 tst_res(TPASS, "WTERMSIG() == %s", tst_strsig(tc->sig));
130
131 if (!test_coredump)
132 return;
133
134 if (!tc->coredump) {
135 if (WCOREDUMP(status))
136 tst_res(TFAIL, "Child unexpectedly dumped core");
137
138 return;
139 }
140
141 if (!WCOREDUMP(status)) {
142 tst_res(TFAIL, "Child did not dump core when expected");
143 return;
144 }
145
146 tst_res(TPASS, "Child dumped core as expected");
147 }
148
149 static struct tst_test test = {
150 .forks_child = 1,
151 .setup = setup,
152 .test = run,
153 .tcnt = ARRAY_SIZE(testcase_list),
154 .test_variants = ARRAY_SIZE(variant_list),
155 .needs_tmpdir = 1 /* for coredumps */
156 };
157