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
print_verifier_log(const char * log)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
test_aux(const char * main_prog_name,const char * to_be_replaced,const char * replacement,bool expect_load,const char * err_msg)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 */
test_summarization_freplace(void)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