[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