Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2019 Facebook */
  3#include <test_progs.h>
  4#include <network_helpers.h>
  5#include <bpf/btf.h>
  6
  7typedef int (*test_cb)(struct bpf_object *obj);
  8
  9static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)
 10{
 11	struct bpf_map *data_map = NULL, *map;
 12	__u64 *result = NULL;
 13	const int zero = 0;
 14	__u32 duration = 0;
 15	int ret = -1, i;
 16
 17	result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
 18	if (CHECK(!result, "alloc_memory", "failed to alloc memory"))
 19		return -ENOMEM;
 20
 21	bpf_object__for_each_map(map, obj)
 22		if (bpf_map__is_internal(map)) {
 23			data_map = map;
 24			break;
 25		}
 26	if (CHECK(!data_map, "find_data_map", "data map not found\n"))
 27		goto out;
 28
 29	ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
 30	if (CHECK(ret, "get_result",
 31		  "failed to get output data: %d\n", ret))
 32		goto out;
 33
 34	for (i = 0; i < prog_cnt; i++) {
 35		if (CHECK(result[i] != 1, "result",
 36			  "fexit_bpf2bpf result[%d] failed err %llu\n",
 37			  i, result[i]))
 38			goto out;
 39		result[i] = 0;
 40	}
 41	if (reset) {
 42		ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0);
 43		if (CHECK(ret, "reset_result", "failed to reset result\n"))
 44			goto out;
 45	}
 46
 47	ret = 0;
 48out:
 49	free(result);
 50	return ret;
 51}
 52
 53static void test_fexit_bpf2bpf_common(const char *obj_file,
 54				      const char *target_obj_file,
 55				      int prog_cnt,
 56				      const char **prog_name,
 57				      bool run_prog,
 58				      test_cb cb)
 59{
 60	struct bpf_object *obj = NULL, *tgt_obj;
 61	__u32 retval, tgt_prog_id, info_len;
 62	struct bpf_prog_info prog_info = {};
 63	struct bpf_program **prog = NULL;
 64	struct bpf_link **link = NULL;
 65	int err, tgt_fd, i;
 66	struct btf *btf;
 67
 68	err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
 69			    &tgt_obj, &tgt_fd);
 70	if (!ASSERT_OK(err, "tgt_prog_load"))
 71		return;
 72	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
 73			    .attach_prog_fd = tgt_fd,
 74			   );
 75
 76	info_len = sizeof(prog_info);
 77	err = bpf_obj_get_info_by_fd(tgt_fd, &prog_info, &info_len);
 78	if (!ASSERT_OK(err, "tgt_fd_get_info"))
 79		goto close_prog;
 80
 81	tgt_prog_id = prog_info.id;
 82	btf = bpf_object__btf(tgt_obj);
 83
 84	link = calloc(sizeof(struct bpf_link *), prog_cnt);
 85	if (!ASSERT_OK_PTR(link, "link_ptr"))
 86		goto close_prog;
 87
 88	prog = calloc(sizeof(struct bpf_program *), prog_cnt);
 89	if (!ASSERT_OK_PTR(prog, "prog_ptr"))
 90		goto close_prog;
 91
 92	obj = bpf_object__open_file(obj_file, &opts);
 93	if (!ASSERT_OK_PTR(obj, "obj_open"))
 94		goto close_prog;
 95
 96	err = bpf_object__load(obj);
 97	if (!ASSERT_OK(err, "obj_load"))
 98		goto close_prog;
 99
100	for (i = 0; i < prog_cnt; i++) {
101		struct bpf_link_info link_info;
102		char *tgt_name;
103		__s32 btf_id;
104
105		tgt_name = strstr(prog_name[i], "/");
106		if (!ASSERT_OK_PTR(tgt_name, "tgt_name"))
107			goto close_prog;
108		btf_id = btf__find_by_name_kind(btf, tgt_name + 1, BTF_KIND_FUNC);
109
110		prog[i] = bpf_object__find_program_by_title(obj, prog_name[i]);
111		if (!ASSERT_OK_PTR(prog[i], prog_name[i]))
112			goto close_prog;
113
114		link[i] = bpf_program__attach_trace(prog[i]);
115		if (!ASSERT_OK_PTR(link[i], "attach_trace"))
116			goto close_prog;
117
118		info_len = sizeof(link_info);
119		memset(&link_info, 0, sizeof(link_info));
120		err = bpf_obj_get_info_by_fd(bpf_link__fd(link[i]),
121					     &link_info, &info_len);
122		ASSERT_OK(err, "link_fd_get_info");
123		ASSERT_EQ(link_info.tracing.attach_type,
124			  bpf_program__get_expected_attach_type(prog[i]),
125			  "link_attach_type");
126		ASSERT_EQ(link_info.tracing.target_obj_id, tgt_prog_id, "link_tgt_obj_id");
127		ASSERT_EQ(link_info.tracing.target_btf_id, btf_id, "link_tgt_btf_id");
128	}
129
130	if (cb) {
131		err = cb(obj);
132		if (err)
133			goto close_prog;
134	}
135
136	if (!run_prog)
137		goto close_prog;
138
139	err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
140				NULL, NULL, &retval, NULL);
141	ASSERT_OK(err, "prog_run");
142	ASSERT_EQ(retval, 0, "prog_run_ret");
143
144	if (check_data_map(obj, prog_cnt, false))
145		goto close_prog;
146
147close_prog:
148	for (i = 0; i < prog_cnt; i++)
149		bpf_link__destroy(link[i]);
150	bpf_object__close(obj);
151	bpf_object__close(tgt_obj);
152	free(link);
153	free(prog);
154}
155
156static void test_target_no_callees(void)
157{
158	const char *prog_name[] = {
159		"fexit/test_pkt_md_access",
160	};
161	test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
162				  "./test_pkt_md_access.o",
163				  ARRAY_SIZE(prog_name),
164				  prog_name, true, NULL);
165}
166
167static void test_target_yes_callees(void)
168{
169	const char *prog_name[] = {
170		"fexit/test_pkt_access",
171		"fexit/test_pkt_access_subprog1",
172		"fexit/test_pkt_access_subprog2",
173		"fexit/test_pkt_access_subprog3",
174	};
175	test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
176				  "./test_pkt_access.o",
177				  ARRAY_SIZE(prog_name),
178				  prog_name, true, NULL);
179}
180
181static void test_func_replace(void)
182{
183	const char *prog_name[] = {
184		"fexit/test_pkt_access",
185		"fexit/test_pkt_access_subprog1",
186		"fexit/test_pkt_access_subprog2",
187		"fexit/test_pkt_access_subprog3",
188		"freplace/get_skb_len",
189		"freplace/get_skb_ifindex",
190		"freplace/get_constant",
191		"freplace/test_pkt_write_access_subprog",
192	};
193	test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
194				  "./test_pkt_access.o",
195				  ARRAY_SIZE(prog_name),
196				  prog_name, true, NULL);
197}
198
199static void test_func_replace_verify(void)
200{
201	const char *prog_name[] = {
202		"freplace/do_bind",
203	};
204	test_fexit_bpf2bpf_common("./freplace_connect4.o",
205				  "./connect4_prog.o",
206				  ARRAY_SIZE(prog_name),
207				  prog_name, false, NULL);
208}
209
210static int test_second_attach(struct bpf_object *obj)
211{
212	const char *prog_name = "freplace/get_constant";
213	const char *tgt_name = prog_name + 9; /* cut off freplace/ */
214	const char *tgt_obj_file = "./test_pkt_access.o";
215	struct bpf_program *prog = NULL;
216	struct bpf_object *tgt_obj;
217	__u32 duration = 0, retval;
218	struct bpf_link *link;
219	int err = 0, tgt_fd;
220
221	prog = bpf_object__find_program_by_title(obj, prog_name);
222	if (CHECK(!prog, "find_prog", "prog %s not found\n", prog_name))
223		return -ENOENT;
224
225	err = bpf_prog_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,
226			    &tgt_obj, &tgt_fd);
227	if (CHECK(err, "second_prog_load", "file %s err %d errno %d\n",
228		  tgt_obj_file, err, errno))
229		return err;
230
231	link = bpf_program__attach_freplace(prog, tgt_fd, tgt_name);
232	if (!ASSERT_OK_PTR(link, "second_link"))
233		goto out;
234
235	err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
236				NULL, NULL, &retval, &duration);
237	if (CHECK(err || retval, "ipv6",
238		  "err %d errno %d retval %d duration %d\n",
239		  err, errno, retval, duration))
240		goto out;
241
242	err = check_data_map(obj, 1, true);
243	if (err)
244		goto out;
245
246out:
247	bpf_link__destroy(link);
248	bpf_object__close(tgt_obj);
249	return err;
250}
251
252static void test_func_replace_multi(void)
253{
254	const char *prog_name[] = {
255		"freplace/get_constant",
256	};
257	test_fexit_bpf2bpf_common("./freplace_get_constant.o",
258				  "./test_pkt_access.o",
259				  ARRAY_SIZE(prog_name),
260				  prog_name, true, test_second_attach);
261}
262
263static void test_fmod_ret_freplace(void)
264{
265	struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;
266	const char *freplace_name = "./freplace_get_constant.o";
267	const char *fmod_ret_name = "./fmod_ret_freplace.o";
268	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
269	const char *tgt_name = "./test_pkt_access.o";
270	struct bpf_link *freplace_link = NULL;
271	struct bpf_program *prog;
272	__u32 duration = 0;
273	int err, pkt_fd;
274
275	err = bpf_prog_load(tgt_name, BPF_PROG_TYPE_UNSPEC,
276			    &pkt_obj, &pkt_fd);
277	/* the target prog should load fine */
278	if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
279		  tgt_name, err, errno))
280		return;
281	opts.attach_prog_fd = pkt_fd;
282
283	freplace_obj = bpf_object__open_file(freplace_name, &opts);
284	if (!ASSERT_OK_PTR(freplace_obj, "freplace_obj_open"))
285		goto out;
286
287	err = bpf_object__load(freplace_obj);
288	if (CHECK(err, "freplace_obj_load", "err %d\n", err))
289		goto out;
290
291	prog = bpf_program__next(NULL, freplace_obj);
292	freplace_link = bpf_program__attach_trace(prog);
293	if (!ASSERT_OK_PTR(freplace_link, "freplace_attach_trace"))
294		goto out;
295
296	opts.attach_prog_fd = bpf_program__fd(prog);
297	fmod_obj = bpf_object__open_file(fmod_ret_name, &opts);
298	if (!ASSERT_OK_PTR(fmod_obj, "fmod_obj_open"))
299		goto out;
300
301	err = bpf_object__load(fmod_obj);
302	if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n"))
303		goto out;
304
305out:
306	bpf_link__destroy(freplace_link);
307	bpf_object__close(freplace_obj);
308	bpf_object__close(fmod_obj);
309	bpf_object__close(pkt_obj);
310}
311
312
313static void test_func_sockmap_update(void)
314{
315	const char *prog_name[] = {
316		"freplace/cls_redirect",
317	};
318	test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",
319				  "./test_cls_redirect.o",
320				  ARRAY_SIZE(prog_name),
321				  prog_name, false, NULL);
322}
323
324static void test_obj_load_failure_common(const char *obj_file,
325					  const char *target_obj_file)
326
327{
328	/*
329	 * standalone test that asserts failure to load freplace prog
330	 * because of invalid return code.
331	 */
332	struct bpf_object *obj = NULL, *pkt_obj;
333	int err, pkt_fd;
334	__u32 duration = 0;
335
336	err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
337			    &pkt_obj, &pkt_fd);
338	/* the target prog should load fine */
339	if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
340		  target_obj_file, err, errno))
341		return;
342	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
343			    .attach_prog_fd = pkt_fd,
344			   );
345
346	obj = bpf_object__open_file(obj_file, &opts);
347	if (!ASSERT_OK_PTR(obj, "obj_open"))
348		goto close_prog;
349
350	/* It should fail to load the program */
351	err = bpf_object__load(obj);
352	if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err))
353		goto close_prog;
354
355close_prog:
356	bpf_object__close(obj);
357	bpf_object__close(pkt_obj);
358}
359
360static void test_func_replace_return_code(void)
361{
362	/* test invalid return code in the replaced program */
363	test_obj_load_failure_common("./freplace_connect_v4_prog.o",
364				     "./connect4_prog.o");
365}
366
367static void test_func_map_prog_compatibility(void)
368{
369	/* test with spin lock map value in the replaced program */
370	test_obj_load_failure_common("./freplace_attach_probe.o",
371				     "./test_attach_probe.o");
372}
373
374void test_fexit_bpf2bpf(void)
375{
376	if (test__start_subtest("target_no_callees"))
377		test_target_no_callees();
378	if (test__start_subtest("target_yes_callees"))
379		test_target_yes_callees();
380	if (test__start_subtest("func_replace"))
381		test_func_replace();
382	if (test__start_subtest("func_replace_verify"))
383		test_func_replace_verify();
384	if (test__start_subtest("func_sockmap_update"))
385		test_func_sockmap_update();
386	if (test__start_subtest("func_replace_return_code"))
387		test_func_replace_return_code();
388	if (test__start_subtest("func_map_prog_compatibility"))
389		test_func_map_prog_compatibility();
390	if (test__start_subtest("func_replace_multi"))
391		test_func_replace_multi();
392	if (test__start_subtest("fmod_ret_freplace"))
393		test_fmod_ret_freplace();
394}