bpf, cgroup: Fix storage null-ptr-deref after replacing prog

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 rejecting a link update if new_prog's cgroup storage is
incompatible with link->prog.

Fixes: 0c991ebc8c ("bpf: Implement bpf_prog replacement for an active bpf_cgroup_link")
Signed-off-by: Pu Lehui <pulehui@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/bpf/20260728132336.2857800-1-pulehui@huaweicloud.com [0]
Link: https://lore.kernel.org/bpf/f87b53c0-8f00-45a6-82db-8242fa9b143f@huaweicloud.com [1]
Link: https://lore.kernel.org/bpf/20260807104403.1013064-1-pulehui@huaweicloud.com
This commit is contained in:
Pu Lehui
2026-08-07 10:44:03 +00:00
committed by Andrii Nakryiko
parent e1d9b82db5
commit 3f562c537e

View File

@@ -1026,6 +1026,20 @@ static void replace_effective_prog(struct cgroup *cgrp,
}
}
static bool cgroup_bpf_storages_compatible(struct bpf_prog *old_prog,
struct bpf_prog *new_prog)
{
enum bpf_cgroup_storage_type stype;
for_each_cgroup_storage_type(stype) {
if (old_prog->aux->cgroup_storage[stype] !=
new_prog->aux->cgroup_storage[stype])
return false;
}
return true;
}
/**
* __cgroup_bpf_replace() - Replace link's program and propagate the change
* to descendants
@@ -1064,6 +1078,9 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,
if (!found)
return -ENOENT;
if (!cgroup_bpf_storages_compatible(link->link.prog, new_prog))
return -EINVAL;
cgrp->bpf.revisions[atype] += 1;
old_prog = xchg(&link->link.prog, new_prog);
replace_effective_prog(cgrp, atype, pl);