Skip to content

Commit 5e544e5

Browse files
Florian Westphalintel-lab-lkp
Florian Westphal
authored andcommitted
selftests/bpf: add missing netfilter return value and ctx access tests
Extend prog_tests with two test cases: # ./test_progs --allow=verifier_netfilter_retcode torvalds#278/1 verifier_netfilter_retcode/bpf_exit with invalid return code. test1:OK torvalds#278/2 verifier_netfilter_retcode/bpf_exit with valid return code. test2:OK torvalds#278/3 verifier_netfilter_retcode/bpf_exit with valid return code. test3:OK torvalds#278/4 verifier_netfilter_retcode/bpf_exit with invalid return code. test4:OK torvalds#278 verifier_netfilter_retcode:OK This checks that only accept and drop (0,1) are permitted. NF_QUEUE could be implemented later if we can guarantee that attachment of such programs can be rejected if they get attached to a pf/hook that doesn't support async reinjection. NF_STOLEN could be implemented via trusted helpers that can guarantee that the skb will eventually be free'd. v4: test case for bpf_nf_ctx access checks, requested by Alexei Starovoitov. # ./test_progs --allow=verifier_netfilter_ctx torvalds#280/1 verifier_netfilter_ctx/netfilter invalid context access, size too short:OK torvalds#280/2 verifier_netfilter_ctx/netfilter invalid context access, size too short:OK torvalds#280/3 verifier_netfilter_ctx/netfilter invalid context access, past end of ctx:OK torvalds#280/4 verifier_netfilter_ctx/netfilter invalid context, write:OK torvalds#280/5 verifier_netfilter_ctx/netfilter valid context access:OK torvalds#280/6 verifier_netfilter_ctx/netfilter valid context access @unpriv:OK torvalds#280 verifier_netfilter_ctx:OK Summary: 1/6 PASSED, 0 SKIPPED, 0 FAILED This checks: 1/2: partial reads of ctx->{skb,state} are rejected 3. read access past sizeof(ctx) is rejected 4. write to ctx content, e.g. 'ctx->skb = NULL;' is rejected 5. ctx->skb and ctx->state can be read (valid case), but ... 6. ... same program fails for unpriv (CAP_NET_ADMIN needed). Link: https://lore.kernel.org/bpf/20230419021152.sjq4gttphzzy6b5f@dhcp-172-26-102-232.dhcp.thefacebook.com/ Signed-off-by: Florian Westphal <[email protected]>
1 parent 2a70d8b commit 5e544e5

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

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

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "verifier_map_ret_val.skel.h"
3030
#include "verifier_masking.skel.h"
3131
#include "verifier_meta_access.skel.h"
32+
#include "verifier_netfilter_ctx.skel.h"
33+
#include "verifier_netfilter_retcode.skel.h"
3234
#include "verifier_raw_stack.skel.h"
3335
#include "verifier_raw_tp_writable.skel.h"
3436
#include "verifier_reg_equal.skel.h"
@@ -94,6 +96,8 @@ void test_verifier_map_ptr(void) { RUN(verifier_map_ptr); }
9496
void test_verifier_map_ret_val(void) { RUN(verifier_map_ret_val); }
9597
void test_verifier_masking(void) { RUN(verifier_masking); }
9698
void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
99+
void test_verifier_netfilter_ctx(void) { RUN(verifier_netfilter_ctx); }
100+
void test_verifier_netfilter_retcode(void) { RUN(verifier_netfilter_retcode); }
97101
void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); }
98102
void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); }
99103
void test_verifier_reg_equal(void) { RUN(verifier_reg_equal); }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "vmlinux.h"
4+
5+
#include "bpf_misc.h"
6+
7+
#include <bpf/bpf_tracing.h>
8+
#include <bpf/bpf_helpers.h>
9+
10+
SEC("netfilter")
11+
__description("netfilter invalid context access, size too short")
12+
__failure __msg("invalid bpf_context access")
13+
__naked void with_invalid_ctx_access_test1(void)
14+
{
15+
asm volatile (" \
16+
r2 = *(u8*)(r1 + %[__bpf_nf_ctx_state]); \
17+
r0 = 0; \
18+
exit; \
19+
" :
20+
: __imm_const(__bpf_nf_ctx_state, offsetof(struct bpf_nf_ctx, state))
21+
: __clobber_all);
22+
}
23+
24+
SEC("netfilter")
25+
__description("netfilter invalid context access, size too short")
26+
__failure __msg("invalid bpf_context access")
27+
__naked void with_invalid_ctx_access_test2(void)
28+
{
29+
asm volatile (" \
30+
r2 = *(u16*)(r1 + %[__bpf_nf_ctx_skb]); \
31+
r0 = 0; \
32+
exit; \
33+
" :
34+
: __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb))
35+
: __clobber_all);
36+
}
37+
38+
SEC("netfilter")
39+
__description("netfilter invalid context access, past end of ctx")
40+
__failure __msg("invalid bpf_context access")
41+
__naked void with_invalid_ctx_access_test3(void)
42+
{
43+
asm volatile (" \
44+
r2 = *(u64*)(r1 + %[__bpf_nf_ctx_size]); \
45+
r0 = 0; \
46+
exit; \
47+
" :
48+
: __imm_const(__bpf_nf_ctx_size, sizeof(struct bpf_nf_ctx))
49+
: __clobber_all);
50+
}
51+
52+
SEC("netfilter")
53+
__description("netfilter invalid context, write")
54+
__failure __msg("invalid bpf_context access")
55+
__naked void with_invalid_ctx_access_test4(void)
56+
{
57+
asm volatile (" \
58+
r2 = r1; \
59+
*(u64*)(r2 + 0) = r1; \
60+
r0 = 1; \
61+
exit; \
62+
" :
63+
: __imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb))
64+
: __clobber_all);
65+
}
66+
67+
SEC("netfilter")
68+
__description("netfilter valid context access")
69+
__success __failure_unpriv
70+
__retval(1)
71+
__naked void with_invalid_ctx_access_test5(void)
72+
{
73+
asm volatile (" \
74+
r2 = *(u64*)(r1 + %[__bpf_nf_ctx_state]); \
75+
r1 = *(u64*)(r1 + %[__bpf_nf_ctx_skb]); \
76+
r0 = 1; \
77+
exit; \
78+
" :
79+
: __imm_const(__bpf_nf_ctx_state, offsetof(struct bpf_nf_ctx, state)),
80+
__imm_const(__bpf_nf_ctx_skb, offsetof(struct bpf_nf_ctx, skb))
81+
: __clobber_all);
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
#include "bpf_misc.h"
6+
7+
SEC("netfilter")
8+
__description("bpf_exit with invalid return code. test1")
9+
__failure __msg("R0 is not a known value")
10+
__naked void with_invalid_return_code_test1(void)
11+
{
12+
asm volatile (" \
13+
r0 = *(u64*)(r1 + 0); \
14+
exit; \
15+
" ::: __clobber_all);
16+
}
17+
18+
SEC("netfilter")
19+
__description("bpf_exit with valid return code. test2")
20+
__success
21+
__naked void with_valid_return_code_test2(void)
22+
{
23+
asm volatile (" \
24+
r0 = 0; \
25+
exit; \
26+
" ::: __clobber_all);
27+
}
28+
29+
SEC("netfilter")
30+
__description("bpf_exit with valid return code. test3")
31+
__success
32+
__naked void with_valid_return_code_test3(void)
33+
{
34+
asm volatile (" \
35+
r0 = 1; \
36+
exit; \
37+
" ::: __clobber_all);
38+
}
39+
40+
SEC("netfilter")
41+
__description("bpf_exit with invalid return code. test4")
42+
__failure __msg("R0 has value (0x2; 0x0)")
43+
__naked void with_invalid_return_code_test4(void)
44+
{
45+
asm volatile (" \
46+
r0 = 2; \
47+
exit; \
48+
" ::: __clobber_all);
49+
}

0 commit comments

Comments
 (0)