Make sure the return of map-of-maps lookup cannot be passed to nullable memory buffer argument for helper and kfunc. - mapofmaps_value_as_kfunc_mem_buf: an un-narrowed (possibly-NULL) map-of-maps value must not be usable as bpf_dynptr_slice()'s __nullable buffer. mark_ptr_not_null_reg() converts such a value to CONST_PTR_TO_MAP; without it check_map_access() would let the program read the inner map descriptor as raw bytes. - mapofmaps_value_as_helper_mem_buf: the same map-of-maps value passed to a nullable helper mem argument (bpf_csum_diff()) must be rejected too, guarding that helper and kfunc arguments are checked the same way. Signed-off-by: Amery Hung --- .../selftests/bpf/prog_tests/verifier.c | 2 + .../bpf/progs/verifier_mem_size_reg.c | 60 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index be97f6887f0e..a81faa709dd5 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -67,6 +67,7 @@ #include "verifier_masking.skel.h" #include "verifier_may_goto_1.skel.h" #include "verifier_may_goto_2.skel.h" +#include "verifier_mem_size_reg.skel.h" #include "verifier_meta_access.skel.h" #include "verifier_movsx.skel.h" #include "verifier_mtu.skel.h" @@ -221,6 +222,7 @@ void test_verifier_map_ret_val(void) { RUN(verifier_map_ret_val); } void test_verifier_masking(void) { RUN(verifier_masking); } void test_verifier_may_goto_1(void) { RUN(verifier_may_goto_1); } void test_verifier_may_goto_2(void) { RUN(verifier_may_goto_2); } +void test_verifier_mem_size_reg(void) { RUN(verifier_mem_size_reg); } void test_verifier_meta_access(void) { RUN(verifier_meta_access); } void test_verifier_movsx(void) { RUN(verifier_movsx); } void test_verifier_mul(void) { RUN(verifier_mul); } diff --git a/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c new file mode 100644 index 000000000000..78a9ad22b10d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_mem_size_reg.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" +#include "bpf_kfuncs.h" + +char _license[] SEC("license") = "GPL"; + +struct inner_map { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} inner_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, 1); + __type(key, int); + __array(values, struct inner_map); +} outer_map SEC(".maps") = { + .values = { [0] = &inner_map }, +}; + +/* An un-narrowed map-of-maps value must be rejected as a __nullable kfunc mem buffer */ +SEC("?tc") +__failure +int mapofmaps_value_as_kfunc_mem_buf(struct __sk_buff *skb) +{ + struct bpf_dynptr dptr; + __u32 key = 0; + void *inner; + char *p; + + inner = bpf_map_lookup_elem(&outer_map, &key); + /* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */ + + bpf_dynptr_from_skb(skb, 0, &dptr); + /* pass the un-narrowed map-of-maps value as the scratch buffer */ + p = bpf_dynptr_slice(&dptr, 0, inner, 8); + if (p) + return p[0]; + return 0; +} + +/* An un-narrowed map-of-maps value must be rejected as a PTR_MAYBE_NULL helper mem buffer */ +SEC("?tc") +__failure +int mapofmaps_value_as_helper_mem_buf(struct __sk_buff *skb) +{ + __u32 key = 0; + void *inner; + + inner = bpf_map_lookup_elem(&outer_map, &key); + /* intentionally NOT NULL-checked: reg stays PTR_TO_MAP_VALUE_OR_NULL */ + + /* @from is a nullable read-only mem+size arg; outer value_size is 4 */ + return bpf_csum_diff(inner, 4, NULL, 0, 0) + skb->len; +} -- 2.52.0