162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 362306a36Sopenharmony_ci#include <linux/capability.h> 462306a36Sopenharmony_ci#include <stdlib.h> 562306a36Sopenharmony_ci#include <test_progs.h> 662306a36Sopenharmony_ci#include <bpf/btf.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "autoconf_helper.h" 962306a36Sopenharmony_ci#include "unpriv_helpers.h" 1062306a36Sopenharmony_ci#include "cap_helpers.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define str_has_pfx(str, pfx) \ 1362306a36Sopenharmony_ci (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0) 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define TEST_LOADER_LOG_BUF_SZ 1048576 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure" 1862306a36Sopenharmony_ci#define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" 1962306a36Sopenharmony_ci#define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg=" 2062306a36Sopenharmony_ci#define TEST_TAG_EXPECT_FAILURE_UNPRIV "comment:test_expect_failure_unpriv" 2162306a36Sopenharmony_ci#define TEST_TAG_EXPECT_SUCCESS_UNPRIV "comment:test_expect_success_unpriv" 2262306a36Sopenharmony_ci#define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "comment:test_expect_msg_unpriv=" 2362306a36Sopenharmony_ci#define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level=" 2462306a36Sopenharmony_ci#define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags=" 2562306a36Sopenharmony_ci#define TEST_TAG_DESCRIPTION_PFX "comment:test_description=" 2662306a36Sopenharmony_ci#define TEST_TAG_RETVAL_PFX "comment:test_retval=" 2762306a36Sopenharmony_ci#define TEST_TAG_RETVAL_PFX_UNPRIV "comment:test_retval_unpriv=" 2862306a36Sopenharmony_ci#define TEST_TAG_AUXILIARY "comment:test_auxiliary" 2962306a36Sopenharmony_ci#define TEST_TAG_AUXILIARY_UNPRIV "comment:test_auxiliary_unpriv" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Warning: duplicated in bpf_misc.h */ 3262306a36Sopenharmony_ci#define POINTER_VALUE 0xcafe4all 3362306a36Sopenharmony_ci#define TEST_DATA_LEN 64 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 3662306a36Sopenharmony_ci#define EFFICIENT_UNALIGNED_ACCESS 1 3762306a36Sopenharmony_ci#else 3862306a36Sopenharmony_ci#define EFFICIENT_UNALIGNED_ACCESS 0 3962306a36Sopenharmony_ci#endif 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int sysctl_unpriv_disabled = -1; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cienum mode { 4462306a36Sopenharmony_ci PRIV = 1, 4562306a36Sopenharmony_ci UNPRIV = 2 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct test_subspec { 4962306a36Sopenharmony_ci char *name; 5062306a36Sopenharmony_ci bool expect_failure; 5162306a36Sopenharmony_ci const char **expect_msgs; 5262306a36Sopenharmony_ci size_t expect_msg_cnt; 5362306a36Sopenharmony_ci int retval; 5462306a36Sopenharmony_ci bool execute; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct test_spec { 5862306a36Sopenharmony_ci const char *prog_name; 5962306a36Sopenharmony_ci struct test_subspec priv; 6062306a36Sopenharmony_ci struct test_subspec unpriv; 6162306a36Sopenharmony_ci int log_level; 6262306a36Sopenharmony_ci int prog_flags; 6362306a36Sopenharmony_ci int mode_mask; 6462306a36Sopenharmony_ci bool auxiliary; 6562306a36Sopenharmony_ci bool valid; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int tester_init(struct test_loader *tester) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (!tester->log_buf) { 7162306a36Sopenharmony_ci tester->log_buf_sz = TEST_LOADER_LOG_BUF_SZ; 7262306a36Sopenharmony_ci tester->log_buf = malloc(tester->log_buf_sz); 7362306a36Sopenharmony_ci if (!ASSERT_OK_PTR(tester->log_buf, "tester_log_buf")) 7462306a36Sopenharmony_ci return -ENOMEM; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid test_loader_fini(struct test_loader *tester) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (!tester) 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci free(tester->log_buf); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void free_test_spec(struct test_spec *spec) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci free(spec->priv.name); 9162306a36Sopenharmony_ci free(spec->unpriv.name); 9262306a36Sopenharmony_ci free(spec->priv.expect_msgs); 9362306a36Sopenharmony_ci free(spec->unpriv.expect_msgs); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci spec->priv.name = NULL; 9662306a36Sopenharmony_ci spec->unpriv.name = NULL; 9762306a36Sopenharmony_ci spec->priv.expect_msgs = NULL; 9862306a36Sopenharmony_ci spec->unpriv.expect_msgs = NULL; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int push_msg(const char *msg, struct test_subspec *subspec) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci void *tmp; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci tmp = realloc(subspec->expect_msgs, (1 + subspec->expect_msg_cnt) * sizeof(void *)); 10662306a36Sopenharmony_ci if (!tmp) { 10762306a36Sopenharmony_ci ASSERT_FAIL("failed to realloc memory for messages\n"); 10862306a36Sopenharmony_ci return -ENOMEM; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci subspec->expect_msgs = tmp; 11162306a36Sopenharmony_ci subspec->expect_msgs[subspec->expect_msg_cnt++] = msg; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int parse_int(const char *str, int *val, const char *name) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci char *end; 11962306a36Sopenharmony_ci long tmp; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci errno = 0; 12262306a36Sopenharmony_ci if (str_has_pfx(str, "0x")) 12362306a36Sopenharmony_ci tmp = strtol(str + 2, &end, 16); 12462306a36Sopenharmony_ci else 12562306a36Sopenharmony_ci tmp = strtol(str, &end, 10); 12662306a36Sopenharmony_ci if (errno || end[0] != '\0') { 12762306a36Sopenharmony_ci PRINT_FAIL("failed to parse %s from '%s'\n", name, str); 12862306a36Sopenharmony_ci return -EINVAL; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci *val = tmp; 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int parse_retval(const char *str, int *val, const char *name) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct { 13762306a36Sopenharmony_ci char *name; 13862306a36Sopenharmony_ci int val; 13962306a36Sopenharmony_ci } named_values[] = { 14062306a36Sopenharmony_ci { "INT_MIN" , INT_MIN }, 14162306a36Sopenharmony_ci { "POINTER_VALUE", POINTER_VALUE }, 14262306a36Sopenharmony_ci { "TEST_DATA_LEN", TEST_DATA_LEN }, 14362306a36Sopenharmony_ci }; 14462306a36Sopenharmony_ci int i; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(named_values); ++i) { 14762306a36Sopenharmony_ci if (strcmp(str, named_values[i].name) != 0) 14862306a36Sopenharmony_ci continue; 14962306a36Sopenharmony_ci *val = named_values[i].val; 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return parse_int(str, val, name); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* Uses btf_decl_tag attributes to describe the expected test 15762306a36Sopenharmony_ci * behavior, see bpf_misc.h for detailed description of each attribute 15862306a36Sopenharmony_ci * and attribute combinations. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistatic int parse_test_spec(struct test_loader *tester, 16162306a36Sopenharmony_ci struct bpf_object *obj, 16262306a36Sopenharmony_ci struct bpf_program *prog, 16362306a36Sopenharmony_ci struct test_spec *spec) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci const char *description = NULL; 16662306a36Sopenharmony_ci bool has_unpriv_result = false; 16762306a36Sopenharmony_ci bool has_unpriv_retval = false; 16862306a36Sopenharmony_ci int func_id, i, err = 0; 16962306a36Sopenharmony_ci struct btf *btf; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci memset(spec, 0, sizeof(*spec)); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spec->prog_name = bpf_program__name(prog); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci btf = bpf_object__btf(obj); 17662306a36Sopenharmony_ci if (!btf) { 17762306a36Sopenharmony_ci ASSERT_FAIL("BPF object has no BTF"); 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci func_id = btf__find_by_name_kind(btf, spec->prog_name, BTF_KIND_FUNC); 18262306a36Sopenharmony_ci if (func_id < 0) { 18362306a36Sopenharmony_ci ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->prog_name); 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci for (i = 1; i < btf__type_cnt(btf); i++) { 18862306a36Sopenharmony_ci const char *s, *val, *msg; 18962306a36Sopenharmony_ci const struct btf_type *t; 19062306a36Sopenharmony_ci int tmp; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci t = btf__type_by_id(btf, i); 19362306a36Sopenharmony_ci if (!btf_is_decl_tag(t)) 19462306a36Sopenharmony_ci continue; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (t->type != func_id || btf_decl_tag(t)->component_idx != -1) 19762306a36Sopenharmony_ci continue; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci s = btf__str_by_offset(btf, t->name_off); 20062306a36Sopenharmony_ci if (str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX)) { 20162306a36Sopenharmony_ci description = s + sizeof(TEST_TAG_DESCRIPTION_PFX) - 1; 20262306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) { 20362306a36Sopenharmony_ci spec->priv.expect_failure = true; 20462306a36Sopenharmony_ci spec->mode_mask |= PRIV; 20562306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) { 20662306a36Sopenharmony_ci spec->priv.expect_failure = false; 20762306a36Sopenharmony_ci spec->mode_mask |= PRIV; 20862306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE_UNPRIV) == 0) { 20962306a36Sopenharmony_ci spec->unpriv.expect_failure = true; 21062306a36Sopenharmony_ci spec->mode_mask |= UNPRIV; 21162306a36Sopenharmony_ci has_unpriv_result = true; 21262306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS_UNPRIV) == 0) { 21362306a36Sopenharmony_ci spec->unpriv.expect_failure = false; 21462306a36Sopenharmony_ci spec->mode_mask |= UNPRIV; 21562306a36Sopenharmony_ci has_unpriv_result = true; 21662306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_AUXILIARY) == 0) { 21762306a36Sopenharmony_ci spec->auxiliary = true; 21862306a36Sopenharmony_ci spec->mode_mask |= PRIV; 21962306a36Sopenharmony_ci } else if (strcmp(s, TEST_TAG_AUXILIARY_UNPRIV) == 0) { 22062306a36Sopenharmony_ci spec->auxiliary = true; 22162306a36Sopenharmony_ci spec->mode_mask |= UNPRIV; 22262306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 22362306a36Sopenharmony_ci msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 22462306a36Sopenharmony_ci err = push_msg(msg, &spec->priv); 22562306a36Sopenharmony_ci if (err) 22662306a36Sopenharmony_ci goto cleanup; 22762306a36Sopenharmony_ci spec->mode_mask |= PRIV; 22862306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV)) { 22962306a36Sopenharmony_ci msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX_UNPRIV) - 1; 23062306a36Sopenharmony_ci err = push_msg(msg, &spec->unpriv); 23162306a36Sopenharmony_ci if (err) 23262306a36Sopenharmony_ci goto cleanup; 23362306a36Sopenharmony_ci spec->mode_mask |= UNPRIV; 23462306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX)) { 23562306a36Sopenharmony_ci val = s + sizeof(TEST_TAG_RETVAL_PFX) - 1; 23662306a36Sopenharmony_ci err = parse_retval(val, &spec->priv.retval, "__retval"); 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci goto cleanup; 23962306a36Sopenharmony_ci spec->priv.execute = true; 24062306a36Sopenharmony_ci spec->mode_mask |= PRIV; 24162306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_RETVAL_PFX_UNPRIV)) { 24262306a36Sopenharmony_ci val = s + sizeof(TEST_TAG_RETVAL_PFX_UNPRIV) - 1; 24362306a36Sopenharmony_ci err = parse_retval(val, &spec->unpriv.retval, "__retval_unpriv"); 24462306a36Sopenharmony_ci if (err) 24562306a36Sopenharmony_ci goto cleanup; 24662306a36Sopenharmony_ci spec->mode_mask |= UNPRIV; 24762306a36Sopenharmony_ci spec->unpriv.execute = true; 24862306a36Sopenharmony_ci has_unpriv_retval = true; 24962306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) { 25062306a36Sopenharmony_ci val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1; 25162306a36Sopenharmony_ci err = parse_int(val, &spec->log_level, "test log level"); 25262306a36Sopenharmony_ci if (err) 25362306a36Sopenharmony_ci goto cleanup; 25462306a36Sopenharmony_ci } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { 25562306a36Sopenharmony_ci val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; 25662306a36Sopenharmony_ci if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) { 25762306a36Sopenharmony_ci spec->prog_flags |= BPF_F_STRICT_ALIGNMENT; 25862306a36Sopenharmony_ci } else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) { 25962306a36Sopenharmony_ci spec->prog_flags |= BPF_F_ANY_ALIGNMENT; 26062306a36Sopenharmony_ci } else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) { 26162306a36Sopenharmony_ci spec->prog_flags |= BPF_F_TEST_RND_HI32; 26262306a36Sopenharmony_ci } else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) { 26362306a36Sopenharmony_ci spec->prog_flags |= BPF_F_TEST_STATE_FREQ; 26462306a36Sopenharmony_ci } else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) { 26562306a36Sopenharmony_ci spec->prog_flags |= BPF_F_SLEEPABLE; 26662306a36Sopenharmony_ci } else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) { 26762306a36Sopenharmony_ci spec->prog_flags |= BPF_F_XDP_HAS_FRAGS; 26862306a36Sopenharmony_ci } else /* assume numeric value */ { 26962306a36Sopenharmony_ci err = parse_int(val, &tmp, "test prog flags"); 27062306a36Sopenharmony_ci if (err) 27162306a36Sopenharmony_ci goto cleanup; 27262306a36Sopenharmony_ci spec->prog_flags |= tmp; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (spec->mode_mask == 0) 27862306a36Sopenharmony_ci spec->mode_mask = PRIV; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!description) 28162306a36Sopenharmony_ci description = spec->prog_name; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (spec->mode_mask & PRIV) { 28462306a36Sopenharmony_ci spec->priv.name = strdup(description); 28562306a36Sopenharmony_ci if (!spec->priv.name) { 28662306a36Sopenharmony_ci PRINT_FAIL("failed to allocate memory for priv.name\n"); 28762306a36Sopenharmony_ci err = -ENOMEM; 28862306a36Sopenharmony_ci goto cleanup; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (spec->mode_mask & UNPRIV) { 29362306a36Sopenharmony_ci int descr_len = strlen(description); 29462306a36Sopenharmony_ci const char *suffix = " @unpriv"; 29562306a36Sopenharmony_ci char *name; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci name = malloc(descr_len + strlen(suffix) + 1); 29862306a36Sopenharmony_ci if (!name) { 29962306a36Sopenharmony_ci PRINT_FAIL("failed to allocate memory for unpriv.name\n"); 30062306a36Sopenharmony_ci err = -ENOMEM; 30162306a36Sopenharmony_ci goto cleanup; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci strcpy(name, description); 30562306a36Sopenharmony_ci strcpy(&name[descr_len], suffix); 30662306a36Sopenharmony_ci spec->unpriv.name = name; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (spec->mode_mask & (PRIV | UNPRIV)) { 31062306a36Sopenharmony_ci if (!has_unpriv_result) 31162306a36Sopenharmony_ci spec->unpriv.expect_failure = spec->priv.expect_failure; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!has_unpriv_retval) { 31462306a36Sopenharmony_ci spec->unpriv.retval = spec->priv.retval; 31562306a36Sopenharmony_ci spec->unpriv.execute = spec->priv.execute; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!spec->unpriv.expect_msgs) { 31962306a36Sopenharmony_ci size_t sz = spec->priv.expect_msg_cnt * sizeof(void *); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spec->unpriv.expect_msgs = malloc(sz); 32262306a36Sopenharmony_ci if (!spec->unpriv.expect_msgs) { 32362306a36Sopenharmony_ci PRINT_FAIL("failed to allocate memory for unpriv.expect_msgs\n"); 32462306a36Sopenharmony_ci err = -ENOMEM; 32562306a36Sopenharmony_ci goto cleanup; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci memcpy(spec->unpriv.expect_msgs, spec->priv.expect_msgs, sz); 32862306a36Sopenharmony_ci spec->unpriv.expect_msg_cnt = spec->priv.expect_msg_cnt; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci spec->valid = true; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cicleanup: 33762306a36Sopenharmony_ci free_test_spec(spec); 33862306a36Sopenharmony_ci return err; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void prepare_case(struct test_loader *tester, 34262306a36Sopenharmony_ci struct test_spec *spec, 34362306a36Sopenharmony_ci struct bpf_object *obj, 34462306a36Sopenharmony_ci struct bpf_program *prog) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci int min_log_level = 0, prog_flags; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (env.verbosity > VERBOSE_NONE) 34962306a36Sopenharmony_ci min_log_level = 1; 35062306a36Sopenharmony_ci if (env.verbosity > VERBOSE_VERY) 35162306a36Sopenharmony_ci min_log_level = 2; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Make sure we set at least minimal log level, unless test requires 35662306a36Sopenharmony_ci * even higher level already. Make sure to preserve independent log 35762306a36Sopenharmony_ci * level 4 (verifier stats), though. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci if ((spec->log_level & 3) < min_log_level) 36062306a36Sopenharmony_ci bpf_program__set_log_level(prog, (spec->log_level & 4) | min_log_level); 36162306a36Sopenharmony_ci else 36262306a36Sopenharmony_ci bpf_program__set_log_level(prog, spec->log_level); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci prog_flags = bpf_program__flags(prog); 36562306a36Sopenharmony_ci bpf_program__set_flags(prog, prog_flags | spec->prog_flags); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci tester->log_buf[0] = '\0'; 36862306a36Sopenharmony_ci tester->next_match_pos = 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void emit_verifier_log(const char *log_buf, bool force) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci if (!force && env.verbosity == VERBOSE_NONE) 37462306a36Sopenharmony_ci return; 37562306a36Sopenharmony_ci fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void validate_case(struct test_loader *tester, 37962306a36Sopenharmony_ci struct test_subspec *subspec, 38062306a36Sopenharmony_ci struct bpf_object *obj, 38162306a36Sopenharmony_ci struct bpf_program *prog, 38262306a36Sopenharmony_ci int load_err) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int i, j; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci for (i = 0; i < subspec->expect_msg_cnt; i++) { 38762306a36Sopenharmony_ci char *match; 38862306a36Sopenharmony_ci const char *expect_msg; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci expect_msg = subspec->expect_msgs[i]; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci match = strstr(tester->log_buf + tester->next_match_pos, expect_msg); 39362306a36Sopenharmony_ci if (!ASSERT_OK_PTR(match, "expect_msg")) { 39462306a36Sopenharmony_ci /* if we are in verbose mode, we've already emitted log */ 39562306a36Sopenharmony_ci if (env.verbosity == VERBOSE_NONE) 39662306a36Sopenharmony_ci emit_verifier_log(tester->log_buf, true /*force*/); 39762306a36Sopenharmony_ci for (j = 0; j < i; j++) 39862306a36Sopenharmony_ci fprintf(stderr, 39962306a36Sopenharmony_ci "MATCHED MSG: '%s'\n", subspec->expect_msgs[j]); 40062306a36Sopenharmony_ci fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg); 40162306a36Sopenharmony_ci return; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci tester->next_match_pos = match - tester->log_buf + strlen(expect_msg); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistruct cap_state { 40962306a36Sopenharmony_ci __u64 old_caps; 41062306a36Sopenharmony_ci bool initialized; 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int drop_capabilities(struct cap_state *caps) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci const __u64 caps_to_drop = (1ULL << CAP_SYS_ADMIN | 1ULL << CAP_NET_ADMIN | 41662306a36Sopenharmony_ci 1ULL << CAP_PERFMON | 1ULL << CAP_BPF); 41762306a36Sopenharmony_ci int err; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci err = cap_disable_effective(caps_to_drop, &caps->old_caps); 42062306a36Sopenharmony_ci if (err) { 42162306a36Sopenharmony_ci PRINT_FAIL("failed to drop capabilities: %i, %s\n", err, strerror(err)); 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci caps->initialized = true; 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int restore_capabilities(struct cap_state *caps) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci int err; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (!caps->initialized) 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci err = cap_enable_effective(caps->old_caps, NULL); 43762306a36Sopenharmony_ci if (err) 43862306a36Sopenharmony_ci PRINT_FAIL("failed to restore capabilities: %i, %s\n", err, strerror(err)); 43962306a36Sopenharmony_ci caps->initialized = false; 44062306a36Sopenharmony_ci return err; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic bool can_execute_unpriv(struct test_loader *tester, struct test_spec *spec) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci if (sysctl_unpriv_disabled < 0) 44662306a36Sopenharmony_ci sysctl_unpriv_disabled = get_unpriv_disabled() ? 1 : 0; 44762306a36Sopenharmony_ci if (sysctl_unpriv_disabled) 44862306a36Sopenharmony_ci return false; 44962306a36Sopenharmony_ci if ((spec->prog_flags & BPF_F_ANY_ALIGNMENT) && !EFFICIENT_UNALIGNED_ACCESS) 45062306a36Sopenharmony_ci return false; 45162306a36Sopenharmony_ci return true; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic bool is_unpriv_capable_map(struct bpf_map *map) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci enum bpf_map_type type; 45762306a36Sopenharmony_ci __u32 flags; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci type = bpf_map__type(map); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci switch (type) { 46262306a36Sopenharmony_ci case BPF_MAP_TYPE_HASH: 46362306a36Sopenharmony_ci case BPF_MAP_TYPE_PERCPU_HASH: 46462306a36Sopenharmony_ci case BPF_MAP_TYPE_HASH_OF_MAPS: 46562306a36Sopenharmony_ci flags = bpf_map__map_flags(map); 46662306a36Sopenharmony_ci return !(flags & BPF_F_ZERO_SEED); 46762306a36Sopenharmony_ci case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: 46862306a36Sopenharmony_ci case BPF_MAP_TYPE_ARRAY: 46962306a36Sopenharmony_ci case BPF_MAP_TYPE_RINGBUF: 47062306a36Sopenharmony_ci case BPF_MAP_TYPE_PROG_ARRAY: 47162306a36Sopenharmony_ci case BPF_MAP_TYPE_CGROUP_ARRAY: 47262306a36Sopenharmony_ci case BPF_MAP_TYPE_PERCPU_ARRAY: 47362306a36Sopenharmony_ci case BPF_MAP_TYPE_USER_RINGBUF: 47462306a36Sopenharmony_ci case BPF_MAP_TYPE_ARRAY_OF_MAPS: 47562306a36Sopenharmony_ci case BPF_MAP_TYPE_CGROUP_STORAGE: 47662306a36Sopenharmony_ci case BPF_MAP_TYPE_PERF_EVENT_ARRAY: 47762306a36Sopenharmony_ci return true; 47862306a36Sopenharmony_ci default: 47962306a36Sopenharmony_ci return false; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int do_prog_test_run(int fd_prog, int *retval) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci __u8 tmp_out[TEST_DATA_LEN << 2] = {}; 48662306a36Sopenharmony_ci __u8 tmp_in[TEST_DATA_LEN] = {}; 48762306a36Sopenharmony_ci int err, saved_errno; 48862306a36Sopenharmony_ci LIBBPF_OPTS(bpf_test_run_opts, topts, 48962306a36Sopenharmony_ci .data_in = tmp_in, 49062306a36Sopenharmony_ci .data_size_in = sizeof(tmp_in), 49162306a36Sopenharmony_ci .data_out = tmp_out, 49262306a36Sopenharmony_ci .data_size_out = sizeof(tmp_out), 49362306a36Sopenharmony_ci .repeat = 1, 49462306a36Sopenharmony_ci ); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci err = bpf_prog_test_run_opts(fd_prog, &topts); 49762306a36Sopenharmony_ci saved_errno = errno; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (err) { 50062306a36Sopenharmony_ci PRINT_FAIL("FAIL: Unexpected bpf_prog_test_run error: %d (%s) ", 50162306a36Sopenharmony_ci saved_errno, strerror(saved_errno)); 50262306a36Sopenharmony_ci return err; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ASSERT_OK(0, "bpf_prog_test_run"); 50662306a36Sopenharmony_ci *retval = topts.retval; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic bool should_do_test_run(struct test_spec *spec, struct test_subspec *subspec) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci if (!subspec->execute) 51462306a36Sopenharmony_ci return false; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (subspec->expect_failure) 51762306a36Sopenharmony_ci return false; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if ((spec->prog_flags & BPF_F_ANY_ALIGNMENT) && !EFFICIENT_UNALIGNED_ACCESS) { 52062306a36Sopenharmony_ci if (env.verbosity != VERBOSE_NONE) 52162306a36Sopenharmony_ci printf("alignment prevents execution\n"); 52262306a36Sopenharmony_ci return false; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return true; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* this function is forced noinline and has short generic name to look better 52962306a36Sopenharmony_ci * in test_progs output (in case of a failure) 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_cistatic noinline 53262306a36Sopenharmony_civoid run_subtest(struct test_loader *tester, 53362306a36Sopenharmony_ci struct bpf_object_open_opts *open_opts, 53462306a36Sopenharmony_ci const void *obj_bytes, 53562306a36Sopenharmony_ci size_t obj_byte_cnt, 53662306a36Sopenharmony_ci struct test_spec *specs, 53762306a36Sopenharmony_ci struct test_spec *spec, 53862306a36Sopenharmony_ci bool unpriv) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct test_subspec *subspec = unpriv ? &spec->unpriv : &spec->priv; 54162306a36Sopenharmony_ci struct bpf_program *tprog, *tprog_iter; 54262306a36Sopenharmony_ci struct test_spec *spec_iter; 54362306a36Sopenharmony_ci struct cap_state caps = {}; 54462306a36Sopenharmony_ci struct bpf_object *tobj; 54562306a36Sopenharmony_ci struct bpf_map *map; 54662306a36Sopenharmony_ci int retval, err, i; 54762306a36Sopenharmony_ci bool should_load; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (!test__start_subtest(subspec->name)) 55062306a36Sopenharmony_ci return; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (unpriv) { 55362306a36Sopenharmony_ci if (!can_execute_unpriv(tester, spec)) { 55462306a36Sopenharmony_ci test__skip(); 55562306a36Sopenharmony_ci test__end_subtest(); 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci if (drop_capabilities(&caps)) { 55962306a36Sopenharmony_ci test__end_subtest(); 56062306a36Sopenharmony_ci return; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, open_opts); 56562306a36Sopenharmony_ci if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ 56662306a36Sopenharmony_ci goto subtest_cleanup; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci i = 0; 56962306a36Sopenharmony_ci bpf_object__for_each_program(tprog_iter, tobj) { 57062306a36Sopenharmony_ci spec_iter = &specs[i++]; 57162306a36Sopenharmony_ci should_load = false; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (spec_iter->valid) { 57462306a36Sopenharmony_ci if (strcmp(bpf_program__name(tprog_iter), spec->prog_name) == 0) { 57562306a36Sopenharmony_ci tprog = tprog_iter; 57662306a36Sopenharmony_ci should_load = true; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (spec_iter->auxiliary && 58062306a36Sopenharmony_ci spec_iter->mode_mask & (unpriv ? UNPRIV : PRIV)) 58162306a36Sopenharmony_ci should_load = true; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci bpf_program__set_autoload(tprog_iter, should_load); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci prepare_case(tester, spec, tobj, tprog); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* By default bpf_object__load() automatically creates all 59062306a36Sopenharmony_ci * maps declared in the skeleton. Some map types are only 59162306a36Sopenharmony_ci * allowed in priv mode. Disable autoload for such maps in 59262306a36Sopenharmony_ci * unpriv mode. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci bpf_object__for_each_map(map, tobj) 59562306a36Sopenharmony_ci bpf_map__set_autocreate(map, !unpriv || is_unpriv_capable_map(map)); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci err = bpf_object__load(tobj); 59862306a36Sopenharmony_ci if (subspec->expect_failure) { 59962306a36Sopenharmony_ci if (!ASSERT_ERR(err, "unexpected_load_success")) { 60062306a36Sopenharmony_ci emit_verifier_log(tester->log_buf, false /*force*/); 60162306a36Sopenharmony_ci goto tobj_cleanup; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } else { 60462306a36Sopenharmony_ci if (!ASSERT_OK(err, "unexpected_load_failure")) { 60562306a36Sopenharmony_ci emit_verifier_log(tester->log_buf, true /*force*/); 60662306a36Sopenharmony_ci goto tobj_cleanup; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci emit_verifier_log(tester->log_buf, false /*force*/); 61162306a36Sopenharmony_ci validate_case(tester, subspec, tobj, tprog, err); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (should_do_test_run(spec, subspec)) { 61462306a36Sopenharmony_ci /* For some reason test_verifier executes programs 61562306a36Sopenharmony_ci * with all capabilities restored. Do the same here. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci if (restore_capabilities(&caps)) 61862306a36Sopenharmony_ci goto tobj_cleanup; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (tester->pre_execution_cb) { 62162306a36Sopenharmony_ci err = tester->pre_execution_cb(tobj); 62262306a36Sopenharmony_ci if (err) { 62362306a36Sopenharmony_ci PRINT_FAIL("pre_execution_cb failed: %d\n", err); 62462306a36Sopenharmony_ci goto tobj_cleanup; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci do_prog_test_run(bpf_program__fd(tprog), &retval); 62962306a36Sopenharmony_ci if (retval != subspec->retval && subspec->retval != POINTER_VALUE) { 63062306a36Sopenharmony_ci PRINT_FAIL("Unexpected retval: %d != %d\n", retval, subspec->retval); 63162306a36Sopenharmony_ci goto tobj_cleanup; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_citobj_cleanup: 63662306a36Sopenharmony_ci bpf_object__close(tobj); 63762306a36Sopenharmony_cisubtest_cleanup: 63862306a36Sopenharmony_ci test__end_subtest(); 63962306a36Sopenharmony_ci restore_capabilities(&caps); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void process_subtest(struct test_loader *tester, 64362306a36Sopenharmony_ci const char *skel_name, 64462306a36Sopenharmony_ci skel_elf_bytes_fn elf_bytes_factory) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name); 64762306a36Sopenharmony_ci struct test_spec *specs = NULL; 64862306a36Sopenharmony_ci struct bpf_object *obj = NULL; 64962306a36Sopenharmony_ci struct bpf_program *prog; 65062306a36Sopenharmony_ci const void *obj_bytes; 65162306a36Sopenharmony_ci int err, i, nr_progs; 65262306a36Sopenharmony_ci size_t obj_byte_cnt; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (tester_init(tester) < 0) 65562306a36Sopenharmony_ci return; /* failed to initialize tester */ 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci obj_bytes = elf_bytes_factory(&obj_byte_cnt); 65862306a36Sopenharmony_ci obj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 65962306a36Sopenharmony_ci if (!ASSERT_OK_PTR(obj, "obj_open_mem")) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci nr_progs = 0; 66362306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) 66462306a36Sopenharmony_ci ++nr_progs; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci specs = calloc(nr_progs, sizeof(struct test_spec)); 66762306a36Sopenharmony_ci if (!ASSERT_OK_PTR(specs, "Can't alloc specs array")) 66862306a36Sopenharmony_ci return; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci i = 0; 67162306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 67262306a36Sopenharmony_ci /* ignore tests for which we can't derive test specification */ 67362306a36Sopenharmony_ci err = parse_test_spec(tester, obj, prog, &specs[i++]); 67462306a36Sopenharmony_ci if (err) 67562306a36Sopenharmony_ci PRINT_FAIL("Can't parse test spec for program '%s'\n", 67662306a36Sopenharmony_ci bpf_program__name(prog)); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci i = 0; 68062306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 68162306a36Sopenharmony_ci struct test_spec *spec = &specs[i++]; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (!spec->valid || spec->auxiliary) 68462306a36Sopenharmony_ci continue; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (spec->mode_mask & PRIV) 68762306a36Sopenharmony_ci run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, 68862306a36Sopenharmony_ci specs, spec, false); 68962306a36Sopenharmony_ci if (spec->mode_mask & UNPRIV) 69062306a36Sopenharmony_ci run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, 69162306a36Sopenharmony_ci specs, spec, true); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (i = 0; i < nr_progs; ++i) 69662306a36Sopenharmony_ci free_test_spec(&specs[i]); 69762306a36Sopenharmony_ci free(specs); 69862306a36Sopenharmony_ci bpf_object__close(obj); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid test_loader__run_subtests(struct test_loader *tester, 70262306a36Sopenharmony_ci const char *skel_name, 70362306a36Sopenharmony_ci skel_elf_bytes_fn elf_bytes_factory) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci /* see comment in run_subtest() for why we do this function nesting */ 70662306a36Sopenharmony_ci process_subtest(tester, skel_name, elf_bytes_factory); 70762306a36Sopenharmony_ci} 708