xref: /freebsd/tests/sys/vm/page_fault_signal.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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  
28  #include <sys/mman.h>
29  
30  #include <atf-c.h>
31  #include <fcntl.h>
32  #include <setjmp.h>
33  #include <signal.h>
34  #include <stdio.h>
35  
36  static sigjmp_buf sig_env;
37  static volatile int last_sig, last_code;
38  
39  static void
sighandler(int sig,siginfo_t * info,void * context __unused)40  sighandler(int sig, siginfo_t *info, void *context __unused)
41  {
42  
43  	last_sig = sig;
44  	last_code = info->si_code;
45  	siglongjmp(sig_env, 1);
46  }
47  
48  static void
setup_signals(void)49  setup_signals(void)
50  {
51  	struct sigaction sa;
52  	int r;
53  
54  	sa.sa_sigaction = sighandler;
55  	sa.sa_flags = SA_RESTART | SA_RESETHAND | SA_SIGINFO;
56  	r = sigfillset(&sa.sa_mask);
57  	ATF_REQUIRE(r != -1);
58  	r = sigaction(SIGILL, &sa, NULL);
59  	ATF_REQUIRE(r != -1);
60  	r = sigaction(SIGBUS, &sa, NULL);
61  	ATF_REQUIRE(r != -1);
62  	r = sigaction(SIGSEGV, &sa, NULL);
63  	ATF_REQUIRE(r != -1);
64  }
65  
66  ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_maperr_1);
ATF_TC_BODY(page_fault_signal__segv_maperr_1,tc)67  ATF_TC_BODY(page_fault_signal__segv_maperr_1, tc)
68  {
69  	int *p;
70  	int r;
71  	int sz;
72  
73  	sz = getpagesize();
74  	p = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
75  	ATF_REQUIRE(p != MAP_FAILED);
76  	r = munmap(p, sz);
77  	ATF_REQUIRE(r != -1);
78  	if (sigsetjmp(sig_env, 1) == 0) {
79  		setup_signals();
80  		*(volatile int *)p = 1;
81  	}
82  	ATF_CHECK_EQ(SIGSEGV, last_sig);
83  	ATF_CHECK_EQ(SEGV_MAPERR, last_code);
84  }
85  
86  ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_accerr_1);
ATF_TC_BODY(page_fault_signal__segv_accerr_1,tc)87  ATF_TC_BODY(page_fault_signal__segv_accerr_1, tc)
88  {
89  	int *p;
90  	int sz;
91  
92  	sz = getpagesize();
93  	p = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
94  	ATF_REQUIRE(p != MAP_FAILED);
95  	if (sigsetjmp(sig_env, 1) == 0) {
96  		setup_signals();
97  		*(volatile int *)p = 1;
98  	}
99  	(void)munmap(p, sz);
100  	ATF_CHECK_EQ(SIGSEGV, last_sig);
101  	ATF_CHECK_EQ(SEGV_ACCERR, last_code);
102  }
103  
104  ATF_TC_WITHOUT_HEAD(page_fault_signal__segv_accerr_2);
ATF_TC_BODY(page_fault_signal__segv_accerr_2,tc)105  ATF_TC_BODY(page_fault_signal__segv_accerr_2, tc)
106  {
107  	int *p;
108  	int sz;
109  
110  	sz = getpagesize();
111  	p = mmap(NULL, sz, PROT_NONE, MAP_ANON, -1, 0);
112  	ATF_REQUIRE(p != MAP_FAILED);
113  	if (sigsetjmp(sig_env, 1) == 0) {
114  		setup_signals();
115  		(void)*(volatile int *)p;
116  	}
117  	(void)munmap(p, sz);
118  	ATF_CHECK_EQ(SIGSEGV, last_sig);
119  	ATF_CHECK_EQ(SEGV_ACCERR, last_code);
120  }
121  
122  ATF_TC_WITHOUT_HEAD(page_fault_signal__bus_objerr_1);
ATF_TC_BODY(page_fault_signal__bus_objerr_1,tc)123  ATF_TC_BODY(page_fault_signal__bus_objerr_1, tc)
124  {
125  	int *p;
126  	int fd;
127  	int sz;
128  
129  	sz = getpagesize();
130  	fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, 0600);
131  	ATF_REQUIRE(fd != -1);
132  	p = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
133  	ATF_REQUIRE(p != MAP_FAILED);
134  	if (sigsetjmp(sig_env, 1) == 0) {
135  		setup_signals();
136  		*(volatile int *)p = 1;
137  	}
138  	(void)munmap(p, sz);
139  	(void)close(fd);
140  	ATF_CHECK_EQ(SIGBUS, last_sig);
141  	ATF_CHECK_EQ(BUS_OBJERR, last_code);
142  }
143  
144  ATF_TC_WITHOUT_HEAD(page_fault_signal__bus_objerr_2);
ATF_TC_BODY(page_fault_signal__bus_objerr_2,tc)145  ATF_TC_BODY(page_fault_signal__bus_objerr_2, tc)
146  {
147  	int *p;
148  	int fd;
149  	int r;
150  	int sz;
151  
152  	sz = getpagesize();
153  	fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, 0600);
154  	ATF_REQUIRE(fd != -1);
155  	r = ftruncate(fd, sz);
156  	ATF_REQUIRE(r != -1);
157  	p = mmap(NULL, sz * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
158  	ATF_REQUIRE(p != MAP_FAILED);
159  	if (sigsetjmp(sig_env, 1) == 0) {
160  		setup_signals();
161  		((volatile int *)p)[sz / sizeof(int)] = 1;
162  	}
163  	(void)munmap(p, sz * 2);
164  	(void)close(fd);
165  	ATF_CHECK_EQ(SIGBUS, last_sig);
166  	ATF_CHECK_EQ(BUS_OBJERR, last_code);
167  }
168  
ATF_TP_ADD_TCS(tp)169  ATF_TP_ADD_TCS(tp)
170  {
171  
172  	ATF_TP_ADD_TC(tp, page_fault_signal__segv_maperr_1);
173  	ATF_TP_ADD_TC(tp, page_fault_signal__segv_accerr_1);
174  	ATF_TP_ADD_TC(tp, page_fault_signal__segv_accerr_2);
175  	ATF_TP_ADD_TC(tp, page_fault_signal__bus_objerr_1);
176  	ATF_TP_ADD_TC(tp, page_fault_signal__bus_objerr_2);
177  
178  	return (atf_no_error());
179  }
180