1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2019 Jilles Tjoelker
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30#include <sys/mman.h>
31
32#include <atf-c.h>
33#include <fcntl.h>
34#include <setjmp.h>
35#include <signal.h>
36#include <stdio.h>
37
38static sigjmp_buf sig_env;
39static volatile int last_sig, last_code;
40
41static void
42sighandler(int sig, siginfo_t *info, void *context __unused)
43{
44
45	last_sig = sig;
46	last_code = info->si_code;
47	siglongjmp(sig_env, 1);
48}
49
50static void
51setup_signals(void)
52{
53	struct sigaction sa;
54	int r;
55
56	sa.sa_sigaction = sighandler;
57	sa.sa_flags = SA_RESTART | SA_RESETHAND | SA_SIGINFO;
58	r = sigfillset(&sa.sa_mask);
59	ATF_REQUIRE(r != -1);
60	r = sigaction(SIGILL, &sa, NULL);
61	ATF_REQUIRE(r != -1);
62	r = sigaction(SIGBUS, &sa, NULL);
63	ATF_REQUIRE(r != -1);
64	r = sigaction(SIGSEGV, &sa, NULL);
65	ATF_REQUIRE(r != -1);
66}
67
68ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_maperr_1);
69ATF_TC_BODY(page_fault_signal__segv_maperr_1, tc)
70{
71	int *p;
72	int r;
73	int sz;
74
75	sz = getpagesize();
76	p = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
77	ATF_REQUIRE(p != MAP_FAILED);
78	r = munmap(p, sz);
79	ATF_REQUIRE(r != -1);
80	if (sigsetjmp(sig_env, 1) == 0) {
81		setup_signals();
82		*(volatile int *)p = 1;
83	}
84	ATF_CHECK_EQ(SIGSEGV, last_sig);
85	ATF_CHECK_EQ(SEGV_MAPERR, last_code);
86}
87
88ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_accerr_1);
89ATF_TC_BODY(page_fault_signal__segv_accerr_1, tc)
90{
91	int *p;
92	int sz;
93
94	sz = getpagesize();
95	p = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
96	ATF_REQUIRE(p != MAP_FAILED);
97	if (sigsetjmp(sig_env, 1) == 0) {
98		setup_signals();
99		*(volatile int *)p = 1;
100	}
101	(void)munmap(p, sz);
102	ATF_CHECK_EQ(SIGSEGV, last_sig);
103	ATF_CHECK_EQ(SEGV_ACCERR, last_code);
104}
105
106ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_accerr_2);
107ATF_TC_BODY(page_fault_signal__segv_accerr_2, tc)
108{
109	int *p;
110	volatile int dummy;
111	int sz;
112
113	sz = getpagesize();
114	p = mmap(NULL, sz, PROT_NONE, MAP_ANON, -1, 0);
115	ATF_REQUIRE(p != MAP_FAILED);
116	if (sigsetjmp(sig_env, 1) == 0) {
117		setup_signals();
118		dummy = *p;
119	}
120	(void)munmap(p, sz);
121	ATF_CHECK_EQ(SIGSEGV, last_sig);
122	ATF_CHECK_EQ(SEGV_ACCERR, last_code);
123}
124
125ATF_TC_WITHOUT_HEAD(page_fault_signal__bus_objerr_1);
126ATF_TC_BODY(page_fault_signal__bus_objerr_1, tc)
127{
128	int *p;
129	int fd;
130	int sz;
131
132	sz = getpagesize();
133	fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, 0600);
134	ATF_REQUIRE(fd != -1);
135	p = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
136	ATF_REQUIRE(p != MAP_FAILED);
137	if (sigsetjmp(sig_env, 1) == 0) {
138		setup_signals();
139		*(volatile int *)p = 1;
140	}
141	(void)munmap(p, sz);
142	(void)close(fd);
143	ATF_CHECK_EQ(SIGBUS, last_sig);
144	ATF_CHECK_EQ(BUS_OBJERR, last_code);
145}
146
147ATF_TC_WITHOUT_HEAD(page_fault_signal__bus_objerr_2);
148ATF_TC_BODY(page_fault_signal__bus_objerr_2, tc)
149{
150	int *p;
151	int fd;
152	int r;
153	int sz;
154
155	sz = getpagesize();
156	fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, 0600);
157	ATF_REQUIRE(fd != -1);
158	r = ftruncate(fd, sz);
159	ATF_REQUIRE(r != -1);
160	p = mmap(NULL, sz * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
161	ATF_REQUIRE(p != MAP_FAILED);
162	if (sigsetjmp(sig_env, 1) == 0) {
163		setup_signals();
164		((volatile int *)p)[sz / sizeof(int)] = 1;
165	}
166	(void)munmap(p, sz * 2);
167	(void)close(fd);
168	ATF_CHECK_EQ(SIGBUS, last_sig);
169	ATF_CHECK_EQ(BUS_OBJERR, last_code);
170}
171
172ATF_TP_ADD_TCS(tp)
173{
174
175	ATF_TP_ADD_TC(tp, page_fault_signal__segv_maperr_1);
176	ATF_TP_ADD_TC(tp, page_fault_signal__segv_accerr_1);
177	ATF_TP_ADD_TC(tp, page_fault_signal__segv_accerr_2);
178	ATF_TP_ADD_TC(tp, page_fault_signal__bus_objerr_1);
179	ATF_TP_ADD_TC(tp, page_fault_signal__bus_objerr_2);
180
181	return (atf_no_error());
182}
183