xref: /linux/tools/testing/selftests/bpf/prog_tests/bpf_attr_size.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2026 Google LLC */
3 #include <linux/bpf.h>
4 #include <unistd.h>
5 #include <sys/syscall.h>
6 #include <test_progs.h>
7 #include <cgroup_helpers.h>
8 #include "cgroup_skb_direct_packet_access.skel.h"
9 
10 #define OLD_QUERY_SIZE		offsetofend(union bpf_attr, query.prog_cnt)
11 #define FULL_QUERY_SIZE		offsetofend(union bpf_attr, query.revision)
12 
13 static void test_query_size_boundaries(void)
14 {
15 	struct cgroup_skb_direct_packet_access *skel;
16 	struct bpf_link *link = NULL;
17 	union bpf_attr attr;
18 	int cg_fd = -1;
19 	int err;
20 
21 	skel = cgroup_skb_direct_packet_access__open_and_load();
22 	if (!ASSERT_OK_PTR(skel, "skel_load"))
23 		return;
24 
25 	cg_fd = test__join_cgroup("/attr_size_cg");
26 	if (!ASSERT_GE(cg_fd, 0, "join_cgroup"))
27 		goto cleanup;
28 
29 	link = bpf_program__attach_cgroup(skel->progs.direct_packet_access,
30 					  cg_fd);
31 	if (!ASSERT_OK_PTR(link, "cg_attach"))
32 		goto cleanup;
33 
34 	memset(&attr, 0, sizeof(attr));
35 	attr.query.target_fd = cg_fd;
36 	attr.query.attach_type = BPF_CGROUP_INET_INGRESS;
37 	attr.query.revision = 0xdeadbeefdeadbeefULL;
38 
39 	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, OLD_QUERY_SIZE);
40 	if (ASSERT_OK(err, "query_old_size")) {
41 		ASSERT_EQ(attr.query.prog_cnt, 1, "prog_cnt_written_old");
42 		ASSERT_EQ(attr.query.revision, 0xdeadbeefdeadbeefULL,
43 			  "revision_not_written_old");
44 	}
45 
46 	memset(&attr, 0, sizeof(attr));
47 	attr.query.target_fd = cg_fd;
48 	attr.query.attach_type = BPF_CGROUP_INET_INGRESS;
49 
50 	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, FULL_QUERY_SIZE);
51 	if (!ASSERT_OK(err, "query_full_size"))
52 		goto cleanup;
53 
54 	ASSERT_EQ(attr.query.prog_cnt, 1, "prog_cnt_written");
55 	ASSERT_GT(attr.query.revision, 0, "revision_written");
56 
57 cleanup:
58 	if (link)
59 		bpf_link__destroy(link);
60 	if (cg_fd >= 0)
61 		close(cg_fd);
62 	cgroup_skb_direct_packet_access__destroy(skel);
63 }
64 
65 static void test_map_info_tail_zero(void)
66 {
67 	LIBBPF_OPTS(bpf_map_create_opts, map_opts);
68 	struct bpf_map_info_fake {
69 		__u8 info[offsetofend(struct bpf_map_info, hash_size)];
70 		__u32 pad;
71 	} info = {
72 		.pad = 1,
73 	};
74 	int map_fd, err;
75 	__u32 info_len;
76 
77 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr", sizeof(int), 1, 1, &map_opts);
78 	if (!ASSERT_GE(map_fd, 0, "bpf_map_create"))
79 		return;
80 
81 	info_len = sizeof(info);
82 	err = bpf_obj_get_info_by_fd(map_fd, &info, &info_len);
83 	ASSERT_EQ(err, -E2BIG, "bpf_obj_get_info_by_fd");
84 
85 	close(map_fd);
86 }
87 
88 static void test_prog_info_tail_zero(void)
89 {
90 	LIBBPF_OPTS(bpf_prog_load_opts, prog_opts);
91 	struct bpf_insn insns[] = {
92 		BPF_MOV64_IMM(BPF_REG_0, 0),
93 		BPF_EXIT_INSN(),
94 	};
95 	struct bpf_prog_info_fake {
96 		__u8 info[offsetofend(struct bpf_prog_info, attach_btf_id)];
97 		__u32 pad;
98 	} info = {
99 		.pad = 1,
100 	};
101 	int prog_fd, err;
102 	__u32 info_len;
103 
104 	prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, "test_prog", "GPL", insns,
105 				ARRAY_SIZE(insns), &prog_opts);
106 	if (!ASSERT_GE(prog_fd, 0, "bpf_prog_load"))
107 		return;
108 
109 	info_len = sizeof(info);
110 	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
111 	ASSERT_EQ(err, -E2BIG, "bpf_obj_get_info_by_fd");
112 
113 	close(prog_fd);
114 }
115 
116 void test_bpf_attr_size(void)
117 {
118 	if (test__start_subtest("query_size_boundaries"))
119 		test_query_size_boundaries();
120 	if (test__start_subtest("map_info_tail_zero"))
121 		test_map_info_tail_zero();
122 	if (test__start_subtest("prog_info_tail_zero"))
123 		test_prog_info_tail_zero();
124 }
125