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