Skip to content

Commit cbe41c9

Browse files
etsalKernel Patches Daemon
authored andcommitted
selftests/bpf: add selftests for bpf_arena_guard_pages
Add selftests for the new bpf_arena_guard_pages kfunc. Signed-off-by: Emil Tsalapatis <[email protected]>
1 parent d856d02 commit cbe41c9

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

tools/testing/selftests/bpf/bpf_arena_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@
4646

4747
void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt,
4848
int node_id, __u64 flags) __ksym __weak;
49+
int bpf_arena_guard_pages(void *map, void __arena *addr, __u32 page_cnt) __ksym __weak;
4950
void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak;
5051

52+
#define arena_base(map) ((void __arena *)((struct bpf_arena *)(map))->user_vm_start)
53+
5154
#else /* when compiled as user space code */
5255

5356
#define __arena

tools/testing/selftests/bpf/progs/verifier_arena.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,112 @@ int basic_alloc3(void *ctx)
114114
return 0;
115115
}
116116

117+
SEC("syscall")
118+
__success __retval(0)
119+
int basic_guard1(void *ctx)
120+
{
121+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
122+
char __arena *page;
123+
int ret;
124+
125+
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
126+
if (!page)
127+
return 1;
128+
129+
page += __PAGE_SIZE;
130+
131+
/* Guard the second page */
132+
ret = bpf_arena_guard_pages(&arena, page, 1);
133+
if (ret)
134+
return 2;
135+
136+
/* Try to explicitly allocate the guarded page. */
137+
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
138+
if (page)
139+
return 3;
140+
141+
/* Try to implicitly allocate the page (since there's only 2 of them). */
142+
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
143+
if (page)
144+
return 4;
145+
#endif
146+
return 0;
147+
}
148+
149+
SEC("syscall")
150+
__success __retval(0)
151+
int basic_guard2(void *ctx)
152+
{
153+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
154+
char __arena *page;
155+
int ret;
156+
157+
page = arena_base(&arena);
158+
ret = bpf_arena_guard_pages(&arena, page, 1);
159+
if (ret)
160+
return 1;
161+
162+
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
163+
if ((u64)page)
164+
return 2;
165+
#endif
166+
return 0;
167+
}
168+
169+
/* Guard the same page twice, should return -EALREADY. */
170+
SEC("syscall")
171+
__success __retval(0)
172+
int guard_twice(void *ctx)
173+
{
174+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
175+
char __arena *page;
176+
int ret;
177+
178+
page = arena_base(&arena);
179+
180+
ret = bpf_arena_guard_pages(&arena, page, 1);
181+
if (ret)
182+
return 1;
183+
184+
/* Should be -EALREADY. */
185+
ret = bpf_arena_guard_pages(&arena, page, 1);
186+
if (ret != -114)
187+
return 2;
188+
#endif
189+
return 0;
190+
}
191+
192+
/* Try to add a guard past the end of the arena. */
193+
SEC("syscall")
194+
__success __retval(0)
195+
int guard_invalid_region(void *ctx)
196+
{
197+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
198+
char __arena *page;
199+
int ret;
200+
201+
/* Try a NULL pointer. */
202+
ret = bpf_arena_guard_pages(&arena, NULL, 3);
203+
if (ret != -22)
204+
return 1;
205+
206+
page = arena_base(&arena);
207+
208+
ret = bpf_arena_guard_pages(&arena, page, 3);
209+
if (ret != -22)
210+
return 2;
211+
212+
ret = bpf_arena_guard_pages(&arena, page, 4096);
213+
if (ret != -22)
214+
return 3;
215+
216+
ret = bpf_arena_guard_pages(&arena, page, (1ULL << 32) - 1);
217+
if (ret != -22)
218+
return 4;
219+
#endif
220+
return 0;
221+
}
222+
117223
SEC("iter.s/bpf_map")
118224
__success __log_level(2)
119225
int iter_maps1(struct bpf_iter__bpf_map *ctx)

tools/testing/selftests/bpf/progs/verifier_arena_large.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,99 @@ int big_alloc1(void *ctx)
6767
return 0;
6868
}
6969

70+
/* Try to access a guarded page. Behavior should be identical with accessing unallocated pages. */
71+
SEC("syscall")
72+
__success __retval(0)
73+
int access_guarded(void *ctx)
74+
{
75+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
76+
volatile char __arena *page;
77+
char __arena *base;
78+
const size_t len = 4;
79+
int ret, i;
80+
81+
/* Get a separate region of the arena. */
82+
page = base = arena_base(&arena) + 16384 * PAGE_SIZE;
83+
84+
ret = bpf_arena_guard_pages(&arena, base, len);
85+
if (ret)
86+
return 1;
87+
88+
/* Try to dirty guarded memory. */
89+
for (i = 0; i < len && can_loop; i++)
90+
*page = 0x5a;
91+
92+
for (i = 0; i < len && can_loop; i++) {
93+
page = (volatile char __arena *)(base + i * PAGE_SIZE);
94+
95+
/*
96+
* Error out in case either the write went through,
97+
* or the address has random garbage.
98+
*/
99+
if (*page == 0x5a)
100+
return 2 + 2 * i;
101+
102+
if (*page)
103+
return 2 + 2 * i + 1;
104+
}
105+
#endif
106+
return 0;
107+
}
108+
109+
/* Try to allocate a region overlapping with a guard. */
110+
SEC("syscall")
111+
__success __retval(0)
112+
int request_partially_guarded(void *ctx)
113+
{
114+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
115+
volatile char __arena *page;
116+
char __arena *base;
117+
int ret;
118+
119+
/* Add an arbitrary page offset. */
120+
page = base = arena_base(&arena) + 4096 * __PAGE_SIZE;
121+
122+
ret = bpf_arena_guard_pages(&arena, base + 3 * __PAGE_SIZE, 4);
123+
if (ret)
124+
return 1;
125+
126+
page = bpf_arena_alloc_pages(&arena, base, 5, NUMA_NO_NODE, 0);
127+
if ((u64)page != 0ULL)
128+
return 2;
129+
#endif
130+
return 0;
131+
}
132+
133+
SEC("syscall")
134+
__success __retval(0)
135+
int free_guarded(void *ctx)
136+
{
137+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
138+
char __arena *addr;
139+
char __arena *page;
140+
int ret;
141+
142+
/* Add an arbitrary page offset. */
143+
addr = arena_base(&arena) + 32768 * __PAGE_SIZE;
144+
145+
page = bpf_arena_alloc_pages(&arena, addr, 4, NUMA_NO_NODE, 0);
146+
if (!page)
147+
return 1;
148+
149+
ret = bpf_arena_guard_pages(&arena, addr + 4 * __PAGE_SIZE, 4);
150+
if (ret)
151+
return 2;
152+
153+
bpf_arena_free_pages(&arena, addr + 3 * __PAGE_SIZE, 2);
154+
155+
/* The free pages call above should have failed, so this allocation should fail too. */
156+
page = bpf_arena_alloc_pages(&arena, addr + 3 * __PAGE_SIZE, 1, NUMA_NO_NODE, 0);
157+
if (page)
158+
return 3;
159+
#endif
160+
return 0;
161+
}
162+
70163
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
71164
#define PAGE_CNT 100
72165
__u8 __arena * __arena page[PAGE_CNT]; /* occupies the first page */

0 commit comments

Comments
 (0)