[Devel] [PATCH RHEL10 COMMIT] selftests/ve_devcg_bpf: test orig_insns reporting via BPF_OBJ_GET_INFO_BY_FD

Konstantin Khorenko khorenko at virtuozzo.com
Fri Jul 31 16:42:08 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.39.1.16.1.vz10
------>
commit 4ba1a4d54883dd87f0d49f71a848118a6b2cafeb
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Tue Jul 28 13:08:11 2026 +0200

    selftests/ve_devcg_bpf: test orig_insns reporting via BPF_OBJ_GET_INFO_BY_FD
    
    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.
    
    Feature: BPF checkpoint/restore
    https://virtuozzo.atlassian.net/browse/VSTOR-121776
    Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
    Reviewed-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>
---
 tools/testing/selftests/ve_devcg_bpf/Makefile      |  3 ++
 .../selftests/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


More information about the Devel mailing list