[Devel] [PATCH VZ10 3/3] selftests/ve_devcg_bpf: test orig_insns reporting via BPF_OBJ_GET_INFO_BY_FD
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Wed Jul 29 14:39:36 MSK 2026
On 7/29/26 11:47, Vasileios Almpanis wrote:
>
> 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
You are right, this last sentence is a leftover blooper from the version where I
experimented with kptr_restrict. We don't really need extra restriction as we don't have
any kernel-private pointers in the original program (the converted (xlated/jitted)
have this extra restriction via bpf_dump_raw_ok()).
>>
>> 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, Pavel Tikhomirov
Senior Software Developer, Virtuozzo.
More information about the Devel
mailing list