xref: /linux/tools/testing/selftests/bpf/prog_tests/summarization.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "bpf/libbpf.h"
3 #include "summarization_freplace.skel.h"
4 #include "summarization.skel.h"
5 #include <test_progs.h>
6 
7 static void print_verifier_log(const char *log)
8 {
9 	if (env.verbosity >= VERBOSE_VERY)
10 		fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log);
11 }
12 
13 static void test_aux(const char *main_prog_name,
14 		     const char *to_be_replaced,
15 		     const char *replacement,
16 		     bool expect_load,
17 		     const char *err_msg)
18 {
19 	struct summarization_freplace *freplace = NULL;
20 	struct bpf_program *freplace_prog = NULL;
21 	struct bpf_program *main_prog = NULL;
22 	LIBBPF_OPTS(bpf_object_open_opts, opts);
23 	struct summarization *main = NULL;
24 	char log[16*1024];
25 	int err;
26 
27 	opts.kernel_log_buf = log;
28 	opts.kernel_log_size = sizeof(log);
29 	if (env.verbosity >= VERBOSE_SUPER)
30 		opts.kernel_log_level = 1 | 2 | 4;
31 	main = summarization__open_opts(&opts);
32 	if (!ASSERT_OK_PTR(main, "summarization__open"))
33 		goto out;
34 	main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name);
35 	if (!ASSERT_OK_PTR(main_prog, "main_prog"))
36 		goto out;
37 	bpf_program__set_autoload(main_prog, true);
38 	err = summarization__load(main);
39 	print_verifier_log(log);
40 	if (!ASSERT_OK(err, "summarization__load"))
41 		goto out;
42 	freplace = summarization_freplace__open_opts(&opts);
43 	if (!ASSERT_OK_PTR(freplace, "summarization_freplace__open"))
44 		goto out;
45 	freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement);
46 	if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog"))
47 		goto out;
48 	bpf_program__set_autoload(freplace_prog, true);
49 	bpf_program__set_autoattach(freplace_prog, true);
50 	bpf_program__set_attach_target(freplace_prog,
51 				       bpf_program__fd(main_prog),
52 				       to_be_replaced);
53 	err = summarization_freplace__load(freplace);
54 	print_verifier_log(log);
55 
56 	/* The might_sleep extension doesn't work yet as sleepable calls are not
57 	 * allowed, but preserve the check in case it's supported later and then
58 	 * this particular combination can be enabled.
59 	 */
60 	if (!strcmp("might_sleep", replacement) && err) {
61 		ASSERT_HAS_SUBSTR(log, "helper call might sleep in a non-sleepable prog", "error log");
62 		ASSERT_EQ(err, -EINVAL, "err");
63 		test__skip();
64 		goto out;
65 	}
66 
67 	if (expect_load) {
68 		ASSERT_OK(err, "summarization_freplace__load");
69 	} else {
70 		ASSERT_ERR(err, "summarization_freplace__load");
71 		ASSERT_HAS_SUBSTR(log, err_msg, "error log");
72 	}
73 
74 out:
75 	summarization_freplace__destroy(freplace);
76 	summarization__destroy(main);
77 }
78 
79 /* There are two global subprograms in both summarization.skel.h:
80  * - one changes packet data;
81  * - another does not.
82  * It is ok to freplace subprograms that change packet data with those
83  * that either do or do not. It is only ok to freplace subprograms
84  * that do not change packet data with those that do not as well.
85  * The below tests check outcomes for each combination of such freplace.
86  * Also test a case when main subprogram itself is replaced and is a single
87  * subprogram in a program.
88  *
89  * This holds for might_sleep programs. It is ok to replace might_sleep with
90  * might_sleep and with does_not_sleep, but does_not_sleep cannot be replaced
91  * with might_sleep.
92  */
93 void test_summarization_freplace(void)
94 {
95 	struct {
96 		const char *main;
97 		const char *to_be_replaced;
98 		bool has_side_effect;
99 	} mains[2][4] = {
100 		{
101 			{ "main_changes_with_subprogs",		"changes_pkt_data",	    true },
102 			{ "main_changes_with_subprogs",		"does_not_change_pkt_data", false },
103 			{ "main_changes",			"main_changes",             true },
104 			{ "main_does_not_change",		"main_does_not_change",     false },
105 		},
106 		{
107 			{ "main_might_sleep_with_subprogs",	"might_sleep",		    true },
108 			{ "main_might_sleep_with_subprogs",	"does_not_sleep",	    false },
109 			{ "main_might_sleep",			"main_might_sleep",	    true },
110 			{ "main_does_not_sleep",		"main_does_not_sleep",	    false },
111 		},
112 	};
113 	const char *pkt_err = "Extension program changes packet data";
114 	const char *slp_err = "Extension program may sleep";
115 	struct {
116 		const char *func;
117 		bool has_side_effect;
118 		const char *err_msg;
119 	} replacements[2][2] = {
120 		{
121 			{ "changes_pkt_data",	      true,	pkt_err },
122 			{ "does_not_change_pkt_data", false,	pkt_err },
123 		},
124 		{
125 			{ "might_sleep",	      true,	slp_err },
126 			{ "does_not_sleep",	      false,	slp_err },
127 		},
128 	};
129 	char buf[64];
130 
131 	for (int t = 0; t < 2; t++) {
132 		for (int i = 0; i < ARRAY_SIZE(mains); ++i) {
133 			for (int j = 0; j < ARRAY_SIZE(replacements); ++j) {
134 				snprintf(buf, sizeof(buf), "%s_with_%s",
135 					 mains[t][i].to_be_replaced, replacements[t][j].func);
136 				if (!test__start_subtest(buf))
137 					continue;
138 				test_aux(mains[t][i].main, mains[t][i].to_be_replaced, replacements[t][j].func,
139 					 mains[t][i].has_side_effect || !replacements[t][j].has_side_effect,
140 					 replacements[t][j].err_msg);
141 			}
142 		}
143 	}
144 }
145