* [PATCH bpf v3 0/3] Fixes for bpf link update
@ 2026-07-20 3:30 Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 3:30 UTC (permalink / raw)
To: bpf, linux-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Yonghong Song, Song Liu, Jiri Olsa, Emil Tsalapatis, Pu Lehui,
Pu Lehui
From: Pu Lehui <pulehui@huawei.com>
patch 1: fix for UAF issue when reading bpf link info.
patch 2: fix for storage not restored when update_effective_progs failed.
patch 3: Fix storage null-ptr-deref after replacing prog in cgrp_bpf.
v3:
- Add new fix for UAF issue when reading bpf link info. (Sashiko)
- Add new fix for storage not restored when update_effective_progs
failed. (Sashiko)
v2:
https://lore.kernel.org/bpf/20260717073343.958862-1-pulehui@huaweicloud.com
- Fix invalid access for in-place update when storage changed. (Sashiko)
v1:
https://lore.kernel.org/bpf/20260714014659.401063-1-pulehui@huaweicloud.com
Pu Lehui (3):
bpf: Fix potential UAF when reading bpf link info
bpf, cgroup: Fix storage not restored when update_effective_progs
failed
bpf, cgroup: Fix storage null-ptr-deref after replacing prog
kernel/bpf/cgroup.c | 40 +++++++++++++++++++++++++++++++++++++++-
kernel/bpf/syscall.c | 27 +++++++++++++++++++++++----
2 files changed, 62 insertions(+), 5 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info
2026-07-20 3:30 [PATCH bpf v3 0/3] Fixes for bpf link update Pu Lehui
@ 2026-07-20 3:30 ` Pu Lehui
2026-07-20 3:50 ` sashiko-bot
2026-07-20 4:04 ` bot+bpf-ci
2026-07-20 3:30 ` [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 3/3] bpf, cgroup: Fix storage null-ptr-deref after replacing prog Pu Lehui
2 siblings, 2 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 3:30 UTC (permalink / raw)
To: bpf, linux-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Yonghong Song, Song Liu, Jiri Olsa, Emil Tsalapatis, Pu Lehui,
Pu Lehui
From: Pu Lehui <pulehui@huawei.com>
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 holding both normal RCU and tasks trace RCU read locks
before dereferencing the prog, as BPF_LINK_TYPE_ITER support both
non-sleepable and sleepable progs.
Fixes: f9d041271cf4 ("bpf: Refactor bpf_link update handling")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Pu Lehui <pulehui@huawei.com>
---
kernel/bpf/syscall.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6db306d23b47..2458c68146b9 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;
if (type < ARRAY_SIZE(bpf_link_type_strs) && bpf_link_type_strs[type]) {
if (link->type == BPF_LINK_TYPE_KPROBE_MULTI)
@@ -3490,13 +3491,23 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
}
seq_printf(m, "link_id:\t%u\n", link->id);
+ /* prog can be sleepable */
+ rcu_read_lock_trace();
+ 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();
+ rcu_read_unlock_trace();
+
+ 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 +5546,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 +5561,15 @@ 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;
+
+ /* prog can be sleepable */
+ rcu_read_lock_trace();
+ rcu_read_lock();
+ prog = READ_ONCE(link->prog);
+ if (prog)
+ info.prog_id = prog->aux->id;
+ rcu_read_unlock();
+ rcu_read_unlock_trace();
if (link->ops->fill_link_info) {
err = link->ops->fill_link_info(link, &info);
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed
2026-07-20 3:30 [PATCH bpf v3 0/3] Fixes for bpf link update Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
@ 2026-07-20 3:30 ` Pu Lehui
2026-07-20 3:41 ` sashiko-bot
2026-07-20 3:30 ` [PATCH bpf v3 3/3] bpf, cgroup: Fix storage null-ptr-deref after replacing prog Pu Lehui
2 siblings, 1 reply; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 3:30 UTC (permalink / raw)
To: bpf, linux-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Yonghong Song, Song Liu, Jiri Olsa, Emil Tsalapatis, Pu Lehui,
Pu Lehui
From: Pu Lehui <pulehui@huawei.com>
In __cgroup_bpf_attach(), if update_effective_progs() fails, pl->storage
is not restored to old_storage. Since new_storage is subsequently freed,
pl->storage is left pointing to freed memory, leading to a potential UAF
issue.
Fix this by saving the old_storage before assigning the new one, and
restoring it in the error path.
Fixes: 7d9c3427894f ("bpf: Make cgroup storages shared between programs on the same cgroup")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Pu Lehui <pulehui@huawei.com>
---
kernel/bpf/cgroup.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 4355ccb78a9c..70757ae45934 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -813,6 +813,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
struct bpf_prog *old_prog = NULL;
struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
struct bpf_cgroup_storage *new_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
+ struct bpf_cgroup_storage *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
struct bpf_prog *new_prog = prog ? : link->link.prog;
enum cgroup_bpf_attach_type atype;
struct bpf_prog_list *pl;
@@ -883,6 +884,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
pl->prog = prog;
pl->link = link;
pl->flags = flags;
+ bpf_cgroup_storages_assign(old_storage, pl->storage);
bpf_cgroup_storages_assign(pl->storage, storage);
cgrp->bpf.flags[atype] = saved_flags;
@@ -916,6 +918,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
pl->prog = old_prog;
pl->link = NULL;
}
+ bpf_cgroup_storages_assign(pl->storage, old_storage);
bpf_cgroup_storages_free(new_storage);
if (!old_prog) {
hlist_del(&pl->node);
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH bpf v3 3/3] bpf, cgroup: Fix storage null-ptr-deref after replacing prog
2026-07-20 3:30 [PATCH bpf v3 0/3] Fixes for bpf link update Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed Pu Lehui
@ 2026-07-20 3:30 ` Pu Lehui
2 siblings, 0 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 3:30 UTC (permalink / raw)
To: bpf, linux-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Yonghong Song, Song Liu, Jiri Olsa, Emil Tsalapatis, Pu Lehui,
Pu Lehui
From: Pu Lehui <pulehui@huawei.com>
Syzkaller reported a storage null-ptr-deref issue after replacing prog.
This occurs in the following scenario:
1. prog A, an empty prog, is attached to a cgrp.
2. prog B uses BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE and calls the
bpf_get_local_storage helper.
3. link_update is called to replace prog A with prog B.
The reason is that __cgroup_bpf_replace fails to alloc and assign the
required cgrp storage for the incoming replacement prog. Consequently,
the new prog inherits an uninit storage, leading to null-ptr-deref panic
when kick the new prog.
Fix this by properly allocating the storage and comparing the old and
new storage pointers. If the storage changed, fallback to
update_effective_progs which performs a RCU-safe update of the entire
array. If the storage remains unchanged, we can safely retain the
fast-path in-place update.
Fixes: 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
Signed-off-by: Pu Lehui <pulehui@huawei.com>
---
kernel/bpf/cgroup.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 70757ae45934..dad2d6a1d96d 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -1035,11 +1035,17 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,
struct bpf_cgroup_link *link,
struct bpf_prog *new_prog)
{
+ struct bpf_cgroup_storage *new_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
+ struct bpf_cgroup_storage *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
+ struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
+ enum bpf_cgroup_storage_type stype;
enum cgroup_bpf_attach_type atype;
+ bool storage_changed = false;
struct bpf_prog *old_prog;
struct bpf_prog_list *pl;
struct hlist_head *progs;
bool found = false;
+ int err;
atype = bpf_cgroup_atype_find(link->link.attach_type, new_prog->aux->attach_btf_id);
if (atype < 0)
@@ -1059,10 +1065,39 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,
if (!found)
return -ENOENT;
+ if (bpf_cgroup_storages_alloc(storage, new_storage, link->link.attach_type,
+ new_prog, cgrp))
+ return -ENOMEM;
+
+ for_each_cgroup_storage_type(stype) {
+ if (storage[stype] != pl->storage[stype]) {
+ storage_changed = true;
+ break;
+ }
+ }
+
cgrp->bpf.revisions[atype] += 1;
old_prog = xchg(&link->link.prog, new_prog);
- replace_effective_prog(cgrp, atype, pl);
+
+ if (!storage_changed) {
+ replace_effective_prog(cgrp, atype, pl);
+ bpf_prog_put(old_prog);
+ return 0;
+ }
+
+ bpf_cgroup_storages_assign(old_storage, pl->storage);
+ bpf_cgroup_storages_assign(pl->storage, storage);
+ err = update_effective_progs(cgrp, atype);
+ if (err) {
+ xchg(&link->link.prog, old_prog);
+ bpf_cgroup_storages_assign(pl->storage, old_storage);
+ bpf_cgroup_storages_free(new_storage);
+ cgrp->bpf.revisions[atype] -= 1;
+ return err;
+ }
+
bpf_prog_put(old_prog);
+ bpf_cgroup_storages_link(new_storage, cgrp, link->link.attach_type);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed
2026-07-20 3:30 ` [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed Pu Lehui
@ 2026-07-20 3:41 ` sashiko-bot
2026-07-20 12:06 ` Pu Lehui
0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-07-20 3:41 UTC (permalink / raw)
To: Pu Lehui; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] Uninitialized memory is read when saving `pl->storage` into `old_storage` for newly allocated `bpf_prog_list` entries.
Pre-existing issues:
- [High] If the first program attach to a cgroup fails, `cgrp->bpf.flags[atype]` is not rolled back, leading to a complete bypass of ancestor mandatory security policies.
--
--- Patch [2]: [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed ---
commit 30470afb00630f3ed1a914958997d62e12b1f60a
Author: Pu Lehui <pulehui@huawei.com>
bpf, cgroup: Fix storage not restored when update_effective_progs failed
In __cgroup_bpf_attach(), if update_effective_progs() fails, pl->storage
is not restored to old_storage. This patch saves the old_storage before
assigning the new one, and restores it in the error path.
> diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
> --- a/kernel/bpf/cgroup.c
> +++ b/kernel/bpf/cgroup.c
[ ... ]
> @@ -883,6 +884,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
> pl->prog = prog;
> pl->link = link;
> pl->flags = flags;
> + bpf_cgroup_storages_assign(old_storage, pl->storage);
[Severity: Medium]
When __cgroup_bpf_attach() allocates a new bpf_prog_list entry, it does so
without zeroing the memory:
pl = kmalloc_obj(*pl);
Because pl is not zero-initialized, does calling bpf_cgroup_storages_assign()
here result in reading uninitialized garbage pointers from pl->storage and
copying them into old_storage? This could trigger KMSAN uninit-value warnings
when attaching a new program.
> bpf_cgroup_storages_assign(pl->storage, storage);
> cgrp->bpf.flags[atype] = saved_flags;
>
[ ... ]
> @@ -916,6 +918,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
> pl->prog = old_prog;
> pl->link = NULL;
> }
> + bpf_cgroup_storages_assign(pl->storage, old_storage);
> bpf_cgroup_storages_free(new_storage);
> if (!old_prog) {
> hlist_del(&pl->node);
> kfree(pl);
> }
> return err;
> }
[Severity: High]
This isn't a bug introduced by this patch, but looking at the error path, if
the very first program attach to a cgroup fails (for example, if
update_effective_progs() fails), the newly added list entry is deleted and
freed here, making the list empty again.
However, the flags set earlier in the function are not rolled back:
cgrp->bpf.flags[atype] = saved_flags;
Could an attacker attempt an attach with BPF_F_ALLOW_MULTI, intentionally
force an error (like hitting memory limits in update_effective_progs()), and
leave the compromised cgroup with permanently altered BPF flags?
If the flags stay stuck, does this allow bypassing mandatory, non-overridable
programs from ancestor cgroups during compute_effective_progs()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720033055.1215477-1-pulehui@huaweicloud.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
@ 2026-07-20 3:50 ` sashiko-bot
2026-07-20 12:13 ` Pu Lehui
2026-07-20 4:04 ` bot+bpf-ci
1 sibling, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-07-20 3:50 UTC (permalink / raw)
To: Pu Lehui; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] bpf_netns_link_update_prog checks link->prog locklessly, allowing a TOCTOU race that violates atomic replacement guarantees.
- [High] Concurrent BPF_LINK_UPDATE can race with bpf_mprog_link to cause a Use-After-Free when dereferencing link->prog->type.
--
--- Patch [1]: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info ---
commit 5b8e0ac8575ebc387f2ddc7dee211697bb704588
Author: Pu Lehui <pulehui@huawei.com>
bpf: Fix potential UAF when reading bpf link info
This commit addresses a potential Use-After-Free issue when accessing
link->prog without locks in bpf_link_show_fdinfo and bpf_link_get_info_by_fd.
It resolves the problem by acquiring both normal RCU and tasks trace RCU
read locks before dereferencing the program, preventing concurrent freeing
during bpf_link_update operations.
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 6db306d23b479..2458c68146b95 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3490,13 +3491,23 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
> }
> seq_printf(m, "link_id:\t%u\n", link->id);
>
> + /* prog can be sleepable */
> + rcu_read_lock_trace();
> + rcu_read_lock();
> + prog = READ_ONCE(link->prog);
[Severity: High]
This isn't a bug introduced by this patch, but since you are fixing lockless
dereferences of link->prog here, could a similar TOCTOU race happen in
bpf_netns_link_update_prog()?
kernel/bpf/net_namespace.c:bpf_netns_link_update_prog() {
...
if (old_prog && old_prog != link->prog)
return -EPERM;
if (new_prog->type != link->prog->type)
return -EINVAL;
mutex_lock(&netns_bpf_mutex);
...
}
Two threads concurrently calling BPF_LINK_UPDATE on a netns link could both
evaluate the old_prog != link->prog check locklessly and pass it. If they
acquire netns_bpf_mutex one after the other, would the second thread
blindly overwrite link->prog, overriding the first thread's update and
violating the BPF_F_REPLACE API contract?
[Severity: High]
This is also a pre-existing issue, but does a similar Use-After-Free race
exist in bpf_mprog_link()?
kernel/bpf/mprog.c:bpf_mprog_link() {
...
if (type && link->prog->type != type) {
bpf_link_put(link);
return -EINVAL;
}
...
}
If a thread calls BPF_PROG_ATTACH on a tcx hook (holding the sleepable
rtnl_lock) and supplies a relative_fd pointing to a netns link,
bpf_mprog_link() executes without an RCU read-side critical section.
Could this thread be preempted, allowing a concurrent BPF_LINK_UPDATE on
the same netns link to replace and free link->prog? When the first thread
resumes, it would dereference link->prog->type where link->prog now points
to freed memory.
> if (prog) {
> bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
> + prog_id = prog->aux->id;
> + }
> + rcu_read_unlock();
> + rcu_read_unlock_trace();
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720033055.1215477-1-pulehui@huaweicloud.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
2026-07-20 3:50 ` sashiko-bot
@ 2026-07-20 4:04 ` bot+bpf-ci
2026-07-20 12:17 ` Pu Lehui
1 sibling, 1 reply; 10+ messages in thread
From: bot+bpf-ci @ 2026-07-20 4:04 UTC (permalink / raw)
To: pulehui, bpf, linux-kernel
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, yonghong.song,
song, jolsa, emil, pulehui, pulehui, ast, andrii, daniel,
martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1440 bytes --]
> 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 holding both normal RCU and tasks trace RCU read locks
> before dereferencing the prog, as BPF_LINK_TYPE_ITER support both
> non-sleepable and sleepable progs.
>
> Fixes: f9d041271cf4 ("bpf: Refactor bpf_link update handling")
Is the Fixes: tag pointing at the right commit?
f9d041271cf4 ("bpf: Refactor bpf_link update handling") only refactored
the existing update path into the bpf_link_ops->update_prog method. It
does not look like it introduced the ability to concurrently replace and
free link->prog.
The unlocked reader in bpf_link_show_fdinfo() already existed by then,
and the racing replacement path (the BPF_LINK_UPDATE command with
xchg(&link->prog, new_prog) followed by bpf_prog_put(old_prog)) seems to
have first appeared in:
0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
Should the tag instead be:
Fixes: 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/29715011327
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed
2026-07-20 3:41 ` sashiko-bot
@ 2026-07-20 12:06 ` Pu Lehui
0 siblings, 0 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 12:06 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On 2026/7/20 11:41, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> New issues:
> - [Medium] Uninitialized memory is read when saving `pl->storage` into `old_storage` for newly allocated `bpf_prog_list` entries.
>
> Pre-existing issues:
> - [High] If the first program attach to a cgroup fails, `cgrp->bpf.flags[atype]` is not rolled back, leading to a complete bypass of ancestor mandatory security policies.
> --
>
> --- Patch [2]: [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed ---
> commit 30470afb00630f3ed1a914958997d62e12b1f60a
> Author: Pu Lehui <pulehui@huawei.com>
>
> bpf, cgroup: Fix storage not restored when update_effective_progs failed
>
> In __cgroup_bpf_attach(), if update_effective_progs() fails, pl->storage
> is not restored to old_storage. This patch saves the old_storage before
> assigning the new one, and restores it in the error path.
>
>> diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
>> --- a/kernel/bpf/cgroup.c
>> +++ b/kernel/bpf/cgroup.c
> [ ... ]
>> @@ -883,6 +884,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
>> pl->prog = prog;
>> pl->link = link;
>> pl->flags = flags;
>> + bpf_cgroup_storages_assign(old_storage, pl->storage);
>
> [Severity: Medium]
> When __cgroup_bpf_attach() allocates a new bpf_prog_list entry, it does so
> without zeroing the memory:
>
> pl = kmalloc_obj(*pl);
>
> Because pl is not zero-initialized, does calling bpf_cgroup_storages_assign()
> here result in reading uninitialized garbage pointers from pl->storage and
> copying them into old_storage? This could trigger KMSAN uninit-value warnings
> when attaching a new program.
will fix in next
>
>> bpf_cgroup_storages_assign(pl->storage, storage);
>> cgrp->bpf.flags[atype] = saved_flags;
>>
> [ ... ]
>> @@ -916,6 +918,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
>> pl->prog = old_prog;
>> pl->link = NULL;
>> }
>> + bpf_cgroup_storages_assign(pl->storage, old_storage);
>> bpf_cgroup_storages_free(new_storage);
>> if (!old_prog) {
>> hlist_del(&pl->node);
>> kfree(pl);
>> }
>> return err;
>> }
>
> [Severity: High]
> This isn't a bug introduced by this patch, but looking at the error path, if
> the very first program attach to a cgroup fails (for example, if
> update_effective_progs() fails), the newly added list entry is deleted and
> freed here, making the list empty again.
>
> However, the flags set earlier in the function are not rolled back:
>
> cgrp->bpf.flags[atype] = saved_flags;
>
> Could an attacker attempt an attach with BPF_F_ALLOW_MULTI, intentionally
> force an error (like hitting memory limits in update_effective_progs()), and
> leave the compromised cgroup with permanently altered BPF flags?
>
> If the flags stay stuck, does this allow bypassing mandatory, non-overridable
> programs from ancestor cgroups during compute_effective_progs()?
>
It's hard to make update_effective_progs fail in __cgroup_bpf_attach,
but for the sake of code rigor, I will include the storage and flags
rollbacks in the original bugfix patch.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info
2026-07-20 3:50 ` sashiko-bot
@ 2026-07-20 12:13 ` Pu Lehui
0 siblings, 0 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 12:13 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On 2026/7/20 11:50, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] bpf_netns_link_update_prog checks link->prog locklessly, allowing a TOCTOU race that violates atomic replacement guarantees.
> - [High] Concurrent BPF_LINK_UPDATE can race with bpf_mprog_link to cause a Use-After-Free when dereferencing link->prog->type.
> --
>
> --- Patch [1]: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info ---
> commit 5b8e0ac8575ebc387f2ddc7dee211697bb704588
> Author: Pu Lehui <pulehui@huawei.com>
>
> bpf: Fix potential UAF when reading bpf link info
>
> This commit addresses a potential Use-After-Free issue when accessing
> link->prog without locks in bpf_link_show_fdinfo and bpf_link_get_info_by_fd.
> It resolves the problem by acquiring both normal RCU and tasks trace RCU
> read locks before dereferencing the program, preventing concurrent freeing
> during bpf_link_update operations.
>
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index 6db306d23b479..2458c68146b95 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -3490,13 +3491,23 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
>> }
>> seq_printf(m, "link_id:\t%u\n", link->id);
>>
>> + /* prog can be sleepable */
>> + rcu_read_lock_trace();
>> + rcu_read_lock();
>> + prog = READ_ONCE(link->prog);
>
> [Severity: High]
> This isn't a bug introduced by this patch, but since you are fixing lockless
> dereferences of link->prog here, could a similar TOCTOU race happen in
> bpf_netns_link_update_prog()?
>
> kernel/bpf/net_namespace.c:bpf_netns_link_update_prog() {
> ...
> if (old_prog && old_prog != link->prog)
> return -EPERM;
> if (new_prog->type != link->prog->type)
> return -EINVAL;
>
> mutex_lock(&netns_bpf_mutex);
> ...
> }
I will move forware the `mutex_lock(&netns_bpf_mutex)` in next.
>
> Two threads concurrently calling BPF_LINK_UPDATE on a netns link could both
> evaluate the old_prog != link->prog check locklessly and pass it. If they
> acquire netns_bpf_mutex one after the other, would the second thread
> blindly overwrite link->prog, overriding the first thread's update and
> violating the BPF_F_REPLACE API contract?
>
> [Severity: High]
> This is also a pre-existing issue, but does a similar Use-After-Free race
> exist in bpf_mprog_link()?
>
> kernel/bpf/mprog.c:bpf_mprog_link() {
> ...
> if (type && link->prog->type != type) {
> bpf_link_put(link);
> return -EINVAL;
> }
> ...
> }
>
> If a thread calls BPF_PROG_ATTACH on a tcx hook (holding the sleepable
> rtnl_lock) and supplies a relative_fd pointing to a netns link,
emm, the link referenced by relative_fd cannot be a non-netkit or
non-tcx link. We need to add a restriction here.
> bpf_mprog_link() executes without an RCU read-side critical section.
>
> Could this thread be preempted, allowing a concurrent BPF_LINK_UPDATE on
> the same netns link to replace and free link->prog? When the first thread
> resumes, it would dereference link->prog->type where link->prog now points
> to freed memory.
>
>> if (prog) {
>> bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
>> + prog_id = prog->aux->id;
>> + }
>> + rcu_read_unlock();
>> + rcu_read_unlock_trace();
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info
2026-07-20 4:04 ` bot+bpf-ci
@ 2026-07-20 12:17 ` Pu Lehui
0 siblings, 0 replies; 10+ messages in thread
From: Pu Lehui @ 2026-07-20 12:17 UTC (permalink / raw)
To: bot+bpf-ci, bpf, linux-kernel
Cc: ast, daniel, andrii, eddyz87, memxor, martin.lau, yonghong.song,
song, jolsa, emil, pulehui, martin.lau, clm, ihor.solodrai
On 2026/7/20 12:04, bot+bpf-ci@kernel.org wrote:
>> 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 holding both normal RCU and tasks trace RCU read locks
>> before dereferencing the prog, as BPF_LINK_TYPE_ITER support both
>> non-sleepable and sleepable progs.
>>
>> Fixes: f9d041271cf4 ("bpf: Refactor bpf_link update handling")
>
> Is the Fixes: tag pointing at the right commit?
>
> f9d041271cf4 ("bpf: Refactor bpf_link update handling") only refactored
> the existing update path into the bpf_link_ops->update_prog method. It
> does not look like it introduced the ability to concurrently replace and
> free link->prog.
>
> The unlocked reader in bpf_link_show_fdinfo() already existed by then,
> and the racing replacement path (the BPF_LINK_UPDATE command with
> xchg(&link->prog, new_prog) followed by bpf_prog_put(old_prog)) seems to
> have first appeared in:
>
> 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
>
> Should the tag instead be:
>
> Fixes: 0c991ebc8c69 ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
make sense.
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/29715011327
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-20 12:17 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 3:30 [PATCH bpf v3 0/3] Fixes for bpf link update Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 1/3] bpf: Fix potential UAF when reading bpf link info Pu Lehui
2026-07-20 3:50 ` sashiko-bot
2026-07-20 12:13 ` Pu Lehui
2026-07-20 4:04 ` bot+bpf-ci
2026-07-20 12:17 ` Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 2/3] bpf, cgroup: Fix storage not restored when update_effective_progs failed Pu Lehui
2026-07-20 3:41 ` sashiko-bot
2026-07-20 12:06 ` Pu Lehui
2026-07-20 3:30 ` [PATCH bpf v3 3/3] bpf, cgroup: Fix storage null-ptr-deref after replacing prog Pu Lehui
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox