1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 2021 Jan Kokemüller
5  * Copyright 2021 Alex Richardson <arichardson@FreeBSD.org>
6  *
7  * This work was supported by Innovate UK project 105694, "Digital Security by
8  * Design (DSbD) Technology Platform Prototype".
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 #include <sys/event.h>
33 
34 #include <atf-c.h>
35 #include <errno.h>
36 #include <signal.h>
37 
38 ATF_TC_WITHOUT_HEAD(main);
39 
40 ATF_TC_BODY(main, tc)
41 {
42 	int rv;
43 
44 	sigset_t set;
45 	rv = sigemptyset(&set);
46 	ATF_REQUIRE_EQ(0, rv);
47 	rv = sigaddset(&set, SIGUSR1);
48 	ATF_REQUIRE_EQ(0, rv);
49 	rv = sigprocmask(SIG_BLOCK, &set, NULL);
50 	ATF_REQUIRE_EQ(0, rv);
51 
52 	int skq = kqueue();
53 	ATF_REQUIRE(skq >= 0);
54 
55 	struct kevent kev;
56 	EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
57 	rv = kevent(skq, &kev, 1, NULL, 0, NULL);
58 	ATF_REQUIRE_EQ(0, rv);
59 
60 	int kq = kqueue();
61 	ATF_REQUIRE(kq >= 0);
62 
63 	EV_SET(&kev, skq, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
64 	rv = kevent(kq, &kev, 1, NULL, 0, NULL);
65 	ATF_REQUIRE_EQ(0, rv);
66 
67 	/*
68 	 * It was previously not guaranteed that sending a signal to self would
69 	 * be immediately visible in the nested kqueue activation with a zero
70 	 * timeout. As of https://reviews.freebsd.org/D31858, the kqueue task
71 	 * queue will be processed in this case, so we are guaranteed to see the
72 	 * SIGUSR1 here even with a zero timeout. We run the code below in a
73 	 * loop to make it more likely that older kernels without the fix fail
74 	 * this test.
75 	 */
76 	for (int i = 0; i < 100; i++) {
77 		rv = kill(getpid(), SIGUSR1);
78 		ATF_REQUIRE_EQ(0, rv);
79 
80 		rv = kevent(kq, NULL, 0, &kev, 1, &(struct timespec) { 0, 0 });
81 		ATF_REQUIRE_EQ_MSG(1, rv,
82 		    "Unexpected result %d from kevent() after %d iterations",
83 		    rv, i);
84 		rv = kevent(kq, NULL, 0, &kev, 1, &(struct timespec) { 0, 0 });
85 		ATF_REQUIRE_EQ(0, rv);
86 
87 		rv = kevent(skq, NULL, 0, &kev, 1, &(struct timespec) { 0, 0 });
88 		ATF_REQUIRE_EQ(1, rv);
89 		rv = kevent(skq, NULL, 0, &kev, 1, &(struct timespec) { 0, 0 });
90 		ATF_REQUIRE_EQ(0, rv);
91 
92 		siginfo_t siginfo;
93 		rv = sigtimedwait(&set, &siginfo, &(struct timespec) { 0, 0 });
94 		ATF_REQUIRE_EQ(SIGUSR1, rv);
95 
96 		rv = sigtimedwait(&set, &siginfo, &(struct timespec) { 0, 0 });
97 		ATF_REQUIRE_ERRNO(EAGAIN, rv < 0);
98 	}
99 }
100 
101 ATF_TP_ADD_TCS(tp)
102 {
103 	ATF_TP_ADD_TC(tp, main);
104 
105 	return (atf_no_error());
106 }
107