mainline inclusion from mainline-v7.3-rc1 commit 863f3ddd0b8ac65abfb50d3be0869268ac0e277b category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19506 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- In bpf_link_show_fdinfo and bpf_link_get_info_by_fd, link->prog is accessed without holding any locks. If the prog is concurrently replaced via bpf_link_update, the old prog can be freed, leading to a potential UAF issue. Fix this by accessing link->prog under RCU protection to safely fetch the pointer and guarantee its lifetime while reading its fields. Fixes: 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link") Reported-by: Sashiko <sashiko-bot@kernel.org> Signed-off-by: Pu Lehui <pulehui@huawei.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Reviewed-by: Amery Hung <ameryhung@gmail.com> Acked-by: Leon Hwang <leon.hwang@linux.dev> Link: https://lore.kernel.org/bpf/f87b53c0-8f00-45a6-82db-8242fa9b143f@huaweicloud... [0] Link: https://lore.kernel.org/bpf/20260728025457.2814876-1-pulehui@huaweicloud.com Conflicts: kernel/bpf/syscall.c [ctx conflicts] Signed-off-by: Pu Lehui <pulehui@huawei.com> --- kernel/bpf/syscall.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8b54354c0ce0..07a16c9fa23f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2448,24 +2448,35 @@ static const char *bpf_link_type_strs[] = { static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) { const struct bpf_link *link = filp->private_data; - const struct bpf_prog *prog = link->prog; + const struct bpf_prog *prog; enum bpf_link_type type = link->type; char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; + u32 prog_id = 0; - bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); if (type < ARRAY_SIZE(bpf_link_type_strs) && bpf_link_type_strs[type]) { seq_printf(m, "link_type:\t%s\n", bpf_link_type_strs[type]); } else { WARN_ONCE(1, "missing BPF_LINK_TYPE(...) for link type %u\n", type); seq_printf(m, "link_type:\t<%u>\n", type); } - seq_printf(m, - "link_id:\t%u\n" - "prog_tag:\t%s\n" - "prog_id:\t%u\n", - link->id, - prog_tag, - prog->aux->id); + + rcu_read_lock(); + prog = READ_ONCE(link->prog); + if (prog) { + bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); + prog_id = prog->aux->id; + } + rcu_read_unlock(); + + if (prog) { + seq_printf(m, + "link_id:\t%u\n" + "prog_tag:\t%s\n" + "prog_id:\t%u\n", + link->id, + prog_tag, + prog_id); + } if (link->ops->show_fdinfo) link->ops->show_fdinfo(link, m); } @@ -3879,6 +3890,7 @@ static int bpf_link_get_info_by_fd(struct file *file, { struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info); struct bpf_link_info info; + const struct bpf_prog *prog; u32 info_len = attr->info.info_len; int err; @@ -3893,7 +3905,12 @@ static int bpf_link_get_info_by_fd(struct file *file, info.type = link->type; info.id = link->id; - info.prog_id = link->prog->aux->id; + + rcu_read_lock(); + prog = READ_ONCE(link->prog); + if (prog) + info.prog_id = prog->aux->id; + rcu_read_unlock(); if (link->ops->fill_link_info) { err = link->ops->fill_link_info(link, &info); -- 2.34.1