Skip to content

Commit 04a9413

Browse files
Byte-Labanakryiko
authored andcommitted
libbpf: Don't take direct pointers into BTF data from st_ops
In struct bpf_struct_ops, we have take a pointer to a BTF type name, and a struct btf_type. This was presumably done for convenience, but can actually result in subtle and confusing bugs given that BTF data can be invalidated before a program is loaded. For example, in sched_ext, we may sometimes resize a data section after a skeleton has been opened, but before the struct_ops scheduler map has been loaded. This may cause the BTF data to be realloc'd, which can then cause a UAF when loading the program because the struct_ops map has pointers directly into the BTF data. We're already storing the BTF type_id in struct bpf_struct_ops. Because type_id is stable, we can therefore just update the places where we were looking at those pointers to instead do the lookups we need from the type_id. Fixes: 590a008 ("bpf: libbpf: Add STRUCT_OPS support") Signed-off-by: David Vernet <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 8efffab commit 04a9413

File tree

1 file changed

+13
-10
lines changed

1 file changed

+13
-10
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,6 @@ struct bpf_program {
496496
};
497497

498498
struct bpf_struct_ops {
499-
const char *tname;
500-
const struct btf_type *type;
501499
struct bpf_program **progs;
502500
__u32 *kern_func_off;
503501
/* e.g. struct tcp_congestion_ops in bpf_prog's btf format */
@@ -1083,11 +1081,14 @@ static int bpf_object_adjust_struct_ops_autoload(struct bpf_object *obj)
10831081
continue;
10841082

10851083
for (j = 0; j < obj->nr_maps; ++j) {
1084+
const struct btf_type *type;
1085+
10861086
map = &obj->maps[j];
10871087
if (!bpf_map__is_struct_ops(map))
10881088
continue;
10891089

1090-
vlen = btf_vlen(map->st_ops->type);
1090+
type = btf__type_by_id(obj->btf, map->st_ops->type_id);
1091+
vlen = btf_vlen(type);
10911092
for (k = 0; k < vlen; ++k) {
10921093
slot_prog = map->st_ops->progs[k];
10931094
if (prog != slot_prog)
@@ -1121,8 +1122,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
11211122
int err;
11221123

11231124
st_ops = map->st_ops;
1124-
type = st_ops->type;
1125-
tname = st_ops->tname;
1125+
type = btf__type_by_id(btf, st_ops->type_id);
1126+
tname = btf__name_by_offset(btf, type->name_off);
11261127
err = find_struct_ops_kern_types(obj, tname, &mod_btf,
11271128
&kern_type, &kern_type_id,
11281129
&kern_vtype, &kern_vtype_id,
@@ -1423,8 +1424,6 @@ static int init_struct_ops_maps(struct bpf_object *obj, const char *sec_name,
14231424
memcpy(st_ops->data,
14241425
data->d_buf + vsi->offset,
14251426
type->size);
1426-
st_ops->tname = tname;
1427-
st_ops->type = type;
14281427
st_ops->type_id = type_id;
14291428

14301429
pr_debug("struct_ops init: struct %s(type_id=%u) %s found at offset %u\n",
@@ -8445,11 +8444,13 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
84458444

84468445
static void bpf_map_prepare_vdata(const struct bpf_map *map)
84478446
{
8447+
const struct btf_type *type;
84488448
struct bpf_struct_ops *st_ops;
84498449
__u32 i;
84508450

84518451
st_ops = map->st_ops;
8452-
for (i = 0; i < btf_vlen(st_ops->type); i++) {
8452+
type = btf__type_by_id(map->obj->btf, st_ops->type_id);
8453+
for (i = 0; i < btf_vlen(type); i++) {
84538454
struct bpf_program *prog = st_ops->progs[i];
84548455
void *kern_data;
84558456
int prog_fd;
@@ -9712,6 +9713,7 @@ static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj,
97129713
static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
97139714
Elf64_Shdr *shdr, Elf_Data *data)
97149715
{
9716+
const struct btf_type *type;
97159717
const struct btf_member *member;
97169718
struct bpf_struct_ops *st_ops;
97179719
struct bpf_program *prog;
@@ -9771,13 +9773,14 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
97719773
}
97729774
insn_idx = sym->st_value / BPF_INSN_SZ;
97739775

9774-
member = find_member_by_offset(st_ops->type, moff * 8);
9776+
type = btf__type_by_id(btf, st_ops->type_id);
9777+
member = find_member_by_offset(type, moff * 8);
97759778
if (!member) {
97769779
pr_warn("struct_ops reloc %s: cannot find member at moff %u\n",
97779780
map->name, moff);
97789781
return -EINVAL;
97799782
}
9780-
member_idx = member - btf_members(st_ops->type);
9783+
member_idx = member - btf_members(type);
97819784
name = btf__name_by_offset(btf, member->name_off);
97829785

97839786
if (!resolve_func_ptr(btf, member->type, NULL)) {

0 commit comments

Comments
 (0)