
From: Daniel Borkmann <daniel@iogearbox.net> mainline inclusion from mainline-v6.17-rc1 commit fd1c98f0ef5cbcec842209776505d9e70d8fcd53 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/ICTB0G CVE: CVE-2025-38502 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Given this is only relevant for BPF tail call maps, it is adding up space and penalizing other map types. We also need to extend this with further objects to track / compare to. Therefore, lets move this out into a separate structure and dynamically allocate it only for BPF tail call maps. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/r/20250730234733.530041-2-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org> Conflicts: include/linux/bpf.h kernel/bpf/core.c kernel/bpf/syscall.c [The conflicts were due to some minor issue.] Signed-off-by: Xiaomeng Zhang <zhangxiaomeng13@huawei.com> --- include/linux/bpf.h | 35 ++++++++++++++++++++++++----------- kernel/bpf/core.c | 32 ++++++++++++++++---------------- kernel/bpf/syscall.c | 13 +++++++------ 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 0dbeba91e6fc..19bedc5b9e5a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -21,6 +21,7 @@ #include <linux/kallsyms.h> #include <linux/capability.h> #include <linux/percpu-refcount.h> +#include <linux/slab.h> struct bpf_verifier_env; struct bpf_verifier_log; @@ -144,6 +145,17 @@ struct bpf_map_memory { struct user_struct *user; }; +/* 'Ownership' of prog array is claimed by the first program that + * is going to use this map or by the first program which FD is + * stored in the map to make sure that all callers and callees have + * the same prog type and JITed flag. + */ +struct bpf_map_owner { + enum bpf_prog_type type; + bool jited; + const struct btf_type *attach_func_proto; +}; + struct bpf_map { /* The first two cachelines with read-mostly members of which some * are also accessed in fast-path (e.g. ops, max_entries). @@ -186,17 +198,8 @@ struct bpf_map { }) struct mutex freeze_mutex; atomic64_t writecnt; - /* 'Ownership' of prog array is claimed by the first program that - * is going to use this map or by the first program which FD is - * stored in the map to make sure that all callers and callees have - * the same prog type and JITed flag. - */ - struct { - const struct btf_type *attach_func_proto; - spinlock_t lock; - enum bpf_prog_type type; - bool jited; - } owner; + spinlock_t owner_lock; + struct bpf_map_owner *owner; u64 cookie; /* write-once */ }; @@ -1119,6 +1122,16 @@ static inline bool bpf_map_flags_access_ok(u32 access_flags) (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG); } +static inline struct bpf_map_owner *bpf_map_owner_alloc(struct bpf_map *map) +{ + return kzalloc(sizeof(*map->owner), GFP_ATOMIC); +} + +static inline void bpf_map_owner_free(struct bpf_map *map) +{ + kfree(map->owner); +} + struct bpf_event_entry { struct perf_event *event; struct file *perf_file; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 78f45f993d93..2b0e4af37052 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1778,25 +1778,24 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx, bool bpf_prog_map_compatible(struct bpf_map *map, const struct bpf_prog *fp) { - bool ret; struct bpf_prog_aux *aux = fp->aux; - - if (fp->kprobe_override) - return false; - spin_lock(&map->owner.lock); - if (!map->owner.type) { - /* There's no owner yet where we could check for - * compatibility. - */ - map->owner.type = fp->type; - map->owner.jited = fp->jited; - map->owner.attach_func_proto = aux->attach_func_proto; + bool ret = false; + + spin_lock(&map->owner_lock); + /* There's no owner yet where we could check for compatibility. */ + if (!map->owner) { + map->owner = bpf_map_owner_alloc(map); + if (!map->owner) + goto err; + map->owner->type = fp->type; + map->owner->jited = fp->jited; + map->owner->attach_func_proto = aux->attach_func_proto; ret = true; } else { - ret = map->owner.type == fp->type && - map->owner.jited == fp->jited; + ret = map->owner->type == fp->type && + map->owner->jited == fp->jited; if (ret && - map->owner.attach_func_proto != aux->attach_func_proto) { + map->owner->attach_func_proto != aux->attach_func_proto) { switch (fp->type) { case BPF_PROG_TYPE_TRACING: case BPF_PROG_TYPE_LSM: @@ -1809,7 +1808,8 @@ bool bpf_prog_map_compatible(struct bpf_map *map, } } } - spin_unlock(&map->owner.lock); +err: + spin_unlock(&map->owner_lock); return ret; } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 666d6c7077b6..1c5a058fe9d6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -483,6 +483,7 @@ static void bpf_map_free_deferred(struct work_struct *work) bpf_map_charge_move(&mem, &map->memory); security_bpf_map_free(map); + bpf_map_owner_free(map); /* implementation dependent freeing */ map->ops->map_free(map); bpf_map_charge_finish(&mem); @@ -570,12 +571,12 @@ static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) struct bpf_map *map = filp->private_data; u32 type = 0, jited = 0; - if (map_type_contains_progs(map)) { - spin_lock(&map->owner.lock); - type = map->owner.type; - jited = map->owner.jited; - spin_unlock(&map->owner.lock); + spin_lock(&map->owner_lock); + if (map->owner) { + type = map->owner->type; + jited = map->owner->jited; } + spin_unlock(&map->owner_lock); seq_printf(m, "map_type:\t%u\n" @@ -870,7 +871,7 @@ static int map_create(union bpf_attr *attr) atomic64_set(&map->refcnt, 1); atomic64_set(&map->usercnt, 1); mutex_init(&map->freeze_mutex); - spin_lock_init(&map->owner.lock); + spin_lock_init(&map->owner_lock); map->spin_lock_off = -EINVAL; if (attr->btf_key_type_id || attr->btf_value_type_id || -- 2.34.1