mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
bpf, cgroup: Fix invalid storage access after __cgroup_bpf_attach failed
A potential invalid storage access issue can occur after replacing a
cgroup bpf prog.
This occurs in the following scenario:
1. prog1 with storage is attached to a cgroup in multi-attach mode.
2. prog1 is replaced with prog2 using BPF_F_REPLACE in multi-attach
mode, but fails midway (e.g. in bpf_trampoline_link_cgroup_shim or
update_effective_progs).
3. A new prog3 is attached to the cgroup in multi-attach mode.
The reason is that __cgroup_bpf_attach overwrites pl->storage with the
new storage prior to attachment completion. When attachment fails
midway, the cleanup path calls bpf_cgroup_storages_free(new_storage) to
free the newly allocated storage, but fails to restore pl->storage back
to old_storage.
Consequently, the still-active prog1 holds invalid or dangling storage
pointers, leading to an invalid memory access when prog1 executes and
calls bpf_get_local_storage. Additionally, original pl->flags and
cgrp->bpf.flags[atype] are left unrestored.
Fix this by saving old_pl_flags, old_storage, and old_flags prior to the
update, and properly restoring all of them in the cleanup path on error.
Fixes: 7d9c342789 ("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>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/bpf/20260803013934.4036646-1-pulehui@huaweicloud.com
This commit is contained in:
parent
e2baf9cc37
commit
6655c40970
|
|
@ -813,8 +813,10 @@ 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;
|
||||
u32 old_flags, old_pl_flags;
|
||||
struct bpf_prog_list *pl;
|
||||
struct hlist_head *progs;
|
||||
int err;
|
||||
|
|
@ -865,6 +867,8 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
|
|||
|
||||
if (pl) {
|
||||
old_prog = pl->prog;
|
||||
old_pl_flags = pl->flags;
|
||||
bpf_cgroup_storages_assign(old_storage, pl->storage);
|
||||
} else {
|
||||
pl = kmalloc_obj(*pl);
|
||||
if (!pl) {
|
||||
|
|
@ -884,6 +888,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
|
|||
pl->link = link;
|
||||
pl->flags = flags;
|
||||
bpf_cgroup_storages_assign(pl->storage, storage);
|
||||
old_flags = cgrp->bpf.flags[atype];
|
||||
cgrp->bpf.flags[atype] = saved_flags;
|
||||
|
||||
if (type == BPF_LSM_CGROUP) {
|
||||
|
|
@ -915,12 +920,15 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
|
|||
if (old_prog) {
|
||||
pl->prog = old_prog;
|
||||
pl->link = NULL;
|
||||
pl->flags = old_pl_flags;
|
||||
bpf_cgroup_storages_assign(pl->storage, old_storage);
|
||||
}
|
||||
bpf_cgroup_storages_free(new_storage);
|
||||
if (!old_prog) {
|
||||
hlist_del(&pl->node);
|
||||
kfree(pl);
|
||||
}
|
||||
cgrp->bpf.flags[atype] = old_flags;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user