1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * test_sigreceive - wait for signal and exit with value of it
5 *
6 * Written by Sami Kerola <kerolasa@iki.fi>
7 */
8
9 #include <err.h>
10 #include <getopt.h>
11 #include <pwd.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/select.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include "strutils.h"
20
21 #define TEST_SIGRECEIVE_FAILURE 0
22
23 static void __attribute__((__noreturn__)) usage(FILE *out)
24 {
25 fputs("Usage: test_sigreceive [-s|--setuid <login|uid>]\n", out);
26 exit(TEST_SIGRECEIVE_FAILURE);
27 }
28
29 static __attribute__((__noreturn__))
30 void exiter(int signo __attribute__((__unused__)),
31 siginfo_t *info,
32 void *context __attribute__((__unused__)))
33 {
34 int ret = info->si_signo;
35
36 if (info->si_code == SI_QUEUE && info->si_value.sival_int != 0)
37 ret = info->si_value.sival_int;
38 _exit(ret);
39 }
40
41 int main(int argc, char **argv)
42 {
43 struct sigaction sigact;
44 fd_set rfds;
45 struct timeval timeout;
46 char *user = NULL;
47 int c;
48
49 static const struct option longopts[] = {
50 {"setuid", required_argument, NULL, 's'},
51 {NULL, 0, NULL, 0}
52 };
53
54 while ((c = getopt_long(argc, argv, "s:h", longopts, NULL)) != -1)
55 switch (c) {
56 case 's':
57 user = optarg;
58 break;
59 case 'h':
60 usage(stdout);
61 default:
62 usage(stderr);
63 }
64
65 if (user) {
66 struct passwd *pw;
67 uid_t uid;
68
69 pw = getpwnam(user);
70 if (pw)
71 uid = pw->pw_uid;
72 else
73 uid = strtou32_or_err(user, "failed to parse uid");
74 if (setuid(uid) < 0)
75 err(TEST_SIGRECEIVE_FAILURE, "setuid failed");
76 }
77
78 sigemptyset(&sigact.sa_mask);
79 sigact.sa_flags = SA_SIGINFO;
80 sigact.sa_sigaction = exiter;
81 timeout.tv_sec = 5;
82 timeout.tv_usec = 0;
83
84 sigaction(SIGINT, &sigact, NULL);
85 sigaction(SIGQUIT, &sigact, NULL);
86 sigaction(SIGILL, &sigact, NULL);
87 #ifdef SIGTRAP
88 sigaction(SIGTRAP, &sigact, NULL);
89 #endif
90 sigaction(SIGABRT, &sigact, NULL);
91 #ifdef SIGIOT
92 sigaction(SIGIOT, &sigact, NULL);
93 #endif
94 #ifdef SIGEMT
95 sigaction(SIGEMT, &sigact, NULL);
96 #endif
97 #ifdef SIGBUS
98 sigaction(SIGBUS, &sigact, NULL);
99 #endif
100 sigaction(SIGFPE, &sigact, NULL);
101 sigaction(SIGUSR1, &sigact, NULL);
102 sigaction(SIGSEGV, &sigact, NULL);
103 sigaction(SIGUSR2, &sigact, NULL);
104 sigaction(SIGPIPE, &sigact, NULL);
105 sigaction(SIGALRM, &sigact, NULL);
106 sigaction(SIGTERM, &sigact, NULL);
107 #ifdef SIGSTKFLT
108 sigaction(SIGSTKFLT, &sigact, NULL);
109 #endif
110 sigaction(SIGCHLD, &sigact, NULL);
111 #ifdef SIGCLD
112 sigaction(SIGCLD, &sigact, NULL);
113 #endif
114 sigaction(SIGCONT, &sigact, NULL);
115 sigaction(SIGTSTP, &sigact, NULL);
116 sigaction(SIGTTIN, &sigact, NULL);
117 sigaction(SIGTTOU, &sigact, NULL);
118 #ifdef SIGURG
119 sigaction(SIGURG, &sigact, NULL);
120 #endif
121 #ifdef SIGXCPU
122 sigaction(SIGXCPU, &sigact, NULL);
123 #endif
124 #ifdef SIGXFSZ
125 sigaction(SIGXFSZ, &sigact, NULL);
126 #endif
127 #ifdef SIGVTALRM
128 sigaction(SIGVTALRM, &sigact, NULL);
129 #endif
130 #ifdef SIGPROF
131 sigaction(SIGPROF, &sigact, NULL);
132 #endif
133 #ifdef SIGWINCH
134 sigaction(SIGWINCH, &sigact, NULL);
135 #endif
136 #ifdef SIGIO
137 sigaction(SIGIO, &sigact, NULL);
138 #endif
139 #ifdef SIGPOLL
140 sigaction(SIGPOLL, &sigact, NULL);
141 #endif
142 #ifdef SIGINFO
143 sigaction(SIGINFO, &sigact, NULL);
144 #endif
145 #ifdef SIGLOST
146 sigaction(SIGLOST, &sigact, NULL);
147 #endif
148 #ifdef SIGPWR
149 sigaction(SIGPWR, &sigact, NULL);
150 #endif
151 #ifdef SIGUNUSED
152 sigaction(SIGUNUSED, &sigact, NULL);
153 #endif
154 #ifdef SIGSYS
155 sigaction(SIGSYS, &sigact, NULL);
156 #endif
157 #ifdef SIGRTMIN
158 sigaction(SIGRTMIN, &sigact, NULL);
159 sigaction(SIGRTMAX, &sigact, NULL);
160 #endif
161 /* Keep SIGHUP last, the bit it flips tells to check script the
162 * helper is ready to be killed. */
163 sigaction(SIGHUP, &sigact, NULL);
164
165 FD_ZERO(&rfds);
166 FD_SET(STDIN_FILENO, &rfds);
167 select(0, &rfds, NULL, NULL, &timeout);
168
169 exit(TEST_SIGRECEIVE_FAILURE);
170 }