Skip to content

Commit b8fd268

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 a1469a8 commit b8fd268

File tree

3 files changed

+248
-0
lines changed

3 files changed

+248
-0
lines changed

test/zdtm/static/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ TST_NOFILE := \
150150
maps05 \
151151
maps09 \
152152
maps10 \
153+
maps11 \
153154
mlock_setuid \
154155
xids00 \
155156
groups \

test/zdtm/static/maps11.c

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
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+
fail("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+
fail("Failed to write at valid addr. Buggy try_write_to_addr()?");
87+
return 1;
88+
}
89+
90+
if (try_write_to_addr(NULL)) {
91+
fail("Failed to detect an invalid write. Buggy try_write_to_addr()?");
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, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
103+
if (map == MAP_FAILED || (addr_hint && (map != addr_hint)))
104+
return MAP_FAILED;
105+
106+
return map;
107+
}
108+
109+
static int check_guards(const char *when)
110+
{
111+
int i;
112+
113+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
114+
if (!pages[i].guarded)
115+
continue;
116+
117+
if (try_write_to_addr(&map_base[i * PAGE_SIZE])) {
118+
fail("successful write to a guarded area %d %s C/R", i, when);
119+
return 1;
120+
}
121+
}
122+
123+
return 0;
124+
}
125+
126+
static void gen_pages_data(void)
127+
{
128+
int i;
129+
130+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
131+
uint32_t crc;
132+
133+
if (pages[i].guarded)
134+
continue;
135+
136+
crc = ~0;
137+
datagen(&map_base[i * PAGE_SIZE], PAGE_SIZE, &crc);
138+
}
139+
}
140+
141+
static int check_pages_data(void)
142+
{
143+
int i;
144+
145+
for (i = 0; i < ARRAY_SIZE(pages); i++) {
146+
uint32_t crc;
147+
148+
if (pages[i].guarded)
149+
continue;
150+
151+
crc = ~0;
152+
if (datachk(&map_base[i * PAGE_SIZE], PAGE_SIZE, &crc)) {
153+
fail("Page %d is corrupted", i);
154+
return 1;
155+
}
156+
}
157+
158+
return 0;
159+
}
160+
161+
static int prepare_vmas(void)
162+
{
163+
char *map;
164+
int i, shift;
165+
166+
shift = 0;
167+
for (i = 0; i < ARRAY_SIZE(vmas); i++) {
168+
map = mmap_pages(&map_base[shift * PAGE_SIZE], vmas[i].pages_num);
169+
if (map == MAP_FAILED) {
170+
fail("mmap of [%d,%d] pages failed", shift, shift + vmas[i].pages_num);
171+
return 1;
172+
}
173+
174+
shift += vmas[i].pages_num;
175+
}
176+
177+
return 0;
178+
}
179+
180+
int main(int argc, char **argv)
181+
{
182+
unsigned int pages_num = ARRAY_SIZE(pages);
183+
184+
test_init(argc, argv);
185+
186+
if (setup_sigsegv_handler())
187+
return 1;
188+
189+
/*
190+
* ToDo:
191+
* - handle VM_WIPEONFORK in CRIU and test it too
192+
* - ...
193+
*/
194+
195+
/* let's find a large enough area in address space */
196+
map_base = mmap_pages(NULL, pages_num);
197+
if (map_base == MAP_FAILED) {
198+
fail("mmap of %d pages failed", pages_num);
199+
return 1;
200+
}
201+
202+
if (munmap(map_base, pages_num * PAGE_SIZE)) {
203+
fail("munmap failed");
204+
return 1;
205+
}
206+
207+
/* Now we know that we have a free vm address space area [map_base, map_base + pages_num * PAGE_SIZE).
208+
* We can use (map_base) as a hint for our further mmaps.
209+
*/
210+
if (prepare_vmas())
211+
return 1;
212+
213+
/* fill non-guarded pages with data and preserve checksums */
214+
gen_pages_data();
215+
216+
/* guard pages {2,3} */
217+
if (madvise(&map_base[1 * PAGE_SIZE], 2 * PAGE_SIZE, MADV_GUARD_INSTALL)) {
218+
pr_perror("madvise failed");
219+
return 1;
220+
}
221+
222+
/* guard pages {6,7} */
223+
if (madvise(&map_base[5 * PAGE_SIZE], 2 * PAGE_SIZE, MADV_GUARD_INSTALL)) {
224+
pr_perror("madvise failed");
225+
return 1;
226+
}
227+
228+
/* ensure that madvise(MADV_GUARD_INSTALL) works like expected */
229+
if (check_guards("before"))
230+
return 1;
231+
232+
test_daemon();
233+
test_waitsig();
234+
235+
/* ensure that guards are at their places */
236+
if (check_guards("after"))
237+
return 1;
238+
239+
/* check that non-guarded pages still contain original data */
240+
if (check_pages_data())
241+
return 1;
242+
243+
pass();
244+
munmap(map_base, pages_num * PAGE_SIZE);
245+
return 0;
246+
}

test/zdtm/static/maps11.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)