Skip to content

Commit 8d534b3

Browse files
committed
selftests/bpf: Factor out arena stream tests to own source
Prior commit [0] added arena tests to the existing streams tests. As kernel arena code is not always compiled (only 64-bit), building streams tests in test_progs fails for 32-bit systems: progs/stream.c:136:21: error: incomplete definition of type 'struct bpf_arena' 136 | user_vm_start = ptr->user_vm_start; | ~~~^ .../include/vmlinux.h:34574:8: note: forward declaration of 'struct bpf_arena' 34574 | struct bpf_arena; | ^ progs/stream.c:170:21: error: incomplete definition of type 'struct bpf_arena' 170 | user_vm_start = ptr->user_vm_start; | ~~~^ .../include/vmlinux.h:34574:8: note: forward declaration of 'struct bpf_arena' 34574 | struct bpf_arena; | ^ 2 errors generated. Previous arena test code was mainly added as separate source files [1], allowing either their temporary removal as a workaround or, ultimately, exclusion via Makefile to build successfully. Follow the prior approach by separating out arena-specific stream test sources. 0: 86f2225 ("selftests/bpf: Add tests for arena fault reporting") 1: arena_spin_lock.c, arena_atomics.c, arena_htab.c, arena_htab_asm.c, arena_list.c, verifier_arena.c, verifier_arena_large.c Signed-off-by: Tony Ambardar <[email protected]>
1 parent 4a5d77f commit 8d534b3

File tree

4 files changed

+206
-189
lines changed

4 files changed

+206
-189
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
#include <test_progs.h>
4+
#include <sys/mman.h>
5+
6+
#include "arena_stream.skel.h"
7+
8+
static void test_address(struct bpf_program *prog, unsigned long *fault_addr_p)
9+
{
10+
LIBBPF_OPTS(bpf_test_run_opts, opts);
11+
LIBBPF_OPTS(bpf_prog_stream_read_opts, ropts);
12+
int ret, prog_fd;
13+
char fault_addr[64];
14+
char buf[1024];
15+
16+
prog_fd = bpf_program__fd(prog);
17+
18+
ret = bpf_prog_test_run_opts(prog_fd, &opts);
19+
ASSERT_OK(ret, "ret");
20+
ASSERT_OK(opts.retval, "retval");
21+
22+
sprintf(fault_addr, "0x%lx", *fault_addr_p);
23+
24+
ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts);
25+
ASSERT_GT(ret, 0, "stream read");
26+
ASSERT_LE(ret, 1023, "len for buf");
27+
buf[ret] = '\0';
28+
29+
if (!ASSERT_HAS_SUBSTR(buf, fault_addr, "fault_addr")) {
30+
fprintf(stderr, "Output from stream:\n%s\n", buf);
31+
fprintf(stderr, "Fault Addr: %s\n", fault_addr);
32+
}
33+
}
34+
35+
void test_stream_arena_fault_address(void)
36+
{
37+
struct arena_stream *skel;
38+
39+
#if !defined(__x86_64__) && !defined(__aarch64__)
40+
printf("%s:SKIP: arena fault reporting not supported\n", __func__);
41+
test__skip();
42+
return;
43+
#endif
44+
45+
skel = arena_stream__open_and_load();
46+
if (!ASSERT_OK_PTR(skel, "arena_stream__open_and_load"))
47+
return;
48+
49+
if (test__start_subtest("read_fault"))
50+
test_address(skel->progs.stream_arena_read_fault, &skel->bss->fault_addr);
51+
if (test__start_subtest("write_fault"))
52+
test_address(skel->progs.stream_arena_write_fault, &skel->bss->fault_addr);
53+
54+
arena_stream__destroy(skel);
55+
}

tools/testing/selftests/bpf/prog_tests/stream.c

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -58,51 +58,3 @@ void test_stream_syscall(void)
5858
stream__destroy(skel);
5959
}
6060

61-
static void test_address(struct bpf_program *prog, unsigned long *fault_addr_p)
62-
{
63-
LIBBPF_OPTS(bpf_test_run_opts, opts);
64-
LIBBPF_OPTS(bpf_prog_stream_read_opts, ropts);
65-
int ret, prog_fd;
66-
char fault_addr[64];
67-
char buf[1024];
68-
69-
prog_fd = bpf_program__fd(prog);
70-
71-
ret = bpf_prog_test_run_opts(prog_fd, &opts);
72-
ASSERT_OK(ret, "ret");
73-
ASSERT_OK(opts.retval, "retval");
74-
75-
sprintf(fault_addr, "0x%lx", *fault_addr_p);
76-
77-
ret = bpf_prog_stream_read(prog_fd, BPF_STREAM_STDERR, buf, sizeof(buf), &ropts);
78-
ASSERT_GT(ret, 0, "stream read");
79-
ASSERT_LE(ret, 1023, "len for buf");
80-
buf[ret] = '\0';
81-
82-
if (!ASSERT_HAS_SUBSTR(buf, fault_addr, "fault_addr")) {
83-
fprintf(stderr, "Output from stream:\n%s\n", buf);
84-
fprintf(stderr, "Fault Addr: %s\n", fault_addr);
85-
}
86-
}
87-
88-
void test_stream_arena_fault_address(void)
89-
{
90-
struct stream *skel;
91-
92-
#if !defined(__x86_64__) && !defined(__aarch64__)
93-
printf("%s:SKIP: arena fault reporting not supported\n", __func__);
94-
test__skip();
95-
return;
96-
#endif
97-
98-
skel = stream__open_and_load();
99-
if (!ASSERT_OK_PTR(skel, "stream__open_and_load"))
100-
return;
101-
102-
if (test__start_subtest("read_fault"))
103-
test_address(skel->progs.stream_arena_read_fault, &skel->bss->fault_addr);
104-
if (test__start_subtest("write_fault"))
105-
test_address(skel->progs.stream_arena_write_fault, &skel->bss->fault_addr);
106-
107-
stream__destroy(skel);
108-
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_tracing.h>
5+
#include <bpf/bpf_helpers.h>
6+
#include "bpf_misc.h"
7+
#include "bpf_experimental.h"
8+
#include "bpf_arena_common.h"
9+
10+
struct {
11+
__uint(type, BPF_MAP_TYPE_ARENA);
12+
__uint(map_flags, BPF_F_MMAPABLE);
13+
__uint(max_entries, 1); /* number of pages */
14+
} arena SEC(".maps");
15+
16+
struct elem {
17+
struct bpf_timer timer;
18+
};
19+
20+
struct {
21+
__uint(type, BPF_MAP_TYPE_ARRAY);
22+
__uint(max_entries, 1);
23+
__type(key, int);
24+
__type(value, struct elem);
25+
} array SEC(".maps");
26+
27+
u64 fault_addr;
28+
void *arena_ptr;
29+
30+
SEC("syscall")
31+
__arch_x86_64
32+
__arch_arm64
33+
__success __retval(0)
34+
__stderr("ERROR: Arena WRITE access at unmapped address 0x{{.*}}")
35+
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
36+
__stderr("Call trace:\n"
37+
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
38+
"|[ \t]+[^\n]+\n)*}}")
39+
int stream_arena_write_fault(void *ctx)
40+
{
41+
struct bpf_arena *ptr = (void *)&arena;
42+
u64 user_vm_start;
43+
44+
/* Prevent GCC bounds warning: casting &arena to struct bpf_arena *
45+
* triggers bounds checking since the map definition is smaller than struct
46+
* bpf_arena. barrier_var() makes the pointer opaque to GCC, preventing the
47+
* bounds analysis
48+
*/
49+
barrier_var(ptr);
50+
user_vm_start = ptr->user_vm_start;
51+
fault_addr = user_vm_start + 0x7fff;
52+
bpf_addr_space_cast(user_vm_start, 0, 1);
53+
asm volatile (
54+
"r1 = %0;"
55+
"r2 = 1;"
56+
"*(u32 *)(r1 + 0x7fff) = r2;"
57+
:
58+
: "r" (user_vm_start)
59+
: "r1", "r2"
60+
);
61+
return 0;
62+
}
63+
64+
SEC("syscall")
65+
__arch_x86_64
66+
__arch_arm64
67+
__success __retval(0)
68+
__stderr("ERROR: Arena READ access at unmapped address 0x{{.*}}")
69+
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
70+
__stderr("Call trace:\n"
71+
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
72+
"|[ \t]+[^\n]+\n)*}}")
73+
int stream_arena_read_fault(void *ctx)
74+
{
75+
struct bpf_arena *ptr = (void *)&arena;
76+
u64 user_vm_start;
77+
78+
/* Prevent GCC bounds warning: casting &arena to struct bpf_arena *
79+
* triggers bounds checking since the map definition is smaller than struct
80+
* bpf_arena. barrier_var() makes the pointer opaque to GCC, preventing the
81+
* bounds analysis
82+
*/
83+
barrier_var(ptr);
84+
user_vm_start = ptr->user_vm_start;
85+
fault_addr = user_vm_start + 0x7fff;
86+
bpf_addr_space_cast(user_vm_start, 0, 1);
87+
asm volatile (
88+
"r1 = %0;"
89+
"r1 = *(u32 *)(r1 + 0x7fff);"
90+
:
91+
: "r" (user_vm_start)
92+
: "r1"
93+
);
94+
return 0;
95+
}
96+
97+
static __noinline void subprog(void)
98+
{
99+
int __arena *addr = (int __arena *)0xdeadbeef;
100+
101+
arena_ptr = &arena;
102+
*addr = 1;
103+
}
104+
105+
SEC("syscall")
106+
__arch_x86_64
107+
__arch_arm64
108+
__success __retval(0)
109+
__stderr("ERROR: Arena WRITE access at unmapped address 0x{{.*}}")
110+
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
111+
__stderr("Call trace:\n"
112+
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
113+
"|[ \t]+[^\n]+\n)*}}")
114+
int stream_arena_subprog_fault(void *ctx)
115+
{
116+
subprog();
117+
return 0;
118+
}
119+
120+
static __noinline int timer_cb(void *map, int *key, struct bpf_timer *timer)
121+
{
122+
int __arena *addr = (int __arena *)0xdeadbeef;
123+
124+
arena_ptr = &arena;
125+
*addr = 1;
126+
return 0;
127+
}
128+
129+
SEC("syscall")
130+
__arch_x86_64
131+
__arch_arm64
132+
__success __retval(0)
133+
__stderr("ERROR: Arena WRITE access at unmapped address 0x{{.*}}")
134+
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
135+
__stderr("Call trace:\n"
136+
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
137+
"|[ \t]+[^\n]+\n)*}}")
138+
int stream_arena_callback_fault(void *ctx)
139+
{
140+
struct bpf_timer *arr_timer;
141+
142+
arr_timer = bpf_map_lookup_elem(&array, &(int){0});
143+
if (!arr_timer)
144+
return 0;
145+
bpf_timer_init(arr_timer, &array, 1);
146+
bpf_timer_set_callback(arr_timer, timer_cb);
147+
bpf_timer_start(arr_timer, 0, 0);
148+
return 0;
149+
}
150+
151+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)