1*1c593d74SAnton Protopopov // SPDX-License-Identifier: GPL-2.0
2*1c593d74SAnton Protopopov
3*1c593d74SAnton Protopopov #include <test_progs.h>
4*1c593d74SAnton Protopopov
5*1c593d74SAnton Protopopov #include <linux/btf.h>
6*1c593d74SAnton Protopopov #include <bpf/bpf.h>
7*1c593d74SAnton Protopopov
8*1c593d74SAnton Protopopov #include "../test_btf.h"
9*1c593d74SAnton Protopopov
new_map(void)10*1c593d74SAnton Protopopov static inline int new_map(void)
11*1c593d74SAnton Protopopov {
12*1c593d74SAnton Protopopov const char *name = NULL;
13*1c593d74SAnton Protopopov __u32 max_entries = 1;
14*1c593d74SAnton Protopopov __u32 value_size = 8;
15*1c593d74SAnton Protopopov __u32 key_size = 4;
16*1c593d74SAnton Protopopov
17*1c593d74SAnton Protopopov return bpf_map_create(BPF_MAP_TYPE_ARRAY, name,
18*1c593d74SAnton Protopopov key_size, value_size,
19*1c593d74SAnton Protopopov max_entries, NULL);
20*1c593d74SAnton Protopopov }
21*1c593d74SAnton Protopopov
new_btf(void)22*1c593d74SAnton Protopopov static int new_btf(void)
23*1c593d74SAnton Protopopov {
24*1c593d74SAnton Protopopov struct btf_blob {
25*1c593d74SAnton Protopopov struct btf_header btf_hdr;
26*1c593d74SAnton Protopopov __u32 types[8];
27*1c593d74SAnton Protopopov __u32 str;
28*1c593d74SAnton Protopopov } raw_btf = {
29*1c593d74SAnton Protopopov .btf_hdr = {
30*1c593d74SAnton Protopopov .magic = BTF_MAGIC,
31*1c593d74SAnton Protopopov .version = BTF_VERSION,
32*1c593d74SAnton Protopopov .hdr_len = sizeof(struct btf_header),
33*1c593d74SAnton Protopopov .type_len = sizeof(raw_btf.types),
34*1c593d74SAnton Protopopov .str_off = offsetof(struct btf_blob, str) - offsetof(struct btf_blob, types),
35*1c593d74SAnton Protopopov .str_len = sizeof(raw_btf.str),
36*1c593d74SAnton Protopopov },
37*1c593d74SAnton Protopopov .types = {
38*1c593d74SAnton Protopopov /* long */
39*1c593d74SAnton Protopopov BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 64, 8), /* [1] */
40*1c593d74SAnton Protopopov /* unsigned long */
41*1c593d74SAnton Protopopov BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
42*1c593d74SAnton Protopopov },
43*1c593d74SAnton Protopopov };
44*1c593d74SAnton Protopopov
45*1c593d74SAnton Protopopov return bpf_btf_load(&raw_btf, sizeof(raw_btf), NULL);
46*1c593d74SAnton Protopopov }
47*1c593d74SAnton Protopopov
48*1c593d74SAnton Protopopov #define Close(FD) do { \
49*1c593d74SAnton Protopopov if ((FD) >= 0) { \
50*1c593d74SAnton Protopopov close(FD); \
51*1c593d74SAnton Protopopov FD = -1; \
52*1c593d74SAnton Protopopov } \
53*1c593d74SAnton Protopopov } while(0)
54*1c593d74SAnton Protopopov
map_exists(__u32 id)55*1c593d74SAnton Protopopov static bool map_exists(__u32 id)
56*1c593d74SAnton Protopopov {
57*1c593d74SAnton Protopopov int fd;
58*1c593d74SAnton Protopopov
59*1c593d74SAnton Protopopov fd = bpf_map_get_fd_by_id(id);
60*1c593d74SAnton Protopopov if (fd >= 0) {
61*1c593d74SAnton Protopopov close(fd);
62*1c593d74SAnton Protopopov return true;
63*1c593d74SAnton Protopopov }
64*1c593d74SAnton Protopopov return false;
65*1c593d74SAnton Protopopov }
66*1c593d74SAnton Protopopov
btf_exists(__u32 id)67*1c593d74SAnton Protopopov static bool btf_exists(__u32 id)
68*1c593d74SAnton Protopopov {
69*1c593d74SAnton Protopopov int fd;
70*1c593d74SAnton Protopopov
71*1c593d74SAnton Protopopov fd = bpf_btf_get_fd_by_id(id);
72*1c593d74SAnton Protopopov if (fd >= 0) {
73*1c593d74SAnton Protopopov close(fd);
74*1c593d74SAnton Protopopov return true;
75*1c593d74SAnton Protopopov }
76*1c593d74SAnton Protopopov return false;
77*1c593d74SAnton Protopopov }
78*1c593d74SAnton Protopopov
bpf_prog_get_map_ids(int prog_fd,__u32 * nr_map_ids,__u32 * map_ids)79*1c593d74SAnton Protopopov static inline int bpf_prog_get_map_ids(int prog_fd, __u32 *nr_map_ids, __u32 *map_ids)
80*1c593d74SAnton Protopopov {
81*1c593d74SAnton Protopopov __u32 len = sizeof(struct bpf_prog_info);
82*1c593d74SAnton Protopopov struct bpf_prog_info info;
83*1c593d74SAnton Protopopov int err;
84*1c593d74SAnton Protopopov
85*1c593d74SAnton Protopopov memset(&info, 0, len);
86*1c593d74SAnton Protopopov info.nr_map_ids = *nr_map_ids,
87*1c593d74SAnton Protopopov info.map_ids = ptr_to_u64(map_ids),
88*1c593d74SAnton Protopopov
89*1c593d74SAnton Protopopov err = bpf_prog_get_info_by_fd(prog_fd, &info, &len);
90*1c593d74SAnton Protopopov if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))
91*1c593d74SAnton Protopopov return -1;
92*1c593d74SAnton Protopopov
93*1c593d74SAnton Protopopov *nr_map_ids = info.nr_map_ids;
94*1c593d74SAnton Protopopov
95*1c593d74SAnton Protopopov return 0;
96*1c593d74SAnton Protopopov }
97*1c593d74SAnton Protopopov
__load_test_prog(int map_fd,const int * fd_array,int fd_array_cnt)98*1c593d74SAnton Protopopov static int __load_test_prog(int map_fd, const int *fd_array, int fd_array_cnt)
99*1c593d74SAnton Protopopov {
100*1c593d74SAnton Protopopov /* A trivial program which uses one map */
101*1c593d74SAnton Protopopov struct bpf_insn insns[] = {
102*1c593d74SAnton Protopopov BPF_LD_MAP_FD(BPF_REG_1, map_fd),
103*1c593d74SAnton Protopopov BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
104*1c593d74SAnton Protopopov BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
105*1c593d74SAnton Protopopov BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
106*1c593d74SAnton Protopopov BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
107*1c593d74SAnton Protopopov BPF_MOV64_IMM(BPF_REG_0, 0),
108*1c593d74SAnton Protopopov BPF_EXIT_INSN(),
109*1c593d74SAnton Protopopov };
110*1c593d74SAnton Protopopov LIBBPF_OPTS(bpf_prog_load_opts, opts);
111*1c593d74SAnton Protopopov
112*1c593d74SAnton Protopopov opts.fd_array = fd_array;
113*1c593d74SAnton Protopopov opts.fd_array_cnt = fd_array_cnt;
114*1c593d74SAnton Protopopov
115*1c593d74SAnton Protopopov return bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, ARRAY_SIZE(insns), &opts);
116*1c593d74SAnton Protopopov }
117*1c593d74SAnton Protopopov
load_test_prog(const int * fd_array,int fd_array_cnt)118*1c593d74SAnton Protopopov static int load_test_prog(const int *fd_array, int fd_array_cnt)
119*1c593d74SAnton Protopopov {
120*1c593d74SAnton Protopopov int map_fd;
121*1c593d74SAnton Protopopov int ret;
122*1c593d74SAnton Protopopov
123*1c593d74SAnton Protopopov map_fd = new_map();
124*1c593d74SAnton Protopopov if (!ASSERT_GE(map_fd, 0, "new_map"))
125*1c593d74SAnton Protopopov return map_fd;
126*1c593d74SAnton Protopopov
127*1c593d74SAnton Protopopov ret = __load_test_prog(map_fd, fd_array, fd_array_cnt);
128*1c593d74SAnton Protopopov close(map_fd);
129*1c593d74SAnton Protopopov return ret;
130*1c593d74SAnton Protopopov }
131*1c593d74SAnton Protopopov
check_expected_map_ids(int prog_fd,int expected,__u32 * map_ids,__u32 * nr_map_ids)132*1c593d74SAnton Protopopov static bool check_expected_map_ids(int prog_fd, int expected, __u32 *map_ids, __u32 *nr_map_ids)
133*1c593d74SAnton Protopopov {
134*1c593d74SAnton Protopopov int err;
135*1c593d74SAnton Protopopov
136*1c593d74SAnton Protopopov err = bpf_prog_get_map_ids(prog_fd, nr_map_ids, map_ids);
137*1c593d74SAnton Protopopov if (!ASSERT_OK(err, "bpf_prog_get_map_ids"))
138*1c593d74SAnton Protopopov return false;
139*1c593d74SAnton Protopopov if (!ASSERT_EQ(*nr_map_ids, expected, "unexpected nr_map_ids"))
140*1c593d74SAnton Protopopov return false;
141*1c593d74SAnton Protopopov
142*1c593d74SAnton Protopopov return true;
143*1c593d74SAnton Protopopov }
144*1c593d74SAnton Protopopov
145*1c593d74SAnton Protopopov /*
146*1c593d74SAnton Protopopov * Load a program, which uses one map. No fd_array maps are present.
147*1c593d74SAnton Protopopov * On return only one map is expected to be bound to prog.
148*1c593d74SAnton Protopopov */
check_fd_array_cnt__no_fd_array(void)149*1c593d74SAnton Protopopov static void check_fd_array_cnt__no_fd_array(void)
150*1c593d74SAnton Protopopov {
151*1c593d74SAnton Protopopov __u32 map_ids[16];
152*1c593d74SAnton Protopopov __u32 nr_map_ids;
153*1c593d74SAnton Protopopov int prog_fd = -1;
154*1c593d74SAnton Protopopov
155*1c593d74SAnton Protopopov prog_fd = load_test_prog(NULL, 0);
156*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "BPF_PROG_LOAD"))
157*1c593d74SAnton Protopopov return;
158*1c593d74SAnton Protopopov nr_map_ids = ARRAY_SIZE(map_ids);
159*1c593d74SAnton Protopopov check_expected_map_ids(prog_fd, 1, map_ids, &nr_map_ids);
160*1c593d74SAnton Protopopov close(prog_fd);
161*1c593d74SAnton Protopopov }
162*1c593d74SAnton Protopopov
163*1c593d74SAnton Protopopov /*
164*1c593d74SAnton Protopopov * Load a program, which uses one map, and pass two extra, non-equal, maps in
165*1c593d74SAnton Protopopov * fd_array with fd_array_cnt=2. On return three maps are expected to be bound
166*1c593d74SAnton Protopopov * to the program.
167*1c593d74SAnton Protopopov */
check_fd_array_cnt__fd_array_ok(void)168*1c593d74SAnton Protopopov static void check_fd_array_cnt__fd_array_ok(void)
169*1c593d74SAnton Protopopov {
170*1c593d74SAnton Protopopov int extra_fds[2] = { -1, -1 };
171*1c593d74SAnton Protopopov __u32 map_ids[16];
172*1c593d74SAnton Protopopov __u32 nr_map_ids;
173*1c593d74SAnton Protopopov int prog_fd = -1;
174*1c593d74SAnton Protopopov
175*1c593d74SAnton Protopopov extra_fds[0] = new_map();
176*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[0], 0, "new_map"))
177*1c593d74SAnton Protopopov goto cleanup;
178*1c593d74SAnton Protopopov extra_fds[1] = new_map();
179*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[1], 0, "new_map"))
180*1c593d74SAnton Protopopov goto cleanup;
181*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 2);
182*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "BPF_PROG_LOAD"))
183*1c593d74SAnton Protopopov goto cleanup;
184*1c593d74SAnton Protopopov nr_map_ids = ARRAY_SIZE(map_ids);
185*1c593d74SAnton Protopopov if (!check_expected_map_ids(prog_fd, 3, map_ids, &nr_map_ids))
186*1c593d74SAnton Protopopov goto cleanup;
187*1c593d74SAnton Protopopov
188*1c593d74SAnton Protopopov /* maps should still exist when original file descriptors are closed */
189*1c593d74SAnton Protopopov Close(extra_fds[0]);
190*1c593d74SAnton Protopopov Close(extra_fds[1]);
191*1c593d74SAnton Protopopov if (!ASSERT_EQ(map_exists(map_ids[0]), true, "map_ids[0] should exist"))
192*1c593d74SAnton Protopopov goto cleanup;
193*1c593d74SAnton Protopopov if (!ASSERT_EQ(map_exists(map_ids[1]), true, "map_ids[1] should exist"))
194*1c593d74SAnton Protopopov goto cleanup;
195*1c593d74SAnton Protopopov
196*1c593d74SAnton Protopopov /* some fds might be invalid, so ignore return codes */
197*1c593d74SAnton Protopopov cleanup:
198*1c593d74SAnton Protopopov Close(extra_fds[1]);
199*1c593d74SAnton Protopopov Close(extra_fds[0]);
200*1c593d74SAnton Protopopov Close(prog_fd);
201*1c593d74SAnton Protopopov }
202*1c593d74SAnton Protopopov
203*1c593d74SAnton Protopopov /*
204*1c593d74SAnton Protopopov * Load a program with a few extra maps duplicated in the fd_array.
205*1c593d74SAnton Protopopov * After the load maps should only be referenced once.
206*1c593d74SAnton Protopopov */
check_fd_array_cnt__duplicated_maps(void)207*1c593d74SAnton Protopopov static void check_fd_array_cnt__duplicated_maps(void)
208*1c593d74SAnton Protopopov {
209*1c593d74SAnton Protopopov int extra_fds[4] = { -1, -1, -1, -1 };
210*1c593d74SAnton Protopopov __u32 map_ids[16];
211*1c593d74SAnton Protopopov __u32 nr_map_ids;
212*1c593d74SAnton Protopopov int prog_fd = -1;
213*1c593d74SAnton Protopopov
214*1c593d74SAnton Protopopov extra_fds[0] = extra_fds[2] = new_map();
215*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[0], 0, "new_map"))
216*1c593d74SAnton Protopopov goto cleanup;
217*1c593d74SAnton Protopopov extra_fds[1] = extra_fds[3] = new_map();
218*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[1], 0, "new_map"))
219*1c593d74SAnton Protopopov goto cleanup;
220*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 4);
221*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "BPF_PROG_LOAD"))
222*1c593d74SAnton Protopopov goto cleanup;
223*1c593d74SAnton Protopopov nr_map_ids = ARRAY_SIZE(map_ids);
224*1c593d74SAnton Protopopov if (!check_expected_map_ids(prog_fd, 3, map_ids, &nr_map_ids))
225*1c593d74SAnton Protopopov goto cleanup;
226*1c593d74SAnton Protopopov
227*1c593d74SAnton Protopopov /* maps should still exist when original file descriptors are closed */
228*1c593d74SAnton Protopopov Close(extra_fds[0]);
229*1c593d74SAnton Protopopov Close(extra_fds[1]);
230*1c593d74SAnton Protopopov if (!ASSERT_EQ(map_exists(map_ids[0]), true, "map should exist"))
231*1c593d74SAnton Protopopov goto cleanup;
232*1c593d74SAnton Protopopov if (!ASSERT_EQ(map_exists(map_ids[1]), true, "map should exist"))
233*1c593d74SAnton Protopopov goto cleanup;
234*1c593d74SAnton Protopopov
235*1c593d74SAnton Protopopov /* some fds might be invalid, so ignore return codes */
236*1c593d74SAnton Protopopov cleanup:
237*1c593d74SAnton Protopopov Close(extra_fds[1]);
238*1c593d74SAnton Protopopov Close(extra_fds[0]);
239*1c593d74SAnton Protopopov Close(prog_fd);
240*1c593d74SAnton Protopopov }
241*1c593d74SAnton Protopopov
242*1c593d74SAnton Protopopov /*
243*1c593d74SAnton Protopopov * Check that if maps which are referenced by a program are
244*1c593d74SAnton Protopopov * passed in fd_array, then they will be referenced only once
245*1c593d74SAnton Protopopov */
check_fd_array_cnt__referenced_maps_in_fd_array(void)246*1c593d74SAnton Protopopov static void check_fd_array_cnt__referenced_maps_in_fd_array(void)
247*1c593d74SAnton Protopopov {
248*1c593d74SAnton Protopopov int extra_fds[1] = { -1 };
249*1c593d74SAnton Protopopov __u32 map_ids[16];
250*1c593d74SAnton Protopopov __u32 nr_map_ids;
251*1c593d74SAnton Protopopov int prog_fd = -1;
252*1c593d74SAnton Protopopov
253*1c593d74SAnton Protopopov extra_fds[0] = new_map();
254*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[0], 0, "new_map"))
255*1c593d74SAnton Protopopov goto cleanup;
256*1c593d74SAnton Protopopov prog_fd = __load_test_prog(extra_fds[0], extra_fds, 1);
257*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "BPF_PROG_LOAD"))
258*1c593d74SAnton Protopopov goto cleanup;
259*1c593d74SAnton Protopopov nr_map_ids = ARRAY_SIZE(map_ids);
260*1c593d74SAnton Protopopov if (!check_expected_map_ids(prog_fd, 1, map_ids, &nr_map_ids))
261*1c593d74SAnton Protopopov goto cleanup;
262*1c593d74SAnton Protopopov
263*1c593d74SAnton Protopopov /* map should still exist when original file descriptor is closed */
264*1c593d74SAnton Protopopov Close(extra_fds[0]);
265*1c593d74SAnton Protopopov if (!ASSERT_EQ(map_exists(map_ids[0]), true, "map should exist"))
266*1c593d74SAnton Protopopov goto cleanup;
267*1c593d74SAnton Protopopov
268*1c593d74SAnton Protopopov /* some fds might be invalid, so ignore return codes */
269*1c593d74SAnton Protopopov cleanup:
270*1c593d74SAnton Protopopov Close(extra_fds[0]);
271*1c593d74SAnton Protopopov Close(prog_fd);
272*1c593d74SAnton Protopopov }
273*1c593d74SAnton Protopopov
get_btf_id_by_fd(int btf_fd,__u32 * id)274*1c593d74SAnton Protopopov static int get_btf_id_by_fd(int btf_fd, __u32 *id)
275*1c593d74SAnton Protopopov {
276*1c593d74SAnton Protopopov struct bpf_btf_info info;
277*1c593d74SAnton Protopopov __u32 info_len = sizeof(info);
278*1c593d74SAnton Protopopov int err;
279*1c593d74SAnton Protopopov
280*1c593d74SAnton Protopopov memset(&info, 0, info_len);
281*1c593d74SAnton Protopopov err = bpf_btf_get_info_by_fd(btf_fd, &info, &info_len);
282*1c593d74SAnton Protopopov if (err)
283*1c593d74SAnton Protopopov return err;
284*1c593d74SAnton Protopopov if (id)
285*1c593d74SAnton Protopopov *id = info.id;
286*1c593d74SAnton Protopopov return 0;
287*1c593d74SAnton Protopopov }
288*1c593d74SAnton Protopopov
289*1c593d74SAnton Protopopov /*
290*1c593d74SAnton Protopopov * Check that fd_array operates properly for btfs. Namely, to check that
291*1c593d74SAnton Protopopov * passing a btf fd in fd_array increases its reference count, do the
292*1c593d74SAnton Protopopov * following:
293*1c593d74SAnton Protopopov * 1) Create a new btf, it's referenced only by a file descriptor, so refcnt=1
294*1c593d74SAnton Protopopov * 2) Load a BPF prog with fd_array[0] = btf_fd; now btf's refcnt=2
295*1c593d74SAnton Protopopov * 3) Close the btf_fd, now refcnt=1
296*1c593d74SAnton Protopopov * Wait and check that BTF stil exists.
297*1c593d74SAnton Protopopov */
check_fd_array_cnt__referenced_btfs(void)298*1c593d74SAnton Protopopov static void check_fd_array_cnt__referenced_btfs(void)
299*1c593d74SAnton Protopopov {
300*1c593d74SAnton Protopopov int extra_fds[1] = { -1 };
301*1c593d74SAnton Protopopov int prog_fd = -1;
302*1c593d74SAnton Protopopov __u32 btf_id;
303*1c593d74SAnton Protopopov int tries;
304*1c593d74SAnton Protopopov int err;
305*1c593d74SAnton Protopopov
306*1c593d74SAnton Protopopov extra_fds[0] = new_btf();
307*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[0], 0, "new_btf"))
308*1c593d74SAnton Protopopov goto cleanup;
309*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 1);
310*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "BPF_PROG_LOAD"))
311*1c593d74SAnton Protopopov goto cleanup;
312*1c593d74SAnton Protopopov
313*1c593d74SAnton Protopopov /* btf should still exist when original file descriptor is closed */
314*1c593d74SAnton Protopopov err = get_btf_id_by_fd(extra_fds[0], &btf_id);
315*1c593d74SAnton Protopopov if (!ASSERT_GE(err, 0, "get_btf_id_by_fd"))
316*1c593d74SAnton Protopopov goto cleanup;
317*1c593d74SAnton Protopopov
318*1c593d74SAnton Protopopov Close(extra_fds[0]);
319*1c593d74SAnton Protopopov
320*1c593d74SAnton Protopopov if (!ASSERT_GE(kern_sync_rcu(), 0, "kern_sync_rcu 1"))
321*1c593d74SAnton Protopopov goto cleanup;
322*1c593d74SAnton Protopopov
323*1c593d74SAnton Protopopov if (!ASSERT_EQ(btf_exists(btf_id), true, "btf should exist"))
324*1c593d74SAnton Protopopov goto cleanup;
325*1c593d74SAnton Protopopov
326*1c593d74SAnton Protopopov Close(prog_fd);
327*1c593d74SAnton Protopopov
328*1c593d74SAnton Protopopov /* The program is freed by a workqueue, so no reliable
329*1c593d74SAnton Protopopov * way to sync, so just wait a bit (max ~1 second). */
330*1c593d74SAnton Protopopov for (tries = 100; tries >= 0; tries--) {
331*1c593d74SAnton Protopopov usleep(1000);
332*1c593d74SAnton Protopopov
333*1c593d74SAnton Protopopov if (!btf_exists(btf_id))
334*1c593d74SAnton Protopopov break;
335*1c593d74SAnton Protopopov
336*1c593d74SAnton Protopopov if (tries)
337*1c593d74SAnton Protopopov continue;
338*1c593d74SAnton Protopopov
339*1c593d74SAnton Protopopov PRINT_FAIL("btf should have been freed");
340*1c593d74SAnton Protopopov }
341*1c593d74SAnton Protopopov
342*1c593d74SAnton Protopopov /* some fds might be invalid, so ignore return codes */
343*1c593d74SAnton Protopopov cleanup:
344*1c593d74SAnton Protopopov Close(extra_fds[0]);
345*1c593d74SAnton Protopopov Close(prog_fd);
346*1c593d74SAnton Protopopov }
347*1c593d74SAnton Protopopov
348*1c593d74SAnton Protopopov /*
349*1c593d74SAnton Protopopov * Test that a program with trash in fd_array can't be loaded:
350*1c593d74SAnton Protopopov * only map and BTF file descriptors should be accepted.
351*1c593d74SAnton Protopopov */
check_fd_array_cnt__fd_array_with_trash(void)352*1c593d74SAnton Protopopov static void check_fd_array_cnt__fd_array_with_trash(void)
353*1c593d74SAnton Protopopov {
354*1c593d74SAnton Protopopov int extra_fds[3] = { -1, -1, -1 };
355*1c593d74SAnton Protopopov int prog_fd = -1;
356*1c593d74SAnton Protopopov
357*1c593d74SAnton Protopopov extra_fds[0] = new_map();
358*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[0], 0, "new_map"))
359*1c593d74SAnton Protopopov goto cleanup;
360*1c593d74SAnton Protopopov extra_fds[1] = new_btf();
361*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[1], 0, "new_btf"))
362*1c593d74SAnton Protopopov goto cleanup;
363*1c593d74SAnton Protopopov
364*1c593d74SAnton Protopopov /* trash 1: not a file descriptor */
365*1c593d74SAnton Protopopov extra_fds[2] = 0xbeef;
366*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 3);
367*1c593d74SAnton Protopopov if (!ASSERT_EQ(prog_fd, -EBADF, "prog should have been rejected with -EBADF"))
368*1c593d74SAnton Protopopov goto cleanup;
369*1c593d74SAnton Protopopov
370*1c593d74SAnton Protopopov /* trash 2: not a map or btf */
371*1c593d74SAnton Protopopov extra_fds[2] = socket(AF_INET, SOCK_STREAM, 0);
372*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[2], 0, "socket"))
373*1c593d74SAnton Protopopov goto cleanup;
374*1c593d74SAnton Protopopov
375*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 3);
376*1c593d74SAnton Protopopov if (!ASSERT_EQ(prog_fd, -EINVAL, "prog should have been rejected with -EINVAL"))
377*1c593d74SAnton Protopopov goto cleanup;
378*1c593d74SAnton Protopopov
379*1c593d74SAnton Protopopov /* Validate that the prog is ok if trash is removed */
380*1c593d74SAnton Protopopov Close(extra_fds[2]);
381*1c593d74SAnton Protopopov extra_fds[2] = new_btf();
382*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[2], 0, "new_btf"))
383*1c593d74SAnton Protopopov goto cleanup;
384*1c593d74SAnton Protopopov
385*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 3);
386*1c593d74SAnton Protopopov if (!ASSERT_GE(prog_fd, 0, "prog should have been loaded"))
387*1c593d74SAnton Protopopov goto cleanup;
388*1c593d74SAnton Protopopov
389*1c593d74SAnton Protopopov /* some fds might be invalid, so ignore return codes */
390*1c593d74SAnton Protopopov cleanup:
391*1c593d74SAnton Protopopov Close(extra_fds[2]);
392*1c593d74SAnton Protopopov Close(extra_fds[1]);
393*1c593d74SAnton Protopopov Close(extra_fds[0]);
394*1c593d74SAnton Protopopov }
395*1c593d74SAnton Protopopov
396*1c593d74SAnton Protopopov /*
397*1c593d74SAnton Protopopov * Test that a program with too big fd_array can't be loaded.
398*1c593d74SAnton Protopopov */
check_fd_array_cnt__fd_array_too_big(void)399*1c593d74SAnton Protopopov static void check_fd_array_cnt__fd_array_too_big(void)
400*1c593d74SAnton Protopopov {
401*1c593d74SAnton Protopopov int extra_fds[65];
402*1c593d74SAnton Protopopov int prog_fd = -1;
403*1c593d74SAnton Protopopov int i;
404*1c593d74SAnton Protopopov
405*1c593d74SAnton Protopopov for (i = 0; i < 65; i++) {
406*1c593d74SAnton Protopopov extra_fds[i] = new_map();
407*1c593d74SAnton Protopopov if (!ASSERT_GE(extra_fds[i], 0, "new_map"))
408*1c593d74SAnton Protopopov goto cleanup_fds;
409*1c593d74SAnton Protopopov }
410*1c593d74SAnton Protopopov
411*1c593d74SAnton Protopopov prog_fd = load_test_prog(extra_fds, 65);
412*1c593d74SAnton Protopopov ASSERT_EQ(prog_fd, -E2BIG, "prog should have been rejected with -E2BIG");
413*1c593d74SAnton Protopopov
414*1c593d74SAnton Protopopov cleanup_fds:
415*1c593d74SAnton Protopopov while (i > 0)
416*1c593d74SAnton Protopopov Close(extra_fds[--i]);
417*1c593d74SAnton Protopopov }
418*1c593d74SAnton Protopopov
test_fd_array_cnt(void)419*1c593d74SAnton Protopopov void test_fd_array_cnt(void)
420*1c593d74SAnton Protopopov {
421*1c593d74SAnton Protopopov if (test__start_subtest("no-fd-array"))
422*1c593d74SAnton Protopopov check_fd_array_cnt__no_fd_array();
423*1c593d74SAnton Protopopov
424*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-ok"))
425*1c593d74SAnton Protopopov check_fd_array_cnt__fd_array_ok();
426*1c593d74SAnton Protopopov
427*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-dup-input"))
428*1c593d74SAnton Protopopov check_fd_array_cnt__duplicated_maps();
429*1c593d74SAnton Protopopov
430*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-ref-maps-in-array"))
431*1c593d74SAnton Protopopov check_fd_array_cnt__referenced_maps_in_fd_array();
432*1c593d74SAnton Protopopov
433*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-ref-btfs"))
434*1c593d74SAnton Protopopov check_fd_array_cnt__referenced_btfs();
435*1c593d74SAnton Protopopov
436*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-trash-input"))
437*1c593d74SAnton Protopopov check_fd_array_cnt__fd_array_with_trash();
438*1c593d74SAnton Protopopov
439*1c593d74SAnton Protopopov if (test__start_subtest("fd-array-2big"))
440*1c593d74SAnton Protopopov check_fd_array_cnt__fd_array_too_big();
441*1c593d74SAnton Protopopov }
442