Skip to content

Commit

Permalink
selftests/bpf: Introduce __caps_unpriv annotation for tests
Browse files Browse the repository at this point in the history
Add a __caps_unpriv annotation so that tests requiring specific
capabilities while dropping the rest can conveniently specify them
during selftest declaration instead of munging with capabilities at
runtime from the testing binary.

While at it, let us convert test_verifier_mtu to use this new support
instead.

The original diff for this idea is available at link [0].

  [0]: https://lore.kernel.org/bpf/[email protected]

Signed-off-by: Eduard Zingerman <[email protected]>
[ Kartikeya: rebase on bpf-next, remove unnecessary bits, convert test_verifier_mtu ]
Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
  • Loading branch information
eddyz87 authored and Kernel Patches Daemon committed Dec 2, 2024
1 parent fa3e6bf commit ffcd4fd
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 19 deletions.
19 changes: 1 addition & 18 deletions tools/testing/selftests/bpf/prog_tests/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,24 +225,7 @@ void test_verifier_xdp(void) { RUN(verifier_xdp); }
void test_verifier_xdp_direct_packet_access(void) { RUN(verifier_xdp_direct_packet_access); }
void test_verifier_bits_iter(void) { RUN(verifier_bits_iter); }
void test_verifier_lsm(void) { RUN(verifier_lsm); }

void test_verifier_mtu(void)
{
__u64 caps = 0;
int ret;

/* In case CAP_BPF and CAP_PERFMON is not set */
ret = cap_enable_effective(1ULL << CAP_BPF | 1ULL << CAP_NET_ADMIN, &caps);
if (!ASSERT_OK(ret, "set_cap_bpf_cap_net_admin"))
return;
ret = cap_disable_effective(1ULL << CAP_SYS_ADMIN | 1ULL << CAP_PERFMON, NULL);
if (!ASSERT_OK(ret, "disable_cap_sys_admin"))
goto restore_cap;
RUN(verifier_mtu);
restore_cap:
if (caps)
cap_enable_effective(caps, NULL);
}
void test_verifier_mtu(void) { RUN(verifier_mtu); }

static int init_test_val_map(struct bpf_object *obj, char *map_name)
{
Expand Down
2 changes: 2 additions & 0 deletions tools/testing/selftests/bpf/progs/bpf_misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
* __arch_* Specify on which architecture the test case should be tested.
* Several __arch_* annotations could be specified at once.
* When test case is not run on current arch it is marked as skipped.
* __caps_unpriv Specify the capabilities that should be set when running the test
*/
#define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg)))
#define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" XSTR(__COUNTER__) "=" msg)))
Expand All @@ -129,6 +130,7 @@
#define __arch_x86_64 __arch("X86_64")
#define __arch_arm64 __arch("ARM64")
#define __arch_riscv64 __arch("RISCV64")
#define __caps_unpriv(caps) __attribute__((btf_decl_tag("comment:test_caps_unpriv=" XSTR(caps))))

/* Convenience macro for use with 'asm volatile' blocks */
#define __naked __attribute__((naked))
Expand Down
3 changes: 2 additions & 1 deletion tools/testing/selftests/bpf/progs/verifier_mtu.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

SEC("tc/ingress")
__description("uninit/mtu: write rejected")
__failure __msg("invalid indirect read from stack")
__success __failure_unpriv __msg_unpriv("invalid indirect read from stack")
__caps_unpriv(CAP_BPF)
int tc_uninit_mtu(struct __sk_buff *ctx)
{
__u32 mtu;
Expand Down
41 changes: 41 additions & 0 deletions tools/testing/selftests/bpf/test_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#define TEST_TAG_ARCH "comment:test_arch="
#define TEST_TAG_JITED_PFX "comment:test_jited="
#define TEST_TAG_JITED_PFX_UNPRIV "comment:test_jited_unpriv="
#define TEST_TAG_CAPS_UNPRIV "comment:test_caps_unpriv="

/* Warning: duplicated in bpf_misc.h */
#define POINTER_VALUE 0xcafe4all
Expand Down Expand Up @@ -74,6 +75,7 @@ struct test_subspec {
struct expected_msgs jited;
int retval;
bool execute;
__u64 caps;
};

struct test_spec {
Expand Down Expand Up @@ -276,6 +278,33 @@ static int parse_int(const char *str, int *val, const char *name)
return 0;
}

static int parse_caps(const char *str, __u64 *val, const char *name)
{
int cap_flag = 0;
char *token = NULL, *saveptr = NULL;

char *str_cpy = strdup(str);
if (str_cpy == NULL) {
PRINT_FAIL("Memory allocation failed\n");
return -EINVAL;
}

token = strtok_r(str_cpy, "|", &saveptr);
while (token != NULL) {
errno = 0;
cap_flag = strtol(token, NULL, 10);
if (errno) {
PRINT_FAIL("failed to parse caps %s\n", name);
return -EINVAL;
}
*val |= (1ULL << cap_flag);
token = strtok_r(NULL, "|", &saveptr);
}

free(str_cpy);
return 0;
}

static int parse_retval(const char *str, int *val, const char *name)
{
struct {
Expand Down Expand Up @@ -541,6 +570,12 @@ static int parse_test_spec(struct test_loader *tester,
jit_on_next_line = true;
} else if (str_has_pfx(s, TEST_BTF_PATH)) {
spec->btf_custom_path = s + sizeof(TEST_BTF_PATH) - 1;
} else if (str_has_pfx(s, TEST_TAG_CAPS_UNPRIV)) {
val = s + sizeof(TEST_TAG_CAPS_UNPRIV) - 1;
err = parse_caps(val, &spec->unpriv.caps, "test caps");
if (err)
goto cleanup;
spec->mode_mask |= UNPRIV;
}
}

Expand Down Expand Up @@ -917,6 +952,12 @@ void run_subtest(struct test_loader *tester,
test__end_subtest();
return;
}
if (subspec->caps) {
err = cap_enable_effective(subspec->caps, NULL);
if (err)
PRINT_FAIL("failed to set capabilities: %i, %s\n", err, strerror(err));
goto subtest_cleanup;
}
}

/* Implicitly reset to NULL if next test case doesn't specify */
Expand Down

0 comments on commit ffcd4fd

Please sign in to comment.