Skip to content

Commit adfdd9c

Browse files
eddyz87Alexei Starovoitov
authored and
Alexei Starovoitov
committed
selftests/bpf: Introduce __caps_unpriv annotation for tests
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. Since we do not want to include linux/capability.h, we only defined the four main capabilities BPF subsystem deals with in bpf_misc.h for use in tests. If the user passes a CAP_SYS_NICE or anything else that's not defined in the header, capability parsing code will return a warning. Also reject strtol returning 0. CAP_CHOWN = 0 but we'll never need to use it, and strtol doesn't errno on failed conversion. Fail the test in such a case. 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, add warn to parse_caps, convert test_verifier_mtu ] Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b0e6697 commit adfdd9c

File tree

4 files changed

+62
-19
lines changed

4 files changed

+62
-19
lines changed

tools/testing/selftests/bpf/prog_tests/verifier.c

+1-18
Original file line numberDiff line numberDiff line change
@@ -225,24 +225,7 @@ void test_verifier_xdp(void) { RUN(verifier_xdp); }
225225
void test_verifier_xdp_direct_packet_access(void) { RUN(verifier_xdp_direct_packet_access); }
226226
void test_verifier_bits_iter(void) { RUN(verifier_bits_iter); }
227227
void test_verifier_lsm(void) { RUN(verifier_lsm); }
228-
229-
void test_verifier_mtu(void)
230-
{
231-
__u64 caps = 0;
232-
int ret;
233-
234-
/* In case CAP_BPF and CAP_PERFMON is not set */
235-
ret = cap_enable_effective(1ULL << CAP_BPF | 1ULL << CAP_NET_ADMIN, &caps);
236-
if (!ASSERT_OK(ret, "set_cap_bpf_cap_net_admin"))
237-
return;
238-
ret = cap_disable_effective(1ULL << CAP_SYS_ADMIN | 1ULL << CAP_PERFMON, NULL);
239-
if (!ASSERT_OK(ret, "disable_cap_sys_admin"))
240-
goto restore_cap;
241-
RUN(verifier_mtu);
242-
restore_cap:
243-
if (caps)
244-
cap_enable_effective(caps, NULL);
245-
}
228+
void test_verifier_mtu(void) { RUN(verifier_mtu); }
246229

247230
static int init_test_val_map(struct bpf_object *obj, char *map_name)
248231
{

tools/testing/selftests/bpf/progs/bpf_misc.h

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
#define XSTR(s) STR(s)
66
#define STR(s) #s
77

8+
/* Expand a macro and then stringize the expansion */
9+
#define QUOTE(str) #str
10+
#define EXPAND_QUOTE(str) QUOTE(str)
11+
812
/* This set of attributes controls behavior of the
913
* test_loader.c:test_loader__run_subtests().
1014
*
@@ -106,6 +110,7 @@
106110
* __arch_* Specify on which architecture the test case should be tested.
107111
* Several __arch_* annotations could be specified at once.
108112
* When test case is not run on current arch it is marked as skipped.
113+
* __caps_unpriv Specify the capabilities that should be set when running the test.
109114
*/
110115
#define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg)))
111116
#define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" XSTR(__COUNTER__) "=" msg)))
@@ -129,6 +134,13 @@
129134
#define __arch_x86_64 __arch("X86_64")
130135
#define __arch_arm64 __arch("ARM64")
131136
#define __arch_riscv64 __arch("RISCV64")
137+
#define __caps_unpriv(caps) __attribute__((btf_decl_tag("comment:test_caps_unpriv=" EXPAND_QUOTE(caps))))
138+
139+
/* Define common capabilities tested using __caps_unpriv */
140+
#define CAP_NET_ADMIN 12
141+
#define CAP_SYS_ADMIN 21
142+
#define CAP_PERFMON 38
143+
#define CAP_BPF 39
132144

133145
/* Convenience macro for use with 'asm volatile' blocks */
134146
#define __naked __attribute__((naked))

tools/testing/selftests/bpf/progs/verifier_mtu.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
SEC("tc/ingress")
88
__description("uninit/mtu: write rejected")
9-
__failure __msg("invalid indirect read from stack")
9+
__success
10+
__caps_unpriv(CAP_BPF|CAP_NET_ADMIN)
11+
__failure_unpriv __msg_unpriv("invalid indirect read from stack")
1012
int tc_uninit_mtu(struct __sk_buff *ctx)
1113
{
1214
__u32 mtu;

tools/testing/selftests/bpf/test_loader.c

+46
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define TEST_TAG_ARCH "comment:test_arch="
3737
#define TEST_TAG_JITED_PFX "comment:test_jited="
3838
#define TEST_TAG_JITED_PFX_UNPRIV "comment:test_jited_unpriv="
39+
#define TEST_TAG_CAPS_UNPRIV "comment:test_caps_unpriv="
3940

4041
/* Warning: duplicated in bpf_misc.h */
4142
#define POINTER_VALUE 0xcafe4all
@@ -74,6 +75,7 @@ struct test_subspec {
7475
struct expected_msgs jited;
7576
int retval;
7677
bool execute;
78+
__u64 caps;
7779
};
7880

7981
struct test_spec {
@@ -276,6 +278,37 @@ static int parse_int(const char *str, int *val, const char *name)
276278
return 0;
277279
}
278280

281+
static int parse_caps(const char *str, __u64 *val, const char *name)
282+
{
283+
int cap_flag = 0;
284+
char *token = NULL, *saveptr = NULL;
285+
286+
char *str_cpy = strdup(str);
287+
if (str_cpy == NULL) {
288+
PRINT_FAIL("Memory allocation failed\n");
289+
return -EINVAL;
290+
}
291+
292+
token = strtok_r(str_cpy, "|", &saveptr);
293+
while (token != NULL) {
294+
errno = 0;
295+
if (!strncmp("CAP_", token, sizeof("CAP_") - 1)) {
296+
PRINT_FAIL("define %s constant in bpf_misc.h, failed to parse caps\n", token);
297+
return -EINVAL;
298+
}
299+
cap_flag = strtol(token, NULL, 10);
300+
if (!cap_flag || errno) {
301+
PRINT_FAIL("failed to parse caps %s\n", name);
302+
return -EINVAL;
303+
}
304+
*val |= (1ULL << cap_flag);
305+
token = strtok_r(NULL, "|", &saveptr);
306+
}
307+
308+
free(str_cpy);
309+
return 0;
310+
}
311+
279312
static int parse_retval(const char *str, int *val, const char *name)
280313
{
281314
struct {
@@ -541,6 +574,12 @@ static int parse_test_spec(struct test_loader *tester,
541574
jit_on_next_line = true;
542575
} else if (str_has_pfx(s, TEST_BTF_PATH)) {
543576
spec->btf_custom_path = s + sizeof(TEST_BTF_PATH) - 1;
577+
} else if (str_has_pfx(s, TEST_TAG_CAPS_UNPRIV)) {
578+
val = s + sizeof(TEST_TAG_CAPS_UNPRIV) - 1;
579+
err = parse_caps(val, &spec->unpriv.caps, "test caps");
580+
if (err)
581+
goto cleanup;
582+
spec->mode_mask |= UNPRIV;
544583
}
545584
}
546585

@@ -917,6 +956,13 @@ void run_subtest(struct test_loader *tester,
917956
test__end_subtest();
918957
return;
919958
}
959+
if (subspec->caps) {
960+
err = cap_enable_effective(subspec->caps, NULL);
961+
if (err) {
962+
PRINT_FAIL("failed to set capabilities: %i, %s\n", err, strerror(err));
963+
goto subtest_cleanup;
964+
}
965+
}
920966
}
921967

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

0 commit comments

Comments
 (0)