Re: [PATCH bpf v6 3/4] bpf: Fix potential UAF when reading bpf link info
From: Pu Lehui
Date: Mon Jul 27 2026 - 21:51:34 EST
On 2026/7/28 7:15, Andrii Nakryiko wrote:
On Wed, Jul 22, 2026 at 12:19 AM Pu Lehui <pulehui@xxxxxxxxxxxxxxx> wrote:
From: Pu Lehui <pulehui@xxxxxxxxxx>
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.
Before dereferencing the prog, both normal RCU and RCU Tasks Trace read
no, either one is enough (and that's why we wait for RCU and RCU Tasks
Trace grace periods, to make sure that both kinds of accesses work).
This paragraph is misleading, just drop it.
ok
locks would normally be required, as BPF_LINK_TYPE_ITER supports both
non-sleepable and sleepable progs. However, as commit 57b23c0f612d
("bpf: Retire rcu_trace_implies_rcu_gp()") clarifies, an RCU Tasks Trace
grace period implies an RCU grace period, so holding only
rcu_read_lock() is already sufficient.
Fixes: 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Reviewed-by: Emil Tsalapatis <emil@xxxxxxxxxxxxxxx>
Reviewed-by: Amery Hung <ameryhung@xxxxxxxxx>
Signed-off-by: Pu Lehui <pulehui@xxxxxxxxxx>
---
kernel/bpf/syscall.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6db306d23b47..cad986807d53 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3471,9 +3471,10 @@ 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;
can be read uninitialized (if link->prog is null), initialize to zero
will send new
pw-bot: cr
if (type < ARRAY_SIZE(bpf_link_type_strs) && bpf_link_type_strs[type]) {
if (link->type == BPF_LINK_TYPE_KPROBE_MULTI)
@@ -3490,13 +3491,20 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
}
seq_printf(m, "link_id:\t%u\n", link->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,
"prog_tag:\t%s\n"
"prog_id:\t%u\n",
prog_tag,
- prog->aux->id);
+ prog_id);
}
if (link->ops->show_fdinfo)
link->ops->show_fdinfo(link, m);
@@ -5535,6 +5543,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;
@@ -5549,8 +5558,12 @@ static int bpf_link_get_info_by_fd(struct file *file,
info.type = link->type;
info.id = link->id;
- if (link->prog)
- 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