Skip to content

Commit 04de7bc

Browse files
author
Alexei Starovoitov
committed
Merge branch 'more-gen_loader-fixes-2'
Daniel Borkmann says: ==================== More gen_loader fixes #2 Another small follow-up from the sashiko findings about signed loaders. In particular, closing the gap to reject exclusive maps in iterators. ==================== Link: https://patch.msgid.link/20260602133052.423725-1-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2 parents b93c55b + 8dedd34 commit 04de7bc

4 files changed

Lines changed: 80 additions & 5 deletions

File tree

kernel/bpf/map_iter.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
112112
map = bpf_map_get_with_uref(linfo->map.map_fd);
113113
if (IS_ERR(map))
114114
return PTR_ERR(map);
115+
if (map->excl_prog_sha) {
116+
err = -EPERM;
117+
goto put_map;
118+
}
115119

116120
if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
117121
map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||

tools/lib/bpf/gen_loader.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,16 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
160160

161161
static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
162162
{
163-
__u32 size8 = roundup(size, 8);
164163
__u64 zero = 0;
164+
__u32 size8;
165165
void *prev;
166166

167+
if (size > INT32_MAX) {
168+
gen->error = -ERANGE;
169+
return 0;
170+
}
171+
size8 = roundup(size, 8);
172+
167173
if (realloc_data_buf(gen, size8))
168174
return 0;
169175
prev = gen->data_cur;

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <bpf/btf.h>
88

99
#include "map_excl.skel.h"
10+
#include "bpf_iter_bpf_array_map.skel.h"
1011

1112
#ifndef SHA256_DIGEST_SIZE
1213
#define SHA256_DIGEST_SIZE 32
@@ -89,6 +90,42 @@ static void test_map_excl_no_map_in_map(void)
8990
close(excl_fd);
9091
}
9192

93+
static void test_map_excl_no_map_iter(void)
94+
{
95+
__u8 hash[SHA256_DIGEST_SIZE] = {};
96+
LIBBPF_OPTS(bpf_map_create_opts, excl_opts,
97+
.excl_prog_hash = hash,
98+
.excl_prog_hash_size = sizeof(hash));
99+
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
100+
struct bpf_iter_bpf_array_map *skel = NULL;
101+
union bpf_iter_link_info linfo;
102+
struct bpf_link *link;
103+
int excl_fd;
104+
105+
excl_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl_iter", 4, 8, 3, &excl_opts);
106+
if (!ASSERT_OK_FD(excl_fd, "create exclusive map"))
107+
return;
108+
109+
skel = bpf_iter_bpf_array_map__open_and_load();
110+
if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_array_map__open_and_load"))
111+
goto out;
112+
113+
memset(&linfo, 0, sizeof(linfo));
114+
linfo.map.map_fd = excl_fd;
115+
opts.link_info = &linfo;
116+
opts.link_info_len = sizeof(linfo);
117+
118+
link = bpf_program__attach_iter(skel->progs.dump_bpf_array_map, &opts);
119+
if (!ASSERT_ERR_PTR(link, "reject exclusive map as iter target")) {
120+
bpf_link__destroy(link);
121+
goto out;
122+
}
123+
ASSERT_EQ(libbpf_get_error(link), -EPERM, "iter attach errno");
124+
out:
125+
bpf_iter_bpf_array_map__destroy(skel);
126+
close(excl_fd);
127+
}
128+
92129
void test_map_excl(void)
93130
{
94131
if (test__start_subtest("map_excl_allowed"))
@@ -97,4 +134,6 @@ void test_map_excl(void)
97134
test_map_excl_denied();
98135
if (test__start_subtest("map_excl_no_map_in_map"))
99136
test_map_excl_no_map_in_map();
137+
if (test__start_subtest("map_excl_no_map_iter"))
138+
test_map_excl_no_map_iter();
100139
}

tools/testing/selftests/bpf/progs/verifier_map_ptr.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,43 @@ __naked void bpf_map_ptr_write_rejected(void)
7272

7373
/*
7474
* struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable
75-
* byte array), followed by the u32 excl field at offset 32. Reading a u32 at
76-
* offset 33 runs past the end of excl and is rejected.
75+
* byte array), the u32 excl field at offset 32, and the ops pointer at offset
76+
* 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer,
77+
* i.e. a partial pointer access, which is rejected.
7778
*/
7879
SEC("socket")
7980
__description("bpf_map_ptr: read non-existent field rejected")
8081
__failure
81-
__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
82+
__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4")
8283
__failure_unpriv
8384
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
8485
__flag(BPF_F_ANY_ALIGNMENT)
8586
__naked void read_non_existent_field_rejected(void)
87+
{
88+
asm volatile (" \
89+
r6 = 0; \
90+
r1 = %[map_array_48b] ll; \
91+
r6 = *(u32*)(r1 + 41); \
92+
r0 = 1; \
93+
exit; \
94+
" :
95+
: __imm_addr(map_array_48b)
96+
: __clobber_all);
97+
}
98+
99+
/*
100+
* The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset
101+
* 33 starts inside excl but extends past its end, which the verifier rejects
102+
* as an out-of-bounds scalar access.
103+
*/
104+
SEC("socket")
105+
__description("bpf_map_ptr: read beyond excl field rejected")
106+
__failure
107+
__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4")
108+
__failure_unpriv
109+
__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")
110+
__flag(BPF_F_ANY_ALIGNMENT)
111+
__naked void read_beyond_excl_field_rejected(void)
86112
{
87113
asm volatile (" \
88114
r6 = 0; \
@@ -105,7 +131,7 @@ __naked void ptr_read_ops_field_accepted(void)
105131
asm volatile (" \
106132
r6 = 0; \
107133
r1 = %[map_array_48b] ll; \
108-
r6 = *(u64*)(r1 + 0); \
134+
r6 = *(u64*)(r1 + 40); \
109135
r0 = 1; \
110136
exit; \
111137
" :

0 commit comments

Comments
 (0)