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