Test the correctness of the 32bit narrow reads by reading both halves of the 64 bit field and doing a binary or on them to see if we get the original value. It succeeds as it should, but with the commit e2f7fc0ac695 ("bpf: fix undefined behavior in narrow load handling") reverted, the test fails with a following message: > $ sudo ./test_verifier > ... > #967/p 32bit loads of a 64bit field (both least and most significant words) FAIL retval -1985229329 != 0 > verification time 17 usec > stack depth 0 > processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 > ... > Summary: 1519 PASSED, 0 SKIPPED, 1 FAILED Signed-off-by: Krzesimir Nowak <krzesimir@xxxxxxxxxx> --- tools/testing/selftests/bpf/test_verifier.c | 19 +++++++++++++++++ .../testing/selftests/bpf/verifier/var_off.c | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 484ea8842b06..2a20280a4a44 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -24,6 +24,7 @@ #include <sys/capability.h> +#include <linux/compiler.h> #include <linux/unistd.h> #include <linux/filter.h> #include <linux/bpf_perf_event.h> @@ -343,6 +344,24 @@ static void bpf_fill_perf_event_test_run_check(struct bpf_test *self) self->fill_insns = NULL; } +static void bpf_fill_32bit_loads(struct bpf_test *self) +{ + compiletime_assert( + sizeof(struct bpf_perf_event_data) <= TEST_CTX_LEN, + "buffer for ctx is too short to fit struct bpf_perf_event_data"); + compiletime_assert( + sizeof(struct bpf_perf_event_value) <= TEST_DATA_LEN, + "buffer for data is too short to fit struct bpf_perf_event_value"); + + struct bpf_perf_event_data ctx = { + .sample_period = 0x0123456789abcdef, + }; + + memcpy(self->ctx, &ctx, sizeof(ctx)); + free(self->fill_insns); + self->fill_insns = NULL; +} + /* BPF_SK_LOOKUP contains 13 instructions, if you need to fix up maps */ #define BPF_SK_LOOKUP(func) \ /* struct bpf_sock_tuple tuple = {} */ \ diff --git a/tools/testing/selftests/bpf/verifier/var_off.c b/tools/testing/selftests/bpf/verifier/var_off.c index 8504ac937809..3f8bee0a50ef 100644 --- a/tools/testing/selftests/bpf/verifier/var_off.c +++ b/tools/testing/selftests/bpf/verifier/var_off.c @@ -246,3 +246,24 @@ .result = ACCEPT, .prog_type = BPF_PROG_TYPE_LWT_IN, }, +{ + "32bit loads of a 64bit field (both least and most significant words)", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_perf_event_data, sample_period)), + BPF_LDX_MEM(BPF_W, BPF_REG_5, BPF_REG_1, offsetof(struct bpf_perf_event_data, sample_period) + 4), + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, offsetof(struct bpf_perf_event_data, sample_period)), + BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 32), + BPF_ALU64_REG(BPF_OR, BPF_REG_4, BPF_REG_5), + BPF_ALU64_REG(BPF_XOR, BPF_REG_4, BPF_REG_6), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_4), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_PERF_EVENT, + .ctx = { 0, }, + .ctx_len = sizeof(struct bpf_perf_event_data), + .data = { 0, }, + .data_len = sizeof(struct bpf_perf_event_value), + .fill_helper = bpf_fill_32bit_loads, + .override_data_out_len = true, +}, -- 2.20.1