Re: [RFC PATCH bpf-next v6 11/12] selftests/bpf: Add test for memcg_bpf_ops hierarchies

From: XIAO WU

Date: Thu Apr 23 2026 - 05:15:45 EST


Hi,

> +cleanup:
> + bpf_link__destroy(link1);
> + bpf_link__destroy(link2);
> + bpf_link__destroy(link3);
> + memcg_ops__detach(skel);
> + memcg_ops__destroy(skel);
>
> Can this crash if skel is NULL?

Yes, this is a valid bug in the selftest cleanup path.

If execution jumps to cleanup before memcg_ops__open_and_load()
succeeds, skel remains NULL. In that case, memcg_ops__detach(skel)
dereferences NULL through obj->skeleton in the generated detach helper,
as you pointed out.

This is also inconsistent with nearby tests in the same file that
already do if (skel) {
memcg_ops__detach(skel);
memcg_ops__destroy(skel);
}

The C repro, modeling the same control flow:

--8<--
// SPDX-License-Identifier: GPL-2.0
// PoC for cleanup-path NULL dereference in
test_memcg_ops_hierarchies().

#include <stdio.h>

struct bpf_object_skeleton {
int dummy;
};

struct memcg_ops {
struct bpf_object_skeleton *skeleton;
};

__attribute__((noinline))
static void bpf_object__detach_skeleton(struct bpf_object_skeleton *s)
{
(void)s;
}

/* Matches generated skeleton helper shape from review mail. */
static inline void memcg_ops__detach(struct memcg_ops *obj)
{
bpf_object__detach_skeleton(obj->skeleton);
}

static int setup_cgroup_environment_fail(void)
{
return -1;
}

int main(void)
{
int ret;
struct memcg_ops *skel = NULL;

fprintf(stderr, "[*] trigger cleanup with skel == NULL\n");

/* Simulate early failure before open_and_load() assigns skel. */
ret = setup_cgroup_environment_fail();
if (ret)
goto cleanup;

cleanup:
/* Same problematic call pattern as in the test cleanup block. */
memcg_ops__detach(skel);

return 0;
}
--8<--


Signed-off-by: XIAO WU <shawdoxwu@xxxxxxxxx>

Thanks,

xiao