mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
sashiko complained that 38498c0eba ("selftests/bpf: Adjust verifier_map_ptr
for the map's excl field") would slightly decrease the test coverage given
before the test was against the verifier rejecting the ops pointer. Recover
the old test with the right offsets and add the existing one as an additional
test case.
# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr
[ 1.672932] bpf_testmod: module verification failed: signature and/or required key missing - tainting kernel
#637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK
#637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK
#637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK
#637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK
#637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK
#637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK
#637/7 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected:OK
#637/8 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected @unpriv:OK
#637/9 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK
#637/10 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK
#637/11 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r:OK
#637/12 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r @unpriv:OK
#637/13 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr:OK
#637/14 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr @unpriv:OK
#637 verifier_map_ptr:OK
[...]
Summary: 2/20 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260602133052.423725-4-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
191 lines
4.6 KiB
C
191 lines
4.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Converted from tools/testing/selftests/bpf/verifier/map_ptr.c */
|
|
|
|
#include <linux/bpf.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include "bpf_misc.h"
|
|
|
|
#define MAX_ENTRIES 11
|
|
|
|
struct test_val {
|
|
unsigned int index;
|
|
int foo[MAX_ENTRIES];
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
|
__uint(max_entries, 1);
|
|
__type(key, int);
|
|
__type(value, struct test_val);
|
|
} map_array_48b SEC(".maps");
|
|
|
|
struct other_val {
|
|
long long foo;
|
|
long long bar;
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__uint(max_entries, 1);
|
|
__type(key, long long);
|
|
__type(value, struct other_val);
|
|
} map_hash_16b SEC(".maps");
|
|
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: read with negative offset rejected")
|
|
__failure __msg("R1 is bpf_array invalid negative access: off=-8")
|
|
__failure_unpriv
|
|
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
|
|
__naked void read_with_negative_offset_rejected(void)
|
|
{
|
|
asm volatile (" \
|
|
r1 = r10; \
|
|
r1 = %[map_array_48b] ll; \
|
|
r6 = *(u64*)(r1 - 8); \
|
|
r0 = 1; \
|
|
exit; \
|
|
" :
|
|
: __imm_addr(map_array_48b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: write rejected")
|
|
__failure __msg("only read from bpf_array is supported")
|
|
__failure_unpriv
|
|
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
|
|
__naked void bpf_map_ptr_write_rejected(void)
|
|
{
|
|
asm volatile (" \
|
|
r0 = 0; \
|
|
*(u64*)(r10 - 8) = r0; \
|
|
r2 = r10; \
|
|
r2 += -8; \
|
|
r1 = %[map_array_48b] ll; \
|
|
*(u64*)(r1 + 0) = r2; \
|
|
r0 = 1; \
|
|
exit; \
|
|
" :
|
|
: __imm_addr(map_array_48b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
/*
|
|
* struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable
|
|
* byte array), the u32 excl field at offset 32, and the ops pointer at offset
|
|
* 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer,
|
|
* i.e. a partial pointer access, which is rejected.
|
|
*/
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: read non-existent field rejected")
|
|
__failure
|
|
__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4")
|
|
__failure_unpriv
|
|
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
|
|
__flag(BPF_F_ANY_ALIGNMENT)
|
|
__naked void read_non_existent_field_rejected(void)
|
|
{
|
|
asm volatile (" \
|
|
r6 = 0; \
|
|
r1 = %[map_array_48b] ll; \
|
|
r6 = *(u32*)(r1 + 41); \
|
|
r0 = 1; \
|
|
exit; \
|
|
" :
|
|
: __imm_addr(map_array_48b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
/*
|
|
* The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset
|
|
* 33 starts inside excl but extends past its end, which the verifier rejects
|
|
* as an out-of-bounds scalar access.
|
|
*/
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: read beyond excl field rejected")
|
|
__failure
|
|
__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
|
|
__failure_unpriv
|
|
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
|
|
__flag(BPF_F_ANY_ALIGNMENT)
|
|
__naked void read_beyond_excl_field_rejected(void)
|
|
{
|
|
asm volatile (" \
|
|
r6 = 0; \
|
|
r1 = %[map_array_48b] ll; \
|
|
r6 = *(u32*)(r1 + 33); \
|
|
r0 = 1; \
|
|
exit; \
|
|
" :
|
|
: __imm_addr(map_array_48b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: read ops field accepted")
|
|
__success __failure_unpriv
|
|
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
|
|
__retval(1)
|
|
__naked void ptr_read_ops_field_accepted(void)
|
|
{
|
|
asm volatile (" \
|
|
r6 = 0; \
|
|
r1 = %[map_array_48b] ll; \
|
|
r6 = *(u64*)(r1 + 40); \
|
|
r0 = 1; \
|
|
exit; \
|
|
" :
|
|
: __imm_addr(map_array_48b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: r = 0, map_ptr = map_ptr + r")
|
|
__success __failure_unpriv
|
|
__msg_unpriv("R1 has pointer with unsupported alu operation")
|
|
__retval(0)
|
|
__naked void map_ptr_map_ptr_r(void)
|
|
{
|
|
asm volatile (" \
|
|
r0 = 0; \
|
|
*(u64*)(r10 - 8) = r0; \
|
|
r2 = r10; \
|
|
r2 += -8; \
|
|
r0 = 0; \
|
|
r1 = %[map_hash_16b] ll; \
|
|
r1 += r0; \
|
|
call %[bpf_map_lookup_elem]; \
|
|
r0 = 0; \
|
|
exit; \
|
|
" :
|
|
: __imm(bpf_map_lookup_elem),
|
|
__imm_addr(map_hash_16b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
SEC("socket")
|
|
__description("bpf_map_ptr: r = 0, r = r + map_ptr")
|
|
__success __failure_unpriv
|
|
__msg_unpriv("R0 has pointer with unsupported alu operation")
|
|
__retval(0)
|
|
__naked void _0_r_r_map_ptr(void)
|
|
{
|
|
asm volatile (" \
|
|
r0 = 0; \
|
|
*(u64*)(r10 - 8) = r0; \
|
|
r2 = r10; \
|
|
r2 += -8; \
|
|
r1 = 0; \
|
|
r0 = %[map_hash_16b] ll; \
|
|
r1 += r0; \
|
|
call %[bpf_map_lookup_elem]; \
|
|
r0 = 0; \
|
|
exit; \
|
|
" :
|
|
: __imm(bpf_map_lookup_elem),
|
|
__imm_addr(map_hash_16b)
|
|
: __clobber_all);
|
|
}
|
|
|
|
char _license[] SEC("license") = "GPL";
|