Skip to content

Commit 58f6c3d

Browse files
committed
test/zdtm/static: add madv guards test
Test for madvise(MADV_GUARD_INSTALL). Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
1 parent 616182c commit 58f6c3d

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed

test/zdtm/static/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ TST_NOFILE := \
151151
maps09 \
152152
maps10 \
153153
maps11 \
154+
maps12 \
154155
mlock_setuid \
155156
xids00 \
156157
groups \

test/zdtm/static/maps12.c

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
#include <errno.h>
2+
#include <fcntl.h>
3+
#include <unistd.h>
4+
#include <setjmp.h>
5+
#include <stdlib.h>
6+
#include <signal.h>
7+
#include <sys/mman.h>
8+
#include <sys/types.h>
9+
#include <linux/limits.h>
10+
#include "zdtmtst.h"
11+
12+
const char *test_doc = "Test madvise(MADV_GUARD_INSTALL)";
13+
const char *test_author = "Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>";
14+
/* some parts of code were taken from Linux kernel's kselftest guard-pages.c
15+
written by Lorenzo Stoakes <lorenzo.stoakes@oracle.com> */
16+
17+
#ifndef MADV_GUARD_INSTALL
18+
#define MADV_GUARD_INSTALL 102
19+
#endif
20+
21+
uint8_t *map_base;
22+
23+
struct {
24+
unsigned int pages_num;
25+
} vmas[] = {
26+
{ 2 },
27+
{ 2 },
28+
{ 2 },
29+
{ 2 },
30+
{ 2 },
31+
};
32+
33+
struct {
34+
bool guarded;
35+
} pages[] = {
36+
{ false },
37+
{ true },
38+
{ true },
39+
{ false },
40+
{ false },
41+
{ true },
42+
{ true },
43+
{ false },
44+
{ false },
45+
{ false },
46+
};
47+
48+
static volatile sig_atomic_t signal_jump_set;
49+
static sigjmp_buf signal_jmp_buf;
50+
51+
static void handle_sigsegv(int signo)
52+
{
53+
if (!signal_jump_set)
54+
return;
55+
56+
siglongjmp(signal_jmp_buf, 1);
57+
}
58+
59+
static bool try_write_to_addr(uint8_t *ptr)
60+
{
61+
bool failed;
62+
63+
/* Tell signal handler to jump back here on fatal signal. */
64+
signal_jump_set = true;
65+
/* If a fatal signal arose, we will jump back here and failed is set. */
66+
failed = sigsetjmp(signal_jmp_buf, 1) != 0;
67+
68+
if (!failed)
69+
*ptr = 'x';
70+
71+
signal_jump_set = false;
72+
return !failed;
73+
}
74+
75+
static int setup_sigsegv_handler(void)
76+
{
77+
uint8_t write_me;
78+
79+
if (signal(SIGSEGV, handle_sigsegv) == SIG_ERR) {
80+
pr_perror("setting SIGSEGV handler failed");
81+
return 1;
82+
}
83+
84+
/* ensure that try_write_to_addr() works properly */
85+
if (!try_write_to_addr(&write_me)) {
86+
pr_err("Failed to write at valid addr. Buggy try_write_to_addr()?\n");
87+
return 1;
88+
}
89+
90+
if (try_write_to_addr(NULL)) {
91+
pr_err("Failed to detect an invalid write. Buggy try_write_to_addr()?\n");
92+
return 1;
93+
}
94+
95+
return 0;
96+
}
97+
98+
static inline void *mmap_pages(void *addr_hint, unsigned int count)
99+
{
100+
char *map;
101+
102+
map = mmap(addr_hint, count * PAGE_SIZE, PROT_WRITE | PROT_READ,
103+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
104+
if (map == MAP_FAILED || (addr_hint && (map != addr_hint)))
105+
return MAP_FAILED;
106+
107+
return map;
108+
}
109+
110+
static int check_guards(const char *when)
111+
{
112+
int i;
113+
114+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
115+
if (!pages[i].guarded)
116+
continue;
117+
118+
if (try_write_to_addr(&map_base[i * PAGE_SIZE])) {
119+
pr_err("successful write to a guarded area %d %s C/R\n",
120+
i, when);
121+
return 1;
122+
}
123+
}
124+
125+
return 0;
126+
}
127+
128+
static void gen_pages_data(void)
129+
{
130+
int i;
131+
132+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
133+
uint32_t crc;
134+
135+
if (pages[i].guarded)
136+
continue;
137+
138+
crc = ~0;
139+
datagen(&map_base[i * PAGE_SIZE], PAGE_SIZE, &crc);
140+
}
141+
}
142+
143+
static int check_pages_data(void)
144+
{
145+
int i;
146+
147+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
148+
uint32_t crc;
149+
150+
if (pages[i].guarded)
151+
continue;
152+
153+
crc = ~0;
154+
if (datachk(&map_base[i * PAGE_SIZE], PAGE_SIZE, &crc)) {
155+
pr_err("Page %d is corrupted\n", i);
156+
return 1;
157+
}
158+
}
159+
160+
return 0;
161+
}
162+
163+
static int prepare_vmas(void)
164+
{
165+
char *map;
166+
int i, shift;
167+
168+
shift = 0;
169+
for (i = 0; i < ARRAY_SIZE(vmas); i++) {
170+
map = mmap_pages(&map_base[shift * PAGE_SIZE],
171+
vmas[i].pages_num);
172+
if (map == MAP_FAILED) {
173+
pr_err("mmap of [%d,%d] pages failed\n",
174+
shift, shift + vmas[i].pages_num);
175+
return 1;
176+
}
177+
178+
shift += vmas[i].pages_num;
179+
}
180+
181+
return 0;
182+
}
183+
184+
int main(int argc, char **argv)
185+
{
186+
unsigned int pages_num = ARRAY_SIZE(pages);
187+
188+
test_init(argc, argv);
189+
190+
if (setup_sigsegv_handler()) {
191+
pr_err("setup_sigsegv_handler() failed\n");
192+
return 1;
193+
}
194+
195+
/*
196+
* ToDo:
197+
* - handle VM_WIPEONFORK in CRIU and test it too
198+
* - ...
199+
*/
200+
201+
/* let's find a large enough area in address space */
202+
map_base = mmap_pages(NULL, pages_num);
203+
if (map_base == MAP_FAILED) {
204+
pr_err("mmap of %d pages failed\n", pages_num);
205+
return 1;
206+
}
207+
208+
if (munmap(map_base, pages_num * PAGE_SIZE)) {
209+
pr_perror("munmap failed");
210+
return 1;
211+
}
212+
213+
/*
214+
* Now we know that we have a free vm address space area
215+
* [map_base, map_base + pages_num * PAGE_SIZE).
216+
* We can use (map_base) as a hint for our further mmaps.
217+
*/
218+
if (prepare_vmas()) {
219+
pr_err("prepare_vmas() failed\n");
220+
return 1;
221+
}
222+
223+
/* fill non-guarded pages with data and preserve checksums */
224+
gen_pages_data();
225+
226+
/* guard pages {2,3} */
227+
if (madvise(&map_base[1 * PAGE_SIZE], 2 * PAGE_SIZE,
228+
MADV_GUARD_INSTALL)) {
229+
pr_perror("madvise failed");
230+
return 1;
231+
}
232+
233+
/* guard pages {6,7} */
234+
if (madvise(&map_base[5 * PAGE_SIZE], 2 * PAGE_SIZE,
235+
MADV_GUARD_INSTALL)) {
236+
pr_perror("madvise failed");
237+
return 1;
238+
}
239+
240+
/* ensure that madvise(MADV_GUARD_INSTALL) works like expected */
241+
if (check_guards("before")) {
242+
pr_err("check_guards(\"before\") failed\n");
243+
return 1;
244+
}
245+
246+
test_daemon();
247+
test_waitsig();
248+
249+
/* ensure that guards are at their places */
250+
if (check_guards("after")) {
251+
fail("check_guards(\"after\") failed");
252+
return 1;
253+
}
254+
255+
/* check that non-guarded pages still contain original data */
256+
if (check_pages_data()) {
257+
fail("check_pages_data() failed");
258+
return 1;
259+
}
260+
261+
pass();
262+
munmap(map_base, pages_num * PAGE_SIZE);
263+
return 0;
264+
}

test/zdtm/static/maps12.desc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{'flavor': 'h', 'feature': 'pagemap_scan_guard_pages'}

0 commit comments

Comments
 (0)