xref: /linux/tools/testing/selftests/bpf/prog_tests/fd_array.c (revision d0d106a2bd21499901299160744e5fe9f4c83ddb)
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