[Devel] [PATCH VZ10 3/3] selftests/ve_devcg_bpf: test orig_insns reporting via BPF_OBJ_GET_INFO_BY_FD

Vasileios Almpanis vasileios.almpanis at virtuozzo.com
Wed Jul 29 12:47:37 MSK 2026


On 7/28/26 1:08 PM, Pavel Tikhomirov wrote:
> Add prog_info_orig_host: from privileged (bpf_capable) host context, load
> a CGROUP_DEVICE program and verify BPF_OBJ_GET_INFO_BY_FD reports its
> original instructions - orig_prog_len equals the program size and, when
> dumping is allowed, orig_prog_insns round-trips byte for byte. This is
> the interface CRIU uses to dump the program.
>
> Only a host test is provided: a VE process is not bpf_capable(), so
> bpf_prog_get_info_by_fd() zeroes the program-info lengths and returns
> early, and orig_prog info is never exposed to the VE itself. CRIU dumps
> from the host, which is the path exercised here. The kptr_restrict is
> pinned to make bpf_dump_raw_ok() deterministic and restored afterwards.
Where is kptr_restrict pinned? I don't see it in the test. Also 
orig_insns is not gated
on bpf_dump_raw_ok. Only on bpf_capable(). I think this message part is 
just stale
because we only reset orig_prog_len in capable checks unlike other 
fields that gate on
bpf_dump_raw_ok. Apart from that LGTM
>
> Feature: BPF checkpoint/restore
> https://virtuozzo.atlassian.net/browse/VSTOR-121776
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> ---
>   tools/testing/selftests/ve_devcg_bpf/Makefile |  3 ++
>   .../ve_devcg_bpf/ve_devcg_bpf_test.c          | 50 +++++++++++++++++++
>   2 files changed, 53 insertions(+)
>
> diff --git a/tools/testing/selftests/ve_devcg_bpf/Makefile b/tools/testing/selftests/ve_devcg_bpf/Makefile
> index c5aa8b59880f3..ba811f22e36ac 100644
> --- a/tools/testing/selftests/ve_devcg_bpf/Makefile
> +++ b/tools/testing/selftests/ve_devcg_bpf/Makefile
> @@ -1,6 +1,9 @@
>   # SPDX-License-Identifier: GPL-2.0
>   # Makefile for ve_devcg_bpf selftests.
>   CFLAGS += -g -Wall -O2
> +# orig_prog_len/orig_prog_insns may be newer than the system UAPI headers, so
> +# build against the in-tree copy under tools/include/uapi.
> +CFLAGS += $(TOOLS_INCLUDES)
>   
>   TEST_GEN_PROGS += ve_devcg_bpf_test
>   
> diff --git a/tools/testing/selftests/ve_devcg_bpf/ve_devcg_bpf_test.c b/tools/testing/selftests/ve_devcg_bpf/ve_devcg_bpf_test.c
> index da55f82492f5b..cca0f6905d8da 100644
> --- a/tools/testing/selftests/ve_devcg_bpf/ve_devcg_bpf_test.c
> +++ b/tools/testing/selftests/ve_devcg_bpf/ve_devcg_bpf_test.c
> @@ -12,6 +12,8 @@
>    *   on the VE root cgroup.
>    * - BPF_PROG_TYPE_CGROUP_DEVICE programs can be attached to and queried
>    *   on descendant cgroups inside VE.
> + * - BPF_OBJ_GET_INFO_BY_FD reports a CGROUP_DEVICE program's original
> + *   instructions (orig_prog_len/orig_prog_insns) for CRIU dump/restore.
>    */
>   #define _GNU_SOURCE
>   #include <linux/sched.h>
> @@ -739,4 +741,52 @@ TEST_F(ve_devcg_bpf, prog_load_oversized_denied)
>   			   TEST_PROG_LOAD_OVERSIZED_DENIED), 0);
>   }
>   
> +/*
> + * From host (root) context (hence no fixture in this test), dump the program
> + * and check it matches the loaded version exactly.
> + */
> +TEST(prog_info_orig_host)
> +{
> +	struct bpf_insn insns[] = { DEVCG_PROG_INSNS };
> +	struct bpf_insn readback[ARRAY_SIZE(insns)];
> +	struct bpf_prog_info info;
> +	union bpf_attr attr;
> +	int prog_fd;
> +
> +	prog_fd = load_devcg_prog();
> +	ASSERT_GE(prog_fd, 0);
> +
> +	/* Size query: orig_prog_len must equal the loaded program size. */
> +	memset(&info, 0, sizeof(info));
> +	memset(&attr, 0, sizeof(attr));
> +	attr.info.bpf_fd = prog_fd;
> +	attr.info.info_len = sizeof(info);
> +	attr.info.info = (unsigned long)&info;
> +	ASSERT_EQ(syscall(__NR_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr,
> +			  sizeof(attr)), 0);
> +
> +	if (info.orig_prog_len == 0) {
> +		close(prog_fd);
> +		SKIP(return, "kernel does not report orig_insns");
> +	}
> +	ASSERT_EQ(info.orig_prog_len, sizeof(insns));
> +
> +	/* The original instructions round-trip byte for byte. */
> +	memset(&info, 0, sizeof(info));
> +	memset(readback, 0xff, sizeof(readback));
> +	info.orig_prog_len = sizeof(readback);
> +	info.orig_prog_insns = (unsigned long)readback;
> +	memset(&attr, 0, sizeof(attr));
> +	attr.info.bpf_fd = prog_fd;
> +	attr.info.info_len = sizeof(info);
> +	attr.info.info = (unsigned long)&info;
> +	EXPECT_EQ(syscall(__NR_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr,
> +			  sizeof(attr)), 0);
> +	EXPECT_EQ(info.orig_prog_len, sizeof(insns));
> +	EXPECT_NE(info.orig_prog_insns, 0);
> +	EXPECT_EQ(memcmp(readback, insns, sizeof(insns)), 0);
> +
> +	close(prog_fd);
> +}
> +
>   TEST_HARNESS_MAIN

-- 
Best regards, Vasileios Almpanis
Software Developer, Virtuozzo.



More information about the Devel mailing list