1/*-
2 * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6#include <sys/cdefs.h>
7#include <sys/limits.h>
8#include <sys/time.h>
9#include <sys/sysctl.h>
10#include <sys/user.h>
11#include <sys/wait.h>
12
13#include <err.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <errno.h>
18#include <signal.h>
19#include <stdbool.h>
20#include <unistd.h>
21
22#include <atf-c.h>
23
24
25static inline struct timespec
26make_timespec(time_t s, long int ns)
27{
28	struct timespec rts;
29
30	rts.tv_sec = s;
31	rts.tv_nsec = ns;
32	return (rts);
33}
34
35static void
36dummy_sig_handler(int sig)
37{
38
39}
40
41static void
42dummy_sigchld(int signo, siginfo_t *info, void *ctx)
43{
44
45}
46
47static void
48support_signal(int sig, sig_t handler)
49{
50
51	ATF_REQUIRE(signal(sig, handler) != SIG_ERR);
52}
53
54static void
55support_sysctlset(const char *name, int32_t val)
56{
57
58	ATF_REQUIRE(sysctlbyname(name, NULL, NULL, &val, sizeof(val)) == 0);
59}
60
61static timer_t
62support_create_timer(uint64_t sec, long int nsec, bool repeat,
63    bool callback)
64{
65	struct sigevent ev = {
66		.sigev_notify = SIGEV_SIGNAL,
67		.sigev_signo = SIGALRM
68	};
69	struct itimerspec its =
70	{
71		{ .tv_sec = repeat ? sec : 0, .tv_nsec = repeat ? nsec : 0 },
72		{ .tv_sec = sec, .tv_nsec = nsec }
73	};
74	struct sigaction sa;
75	timer_t timerid;
76
77	if (callback) {
78		sa.sa_handler = dummy_sig_handler;
79		sigemptyset (&sa.sa_mask);
80		sa.sa_flags = 0;
81		ATF_REQUIRE(sigaction(SIGALRM, &sa, NULL) == 0);
82	}
83	ATF_REQUIRE(timer_create(CLOCK_REALTIME, &ev, &timerid) == 0);
84	ATF_REQUIRE(timer_settime(timerid, 0, &its, NULL) == 0);
85	return (timerid);
86}
87
88static void
89support_delete_timer(timer_t timer)
90{
91
92	ATF_REQUIRE(timer_delete(timer) == 0);
93	support_signal(SIGALRM, SIG_DFL);
94}
95
96static pid_t
97support_create_sig_proc(int sig, int count, unsigned int usec)
98{
99	pid_t pid, cpid;
100
101	pid = getpid();
102	ATF_REQUIRE(pid > 0);
103	cpid = fork();
104	ATF_REQUIRE(cpid >= 0);
105
106	if (cpid == 0) {
107		while (count-- > 0) {
108			usleep(usec);
109			if (kill(pid, sig) == -1)
110				break;
111		}
112		exit(0);
113	}
114	return (cpid);
115}
116
117#define TIMESPEC_HZ     1000000000
118
119static void
120test_sigtimedwait_timeout_eagain(time_t sec, bool zero_tmo)
121{
122	struct timespec ts, timeout, now;
123	sigset_t ss;
124	int rv;
125
126	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
127
128	timeout = make_timespec(sec, zero_tmo ? 0 : TIMESPEC_HZ/2);
129	timespecadd(&ts, &timeout, &ts);
130
131	sigemptyset(&ss);
132	sigaddset(&ss, SIGUSR1);
133	rv = sigtimedwait(&ss, NULL, &timeout);
134	ATF_REQUIRE_EQ_MSG(-1, rv,
135	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
136	ATF_REQUIRE_EQ_MSG(EAGAIN, errno,
137	    "sigtimedwait() should fail with EAGAIN: rv %d, errno %d",
138	    rv, errno);
139	/* now >= ts */
140	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
141	ATF_REQUIRE_MSG(timespeccmp(&now, &ts, >=) == true,
142	    "timespeccmp: now { %jd.%ld } < ts { %jd.%ld }",
143	    (intmax_t)now.tv_sec, now.tv_nsec,
144	    (intmax_t)ts.tv_sec, ts.tv_nsec);
145}
146
147ATF_TC(test_sigtimedwait_timeout_eagain0);
148ATF_TC_HEAD(test_sigtimedwait_timeout_eagain0, tc)
149{
150
151	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
152}
153
154ATF_TC_BODY(test_sigtimedwait_timeout_eagain0, tc)
155{
156
157	test_sigtimedwait_timeout_eagain(0, true);
158}
159
160ATF_TC(test_sigtimedwait_timeout_eagain1);
161ATF_TC_HEAD(test_sigtimedwait_timeout_eagain1, tc)
162{
163
164	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
165}
166
167ATF_TC_BODY(test_sigtimedwait_timeout_eagain1, tc)
168{
169
170	test_sigtimedwait_timeout_eagain(-1, true);
171}
172
173ATF_TC(test_sigtimedwait_timeout_eagain2);
174ATF_TC_HEAD(test_sigtimedwait_timeout_eagain2, tc)
175{
176
177	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
178}
179
180ATF_TC_BODY(test_sigtimedwait_timeout_eagain2, tc)
181{
182
183	test_sigtimedwait_timeout_eagain(-1, false);
184}
185
186ATF_TC(test_sigtimedwait_timeout_eagain3);
187ATF_TC_HEAD(test_sigtimedwait_timeout_eagain3, tc)
188{
189
190	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits after specified timeout");
191}
192
193ATF_TC_BODY(test_sigtimedwait_timeout_eagain3, tc)
194{
195
196	test_sigtimedwait_timeout_eagain(0, false);
197}
198
199ATF_TC(test_sigtimedwait_large_timeout_eintr);
200ATF_TC_HEAD(test_sigtimedwait_large_timeout_eintr, tc)
201{
202
203	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINTR");
204}
205
206ATF_TC_BODY(test_sigtimedwait_large_timeout_eintr, tc)
207{
208	struct timespec ts;
209	timer_t timerid;
210	sigset_t ss;
211	int rv;
212
213	ts = make_timespec(LONG_MAX, 0);
214	timerid = support_create_timer(0, 100000000, false, true);
215
216	sigemptyset(&ss);
217	sigaddset(&ss, SIGUSR1);
218	rv = sigtimedwait(&ss, NULL, &ts);
219	ATF_REQUIRE_EQ_MSG(-1, rv,
220	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
221	ATF_REQUIRE_EQ_MSG(EINTR, errno,
222	    "sigtimedwait() should fail with EINTR: rv %d, errno %d",
223	    rv, errno);
224	support_delete_timer(timerid);
225}
226
227ATF_TC(test_sigtimedwait_infinity);
228ATF_TC_HEAD(test_sigtimedwait_infinity, tc)
229{
230
231	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINTR");
232}
233
234ATF_TC_BODY(test_sigtimedwait_infinity, tc)
235{
236	timer_t timerid;
237	sigset_t ss;
238	int rv;
239
240	timerid = support_create_timer(0, 100000000, false, true);
241
242	sigemptyset(&ss);
243	sigaddset(&ss, SIGUSR1);
244	rv = sigtimedwait(&ss, NULL, NULL);
245	ATF_REQUIRE_EQ_MSG(-1, rv,
246	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
247	ATF_REQUIRE_EQ_MSG(EINTR, errno,
248	    "sigtimedwait() should fail with EINTR: rv %d, errno %d",
249	    rv, errno);
250	support_delete_timer(timerid);
251}
252
253ATF_TC(test_sigtimedwait_einval);
254ATF_TC_HEAD(test_sigtimedwait_einval, tc)
255{
256
257	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINVAL");
258}
259
260ATF_TC_BODY(test_sigtimedwait_einval, tc)
261{
262	struct timespec ts;
263	timer_t timerid;
264	sigset_t ss;
265	int rv;
266
267	ts = make_timespec(0, -1);
268	timerid = support_create_timer(0, 100000000, false, true);
269
270	sigemptyset(&ss);
271	sigaddset(&ss, SIGUSR1);
272	rv = sigtimedwait(&ss, NULL, &ts);
273	ATF_REQUIRE_EQ_MSG(-1, rv,
274	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
275	ATF_REQUIRE_EQ_MSG(EINVAL, errno,
276	    "sigtimedwait() should fail with EINVAL: rv %d, errno %d",
277	    rv, errno);
278	support_delete_timer(timerid);
279}
280
281ATF_TC(test_sigwait_eintr);
282ATF_TC_HEAD(test_sigwait_eintr, tc)
283{
284
285	atf_tc_set_md_var(tc, "descr", "Check if sigwait exits with EINTR");
286}
287
288ATF_TC_BODY(test_sigwait_eintr, tc)
289{
290	timer_t timerid;
291	sigset_t ss;
292	int rv, sig, pid;
293
294	support_signal(SIGUSR1, dummy_sig_handler);
295
296	pid = support_create_sig_proc(SIGUSR1, 1, 400000);
297	timerid = support_create_timer(0, 200000, false, true);
298
299	sigemptyset(&ss);
300	sigaddset(&ss, SIGUSR1);
301	rv = sigwait(&ss, &sig);
302	ATF_REQUIRE_EQ_MSG(0, rv,
303	    "sigwait() should not fail: rv %d, errno %d", rv, errno);
304	ATF_REQUIRE_EQ_MSG(SIGUSR1, sig,
305	    "sigwait() should return SIGUSR1: rv %d, sig %d", rv, sig);
306	ATF_REQUIRE(waitid(P_PID, pid, NULL, WEXITED) == 0);
307	support_delete_timer(timerid);
308}
309
310ATF_TC(test_sigwaitinfo_eintr);
311ATF_TC_HEAD(test_sigwaitinfo_eintr, tc)
312{
313
314	atf_tc_set_md_var(tc, "descr", "Check if sigwaitinfo exits with EINTR");
315}
316
317ATF_TC_BODY(test_sigwaitinfo_eintr, tc)
318{
319	timer_t timerid;
320	sigset_t ss;
321	int rv;
322
323	timerid = support_create_timer(0, 100000000, false, true);
324
325	sigemptyset(&ss);
326	sigaddset(&ss, SIGUSR1);
327	rv = sigwaitinfo(&ss, NULL);
328	ATF_REQUIRE_EQ_MSG(-1, rv,
329	    "sigwaitinfo() should fail, rv %d != -1", rv);
330	ATF_REQUIRE_EQ_MSG(EINTR, errno,
331	    "sigwaitinfo() should fail errno %d != EINTR", errno);
332	support_delete_timer(timerid);
333}
334
335/*
336 * Test kern.sig_discard_ign knob (default true).
337 * See commit bc387624
338 */
339static void
340test_sig_discard_ign(bool ignore)
341{
342	struct timespec ts;
343	sigset_t mask;
344	pid_t pid;
345	int rv;
346
347	support_signal(SIGUSR2, SIG_IGN);
348
349	if (ignore)
350		support_sysctlset("kern.sig_discard_ign", 1);
351	else
352		support_sysctlset("kern.sig_discard_ign", 0);
353
354	sigemptyset(&mask);
355	sigaddset(&mask, SIGUSR2);
356	ATF_REQUIRE(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
357
358	pid = support_create_sig_proc(SIGUSR2, 1, 100000);
359
360	ts = make_timespec(1, 0);
361	rv = sigtimedwait(&mask, NULL, &ts);
362	if (ignore == true) {
363		ATF_REQUIRE_EQ_MSG(-1, rv,
364		    "sigtimedwait() ign=on should fail, rv %d != -1", rv);
365		ATF_REQUIRE_EQ_MSG(EAGAIN, errno,
366		    "sigtimedwait() ign=on should fail with EAGAIN errno %d",
367		    errno);
368	} else
369		ATF_REQUIRE_EQ_MSG(SIGUSR2, rv,
370		    "sigtimedwait() ign=off should return SIGUSR2, rv %d errno %d",
371		    rv, errno);
372	ATF_REQUIRE(waitid(P_PID, pid, NULL, WEXITED) == 0);
373}
374
375static void
376support_check_siginfo(int code, int status, pid_t pid,
377    siginfo_t *si, int sig)
378{
379
380	ATF_REQUIRE_EQ_MSG(sig, si->si_signo,
381	    "check_siginfo: si_signo %d != sig %d", si->si_signo, sig);
382	ATF_REQUIRE_EQ_MSG(code, si->si_code,
383	    "check_siginfo: si_code %d != code %d", si->si_code, code);
384	ATF_REQUIRE_EQ_MSG(status, si->si_status,
385	    "check_siginfo: si_status %d != status %d", si->si_status, status);
386	ATF_REQUIRE_EQ_MSG(pid, si->si_pid,
387	    "check_siginfo: si_pid %d != pid %d", si->si_pid, pid);
388}
389
390static void
391support_check_sigchld(sigset_t *set, int code, int status, pid_t pid,
392    bool dequeue)
393{
394	siginfo_t si;
395	int sig, kpid;
396
397	if (dequeue == true)
398		kpid = support_create_sig_proc(SIGUSR2, 1, 1000000);
399
400	sig = sigwaitinfo(set, &si);
401	if (dequeue == true) {
402		ATF_REQUIRE_EQ_MSG(-1, sig,
403		    "sigwaitinfo() should fail, sig %d != -1", sig);
404		ATF_REQUIRE_EQ_MSG(EINTR, errno,
405		    "sigwaitinfo() should fail errno %d != EINTR", errno);
406	} else
407		ATF_REQUIRE_EQ_MSG(SIGCHLD, sig,
408		    "sigwaitinfo() %d != SIGCHLD", sig);
409	if (dequeue == false)
410		support_check_siginfo(code, status, pid, &si, SIGCHLD);
411	if (dequeue == true)
412		ATF_REQUIRE(waitid(P_PID, kpid, &si, WEXITED) == 0);
413}
414
415static void
416test_child(void)
417{
418
419	raise(SIGSTOP);
420	while (1)
421		pause();
422}
423
424/*
425 * Test kern.wait_dequeue_sigchld knob.
426 */
427static void
428test_wait_dequeue_sigchld(bool dequeue)
429{
430	struct sigaction sa;
431	siginfo_t si;
432	sigset_t set;
433	pid_t pid;
434
435	sa.sa_flags = SA_SIGINFO | SA_RESTART;
436	sa.sa_sigaction = dummy_sigchld;
437	sigemptyset(&sa.sa_mask);
438	ATF_REQUIRE(sigaction(SIGCHLD, &sa, NULL) == 0);
439
440	support_signal(SIGUSR2, dummy_sig_handler);
441
442	sigemptyset(&set);
443	sigaddset(&set, SIGCHLD);
444	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
445
446	if (dequeue)
447		support_sysctlset("kern.wait_dequeue_sigchld", 1);
448	else
449		support_sysctlset("kern.wait_dequeue_sigchld", 0);
450
451	pid = fork();
452	ATF_REQUIRE(pid >= 0);
453	if (pid == 0) {
454		test_child();
455		exit(0);
456	}
457
458	bzero(&si, sizeof(si));
459	ATF_REQUIRE(waitid(P_PID, pid, &si, WSTOPPED) == 0);
460
461	support_check_siginfo(CLD_STOPPED, SIGSTOP, pid, &si, SIGCHLD);
462	support_check_sigchld(&set, CLD_STOPPED, SIGSTOP, pid, dequeue);
463
464	ATF_REQUIRE(kill(pid, SIGCONT) == 0);
465
466	bzero(&si, sizeof(si));
467	ATF_REQUIRE(waitid(P_PID, pid, &si, WCONTINUED) == 0);
468
469	support_check_siginfo(CLD_CONTINUED, SIGCONT, pid, &si, SIGCHLD);
470	support_check_sigchld(&set, CLD_CONTINUED, SIGCONT, pid, dequeue);
471
472	ATF_REQUIRE(kill(pid, SIGKILL) == 0);
473
474	bzero(&si, sizeof(si));
475	ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0);
476
477	support_check_siginfo(CLD_KILLED, SIGKILL, pid, &si, SIGCHLD);
478}
479
480ATF_TC_WITH_CLEANUP(test_sig_discard_ign_true);
481ATF_TC_HEAD(test_sig_discard_ign_true, tc)
482{
483
484	atf_tc_set_md_var(tc, "require.user", "root");
485	atf_tc_set_md_var(tc, "descr", "Test kern.sig_discard_ign on");
486}
487
488ATF_TC_BODY(test_sig_discard_ign_true, tc)
489{
490
491	test_sig_discard_ign(true);
492}
493
494ATF_TC_CLEANUP(test_sig_discard_ign_true, tc)
495{
496
497	support_sysctlset("kern.sig_discard_ign", 1);
498}
499
500ATF_TC_WITH_CLEANUP(test_sig_discard_ign_false);
501ATF_TC_HEAD(test_sig_discard_ign_false, tc)
502{
503
504	atf_tc_set_md_var(tc, "require.user", "root");
505	atf_tc_set_md_var(tc, "descr", "Test kern.sig_discard_ign off");
506}
507
508ATF_TC_BODY(test_sig_discard_ign_false, tc)
509{
510
511	test_sig_discard_ign(false);
512}
513
514ATF_TC_CLEANUP(test_sig_discard_ign_false, tc)
515{
516
517	support_sysctlset("kern.sig_discard_ign", 1);
518}
519
520ATF_TC_WITH_CLEANUP(test_wait_dequeue_sigchld_true);
521ATF_TC_HEAD(test_wait_dequeue_sigchld_true, tc)
522{
523
524	atf_tc_set_md_var(tc, "require.user", "root");
525	atf_tc_set_md_var(tc, "descr", "Test kern.wait_dequeue_sigchld on");
526}
527
528ATF_TC_BODY(test_wait_dequeue_sigchld_true, tc)
529{
530
531	test_wait_dequeue_sigchld(true);
532}
533
534ATF_TC_CLEANUP(test_wait_dequeue_sigchld_true, tc)
535{
536
537	support_sysctlset("kern.wait_dequeue_sigchld", 1);
538}
539
540ATF_TC_WITH_CLEANUP(test_wait_dequeue_sigchld_false);
541ATF_TC_HEAD(test_wait_dequeue_sigchld_false, tc)
542{
543
544	atf_tc_set_md_var(tc, "require.user", "root");
545	atf_tc_set_md_var(tc, "descr", "Test kern.wait_dequeue_sigchld off");
546}
547
548ATF_TC_BODY(test_wait_dequeue_sigchld_false, tc)
549{
550
551	test_wait_dequeue_sigchld(false);
552}
553
554ATF_TC_CLEANUP(test_wait_dequeue_sigchld_false, tc)
555{
556
557	support_sysctlset("kern.wait_dequeue_sigchld", 1);
558}
559
560ATF_TP_ADD_TCS(tp)
561{
562
563	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain0);
564	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain1);
565	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain2);
566	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain3);
567
568	ATF_TP_ADD_TC(tp, test_sigtimedwait_large_timeout_eintr);
569	ATF_TP_ADD_TC(tp, test_sigtimedwait_infinity);
570
571	ATF_TP_ADD_TC(tp, test_sigtimedwait_einval);
572
573	ATF_TP_ADD_TC(tp, test_sigwait_eintr);
574	ATF_TP_ADD_TC(tp, test_sigwaitinfo_eintr);
575
576	ATF_TP_ADD_TC(tp, test_sig_discard_ign_true);
577	ATF_TP_ADD_TC(tp, test_sig_discard_ign_false);
578
579	ATF_TP_ADD_TC(tp, test_wait_dequeue_sigchld_true);
580	ATF_TP_ADD_TC(tp, test_wait_dequeue_sigchld_false);
581
582	return (atf_no_error());
583}
584