* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.