-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add selftests for load-acquire and store-release instr…
…uctions Add several ./test_progs tests: - arena_atomics/load_acquire - arena_atomics/store_release - verifier_load_acquire/* - verifier_store_release/* - verifier_precision/bpf_load_acquire - verifier_precision/bpf_store_release The last two tests are added to check if backtrack_insn() handles the new instructions correctly. Additionally, the last test also makes sure that the verifier "remembers" the value (in src_reg) we store-release into e.g. a stack slot. For example, if we take a look at the test program: #0: r1 = 8; /* store_release((u64 *)(r10 - 8), r1); */ #1: .8byte %[store_release]; #2: r1 = *(u64 *)(r10 - 8); #3: r2 = r10; #4: r2 += r1; #5: r0 = 0; #6: exit; At #1, if the verifier doesn't remember that we wrote 8 to the stack, then later at #4 we would be adding an unbounded scalar value to the stack pointer, which would cause the program to be rejected: VERIFIER LOG: ============= ... math between fp pointer and register with unbounded min value is not allowed All new tests depend on #ifdef ENABLE_ATOMICS_TESTS. Currently they only run for arm64. Signed-off-by: Peilin Ye <yepeilin@google.com>
- Loading branch information
Showing
6 changed files
with
641 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
tools/testing/selftests/bpf/progs/verifier_load_acquire.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include "../../../include/linux/filter.h" | ||
#include "bpf_misc.h" | ||
|
||
#if defined(ENABLE_ATOMICS_TESTS) && defined(__TARGET_ARCH_arm64) | ||
|
||
SEC("socket") | ||
__description("load-acquire, 8-bit") | ||
__success __success_unpriv __retval(0x12) | ||
__naked void load_acquire_8(void) | ||
{ | ||
asm volatile ( | ||
"*(u8 *)(r10 - 1) = 0x12;" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r10 - 1)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -1)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire, 16-bit") | ||
__success __success_unpriv __retval(0x1234) | ||
__naked void load_acquire_16(void) | ||
{ | ||
asm volatile ( | ||
"*(u16 *)(r10 - 2) = 0x1234;" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u16 *)(r10 - 2)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_H, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -2)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire, 32-bit") | ||
__success __success_unpriv __retval(0x12345678) | ||
__naked void load_acquire_32(void) | ||
{ | ||
asm volatile ( | ||
"*(u32 *)(r10 - 4) = 0x12345678;" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u32 *)(r10 - 4)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -4)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire, 64-bit") | ||
__success __success_unpriv __retval(0x1234567890abcdef) | ||
__naked void load_acquire_64(void) | ||
{ | ||
asm volatile ( | ||
"*(u64 *)(r10 - 8) = 0x1234567890abcdef;" | ||
".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r10 - 8)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -8)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire with uninitialized src_reg") | ||
__failure __failure_unpriv __msg("R2 !read_ok") | ||
__naked void load_acquire_with_uninitialized_src_reg(void) | ||
{ | ||
asm volatile ( | ||
".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r2 + 0)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire with non-pointer src_reg") | ||
__failure __failure_unpriv __msg("R1 invalid mem access 'scalar'") | ||
__naked void load_acquire_with_non_pointer_src_reg(void) | ||
{ | ||
asm volatile ( | ||
"r1 = 0;" | ||
".8byte %[load_acquire_insn];" // r0 = load_acquire((u64 *)(r1 + 0)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_1, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("misaligned load-acquire") | ||
__failure __failure_unpriv __msg("misaligned stack access off") | ||
__flag(BPF_F_ANY_ALIGNMENT) | ||
__naked void load_acquire_misaligned(void) | ||
{ | ||
asm volatile ( | ||
"*(u64 *)(r10 - 8) = 0;" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u32 *)(r10 - 5)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_10, -5)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("socket") | ||
__description("load-acquire from ctx pointer") | ||
__failure __failure_unpriv __msg("BPF_ATOMIC loads from R1 ctx is not allowed") | ||
__naked void load_acquire_from_ctx_pointer(void) | ||
{ | ||
asm volatile ( | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r1 + 0)); | ||
"exit;" | ||
: | ||
: __imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_1, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("xdp") | ||
__description("load-acquire from pkt pointer") | ||
__failure __msg("BPF_ATOMIC loads from R2 pkt is not allowed") | ||
__naked void load_acquire_from_pkt_pointer(void) | ||
{ | ||
asm volatile ( | ||
"r2 = *(u32 *)(r1 + %[xdp_md_data]);" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r2 + 0)); | ||
"exit;" | ||
: | ||
: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), | ||
__imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("flow_dissector") | ||
__description("load-acquire from flow_keys pointer") | ||
__failure __msg("BPF_ATOMIC loads from R2 flow_keys is not allowed") | ||
__naked void load_acquire_from_flow_keys_pointer(void) | ||
{ | ||
asm volatile ( | ||
"r2 = *(u64 *)(r1 + %[__sk_buff_flow_keys]);" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r2 + 0)); | ||
"exit;" | ||
: | ||
: __imm_const(__sk_buff_flow_keys, | ||
offsetof(struct __sk_buff, flow_keys)), | ||
__imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
SEC("sk_reuseport") | ||
__description("load-acquire from sock pointer") | ||
__failure __msg("BPF_ATOMIC loads from R2 sock is not allowed") | ||
__naked void load_acquire_from_sock_pointer(void) | ||
{ | ||
asm volatile ( | ||
"r2 = *(u64 *)(r1 + %[sk_reuseport_md_sk]);" | ||
".8byte %[load_acquire_insn];" // w0 = load_acquire((u8 *)(r2 + 0)); | ||
"exit;" | ||
: | ||
: __imm_const(sk_reuseport_md_sk, offsetof(struct sk_reuseport_md, sk)), | ||
__imm_insn(load_acquire_insn, | ||
BPF_ATOMIC_OP(BPF_B, BPF_LOAD_ACQ, BPF_REG_0, BPF_REG_2, 0)) | ||
: __clobber_all); | ||
} | ||
|
||
#else | ||
|
||
SEC("socket") | ||
__description("load-acquire is not supported by compiler or jit, use a dummy test") | ||
__success | ||
int dummy_test(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
#endif | ||
|
||
char _license[] SEC("license") = "GPL"; |
Oops, something went wrong.