Skip to content

Commit aaccdf9

Browse files
author
Alexei Starovoitov
committed
Merge branch 'Remove libcap dependency from bpf selftests'
Martin KaFai Lau says: ==================== After upgrading to the newer libcap (>= 2.60), the libcap commit aca076443591 ("Make cap_t operations thread safe.") added a "__u8 mutex;" to the "struct _cap_struct". It caused a few byte shift that breaks the assumption made in the "struct libcap" definition in test_verifier.c. This set is to remove the libcap dependency from the bpf selftests. v2: - Define CAP_PERFMON and CAP_BPF when the older <linux/capability.h> does not have them. (Andrii) ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 6585abe + 82cb2b3 commit aaccdf9

File tree

5 files changed

+124
-102
lines changed

5 files changed

+124
-102
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ CFLAGS += -g -O0 -rdynamic -Wall -Werror $(GENFLAGS) $(SAN_CFLAGS) \
2525
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
2626
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
2727
LDFLAGS += $(SAN_CFLAGS)
28-
LDLIBS += -lcap -lelf -lz -lrt -lpthread
28+
LDLIBS += -lelf -lz -lrt -lpthread
2929

3030
# Silence some warnings when compiled with clang
3131
ifneq ($(LLVM),)
@@ -195,6 +195,7 @@ $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
195195
CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o
196196
TESTING_HELPERS := $(OUTPUT)/testing_helpers.o
197197
TRACE_HELPERS := $(OUTPUT)/trace_helpers.o
198+
CAP_HELPERS := $(OUTPUT)/cap_helpers.o
198199

199200
$(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
200201
$(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
@@ -211,7 +212,7 @@ $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
211212
$(OUTPUT)/xdping: $(TESTING_HELPERS)
212213
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
213214
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
214-
$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
215+
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
215216

216217
BPFTOOL ?= $(DEFAULT_BPFTOOL)
217218
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
@@ -479,7 +480,8 @@ TRUNNER_TESTS_DIR := prog_tests
479480
TRUNNER_BPF_PROGS_DIR := progs
480481
TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \
481482
network_helpers.c testing_helpers.c \
482-
btf_helpers.c flow_dissector_load.h
483+
btf_helpers.c flow_dissector_load.h \
484+
cap_helpers.c
483485
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
484486
ima_setup.sh \
485487
$(wildcard progs/btf_dump_test_case_*.c)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include "cap_helpers.h"
3+
4+
/* Avoid including <sys/capability.h> from the libcap-devel package,
5+
* so directly declare them here and use them from glibc.
6+
*/
7+
int capget(cap_user_header_t header, cap_user_data_t data);
8+
int capset(cap_user_header_t header, const cap_user_data_t data);
9+
10+
int cap_enable_effective(__u64 caps, __u64 *old_caps)
11+
{
12+
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
13+
struct __user_cap_header_struct hdr = {
14+
.version = _LINUX_CAPABILITY_VERSION_3,
15+
};
16+
__u32 cap0 = caps;
17+
__u32 cap1 = caps >> 32;
18+
int err;
19+
20+
err = capget(&hdr, data);
21+
if (err)
22+
return err;
23+
24+
if (old_caps)
25+
*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
26+
27+
if ((data[0].effective & cap0) == cap0 &&
28+
(data[1].effective & cap1) == cap1)
29+
return 0;
30+
31+
data[0].effective |= cap0;
32+
data[1].effective |= cap1;
33+
err = capset(&hdr, data);
34+
if (err)
35+
return err;
36+
37+
return 0;
38+
}
39+
40+
int cap_disable_effective(__u64 caps, __u64 *old_caps)
41+
{
42+
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
43+
struct __user_cap_header_struct hdr = {
44+
.version = _LINUX_CAPABILITY_VERSION_3,
45+
};
46+
__u32 cap0 = caps;
47+
__u32 cap1 = caps >> 32;
48+
int err;
49+
50+
err = capget(&hdr, data);
51+
if (err)
52+
return err;
53+
54+
if (old_caps)
55+
*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
56+
57+
if (!(data[0].effective & cap0) && !(data[1].effective & cap1))
58+
return 0;
59+
60+
data[0].effective &= ~cap0;
61+
data[1].effective &= ~cap1;
62+
err = capset(&hdr, data);
63+
if (err)
64+
return err;
65+
66+
return 0;
67+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __CAP_HELPERS_H
3+
#define __CAP_HELPERS_H
4+
5+
#include <linux/types.h>
6+
#include <linux/capability.h>
7+
8+
#ifndef CAP_PERFMON
9+
#define CAP_PERFMON 38
10+
#endif
11+
12+
#ifndef CAP_BPF
13+
#define CAP_BPF 39
14+
#endif
15+
16+
int cap_enable_effective(__u64 caps, __u64 *old_caps);
17+
int cap_disable_effective(__u64 caps, __u64 *old_caps);
18+
19+
#endif

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

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
#include <stdlib.h>
55
#include <sys/types.h>
66
#include <sys/socket.h>
7-
#include <sys/capability.h>
87

98
#include "test_progs.h"
9+
#include "cap_helpers.h"
1010
#include "bind_perm.skel.h"
1111

1212
static int duration;
@@ -49,41 +49,11 @@ void try_bind(int family, int port, int expected_errno)
4949
close(fd);
5050
}
5151

52-
bool cap_net_bind_service(cap_flag_value_t flag)
53-
{
54-
const cap_value_t cap_net_bind_service = CAP_NET_BIND_SERVICE;
55-
cap_flag_value_t original_value;
56-
bool was_effective = false;
57-
cap_t caps;
58-
59-
caps = cap_get_proc();
60-
if (CHECK(!caps, "cap_get_proc", "errno %d", errno))
61-
goto free_caps;
62-
63-
if (CHECK(cap_get_flag(caps, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE,
64-
&original_value),
65-
"cap_get_flag", "errno %d", errno))
66-
goto free_caps;
67-
68-
was_effective = (original_value == CAP_SET);
69-
70-
if (CHECK(cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_bind_service,
71-
flag),
72-
"cap_set_flag", "errno %d", errno))
73-
goto free_caps;
74-
75-
if (CHECK(cap_set_proc(caps), "cap_set_proc", "errno %d", errno))
76-
goto free_caps;
77-
78-
free_caps:
79-
CHECK(cap_free(caps), "cap_free", "errno %d", errno);
80-
return was_effective;
81-
}
82-
8352
void test_bind_perm(void)
8453
{
85-
bool cap_was_effective;
54+
const __u64 net_bind_svc_cap = 1ULL << CAP_NET_BIND_SERVICE;
8655
struct bind_perm *skel;
56+
__u64 old_caps = 0;
8757
int cgroup_fd;
8858

8959
if (create_netns())
@@ -105,16 +75,18 @@ void test_bind_perm(void)
10575
if (!ASSERT_OK_PTR(skel, "bind_v6_prog"))
10676
goto close_skeleton;
10777

108-
cap_was_effective = cap_net_bind_service(CAP_CLEAR);
78+
ASSERT_OK(cap_disable_effective(net_bind_svc_cap, &old_caps),
79+
"cap_disable_effective");
10980

11081
try_bind(AF_INET, 110, EACCES);
11182
try_bind(AF_INET6, 110, EACCES);
11283

11384
try_bind(AF_INET, 111, 0);
11485
try_bind(AF_INET6, 111, 0);
11586

116-
if (cap_was_effective)
117-
cap_net_bind_service(CAP_SET);
87+
if (old_caps & net_bind_svc_cap)
88+
ASSERT_OK(cap_enable_effective(net_bind_svc_cap, NULL),
89+
"cap_enable_effective");
11890

11991
close_skeleton:
12092
bind_perm__destroy(skel);

tools/testing/selftests/bpf/test_verifier.c

Lines changed: 25 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
#include <limits.h>
2323
#include <assert.h>
2424

25-
#include <sys/capability.h>
26-
2725
#include <linux/unistd.h>
2826
#include <linux/filter.h>
2927
#include <linux/bpf_perf_event.h>
@@ -42,6 +40,7 @@
4240
# define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
4341
# endif
4442
#endif
43+
#include "cap_helpers.h"
4544
#include "bpf_rand.h"
4645
#include "bpf_util.h"
4746
#include "test_btf.h"
@@ -62,6 +61,10 @@
6261
#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0)
6362
#define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1)
6463

64+
/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
65+
#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN | \
66+
1ULL << CAP_PERFMON | \
67+
1ULL << CAP_BPF)
6568
#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
6669
static bool unpriv_disabled = false;
6770
static int skips;
@@ -973,47 +976,19 @@ struct libcap {
973976

974977
static int set_admin(bool admin)
975978
{
976-
cap_t caps;
977-
/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
978-
const cap_value_t cap_net_admin = CAP_NET_ADMIN;
979-
const cap_value_t cap_sys_admin = CAP_SYS_ADMIN;
980-
struct libcap *cap;
981-
int ret = -1;
982-
983-
caps = cap_get_proc();
984-
if (!caps) {
985-
perror("cap_get_proc");
986-
return -1;
987-
}
988-
cap = (struct libcap *)caps;
989-
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) {
990-
perror("cap_set_flag clear admin");
991-
goto out;
992-
}
993-
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin,
994-
admin ? CAP_SET : CAP_CLEAR)) {
995-
perror("cap_set_flag set_or_clear net");
996-
goto out;
997-
}
998-
/* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON,
999-
* so update effective bits manually
1000-
*/
979+
int err;
980+
1001981
if (admin) {
1002-
cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32);
1003-
cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32);
982+
err = cap_enable_effective(ADMIN_CAPS, NULL);
983+
if (err)
984+
perror("cap_enable_effective(ADMIN_CAPS)");
1004985
} else {
1005-
cap->data[1].effective &= ~(1 << (38 - 32));
1006-
cap->data[1].effective &= ~(1 << (39 - 32));
1007-
}
1008-
if (cap_set_proc(caps)) {
1009-
perror("cap_set_proc");
1010-
goto out;
986+
err = cap_disable_effective(ADMIN_CAPS, NULL);
987+
if (err)
988+
perror("cap_disable_effective(ADMIN_CAPS)");
1011989
}
1012-
ret = 0;
1013-
out:
1014-
if (cap_free(caps))
1015-
perror("cap_free");
1016-
return ret;
990+
991+
return err;
1017992
}
1018993

1019994
static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
@@ -1291,31 +1266,18 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
12911266

12921267
static bool is_admin(void)
12931268
{
1294-
cap_flag_value_t net_priv = CAP_CLEAR;
1295-
bool perfmon_priv = false;
1296-
bool bpf_priv = false;
1297-
struct libcap *cap;
1298-
cap_t caps;
1299-
1300-
#ifdef CAP_IS_SUPPORTED
1301-
if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
1302-
perror("cap_get_flag");
1303-
return false;
1304-
}
1305-
#endif
1306-
caps = cap_get_proc();
1307-
if (!caps) {
1308-
perror("cap_get_proc");
1269+
__u64 caps;
1270+
1271+
/* The test checks for finer cap as CAP_NET_ADMIN,
1272+
* CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
1273+
* Thus, disable CAP_SYS_ADMIN at the beginning.
1274+
*/
1275+
if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
1276+
perror("cap_disable_effective(CAP_SYS_ADMIN)");
13091277
return false;
13101278
}
1311-
cap = (struct libcap *)caps;
1312-
bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32));
1313-
perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32));
1314-
if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv))
1315-
perror("cap_get_flag NET");
1316-
if (cap_free(caps))
1317-
perror("cap_free");
1318-
return bpf_priv && perfmon_priv && net_priv == CAP_SET;
1279+
1280+
return (caps & ADMIN_CAPS) == ADMIN_CAPS;
13191281
}
13201282

13211283
static void get_unpriv_disabled()

0 commit comments

Comments
 (0)