mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-14 06:24:53 +08:00
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 <ast@kernel.org>
This commit is contained in:
commit
aaccdf9c93
@ -25,7 +25,7 @@ CFLAGS += -g -O0 -rdynamic -Wall -Werror $(GENFLAGS) $(SAN_CFLAGS) \
|
|||||||
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
|
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
|
||||||
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
|
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
|
||||||
LDFLAGS += $(SAN_CFLAGS)
|
LDFLAGS += $(SAN_CFLAGS)
|
||||||
LDLIBS += -lcap -lelf -lz -lrt -lpthread
|
LDLIBS += -lelf -lz -lrt -lpthread
|
||||||
|
|
||||||
# Silence some warnings when compiled with clang
|
# Silence some warnings when compiled with clang
|
||||||
ifneq ($(LLVM),)
|
ifneq ($(LLVM),)
|
||||||
@ -195,6 +195,7 @@ $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ)
|
|||||||
CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o
|
CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o
|
||||||
TESTING_HELPERS := $(OUTPUT)/testing_helpers.o
|
TESTING_HELPERS := $(OUTPUT)/testing_helpers.o
|
||||||
TRACE_HELPERS := $(OUTPUT)/trace_helpers.o
|
TRACE_HELPERS := $(OUTPUT)/trace_helpers.o
|
||||||
|
CAP_HELPERS := $(OUTPUT)/cap_helpers.o
|
||||||
|
|
||||||
$(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
|
$(OUTPUT)/test_dev_cgroup: $(CGROUP_HELPERS) $(TESTING_HELPERS)
|
||||||
$(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
|
$(OUTPUT)/test_skb_cgroup_id_user: $(CGROUP_HELPERS) $(TESTING_HELPERS)
|
||||||
@ -211,7 +212,7 @@ $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
|
|||||||
$(OUTPUT)/xdping: $(TESTING_HELPERS)
|
$(OUTPUT)/xdping: $(TESTING_HELPERS)
|
||||||
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
|
$(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
|
||||||
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
|
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
|
||||||
$(OUTPUT)/test_verifier: $(TESTING_HELPERS)
|
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS)
|
||||||
|
|
||||||
BPFTOOL ?= $(DEFAULT_BPFTOOL)
|
BPFTOOL ?= $(DEFAULT_BPFTOOL)
|
||||||
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
|
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
|
||||||
@ -479,7 +480,8 @@ TRUNNER_TESTS_DIR := prog_tests
|
|||||||
TRUNNER_BPF_PROGS_DIR := progs
|
TRUNNER_BPF_PROGS_DIR := progs
|
||||||
TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \
|
TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \
|
||||||
network_helpers.c testing_helpers.c \
|
network_helpers.c testing_helpers.c \
|
||||||
btf_helpers.c flow_dissector_load.h
|
btf_helpers.c flow_dissector_load.h \
|
||||||
|
cap_helpers.c
|
||||||
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
|
TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
|
||||||
ima_setup.sh \
|
ima_setup.sh \
|
||||||
$(wildcard progs/btf_dump_test_case_*.c)
|
$(wildcard progs/btf_dump_test_case_*.c)
|
||||||
|
67
tools/testing/selftests/bpf/cap_helpers.c
Normal file
67
tools/testing/selftests/bpf/cap_helpers.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include "cap_helpers.h"
|
||||||
|
|
||||||
|
/* Avoid including <sys/capability.h> from the libcap-devel package,
|
||||||
|
* so directly declare them here and use them from glibc.
|
||||||
|
*/
|
||||||
|
int capget(cap_user_header_t header, cap_user_data_t data);
|
||||||
|
int capset(cap_user_header_t header, const cap_user_data_t data);
|
||||||
|
|
||||||
|
int cap_enable_effective(__u64 caps, __u64 *old_caps)
|
||||||
|
{
|
||||||
|
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
|
||||||
|
struct __user_cap_header_struct hdr = {
|
||||||
|
.version = _LINUX_CAPABILITY_VERSION_3,
|
||||||
|
};
|
||||||
|
__u32 cap0 = caps;
|
||||||
|
__u32 cap1 = caps >> 32;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = capget(&hdr, data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (old_caps)
|
||||||
|
*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
|
||||||
|
|
||||||
|
if ((data[0].effective & cap0) == cap0 &&
|
||||||
|
(data[1].effective & cap1) == cap1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data[0].effective |= cap0;
|
||||||
|
data[1].effective |= cap1;
|
||||||
|
err = capset(&hdr, data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cap_disable_effective(__u64 caps, __u64 *old_caps)
|
||||||
|
{
|
||||||
|
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3];
|
||||||
|
struct __user_cap_header_struct hdr = {
|
||||||
|
.version = _LINUX_CAPABILITY_VERSION_3,
|
||||||
|
};
|
||||||
|
__u32 cap0 = caps;
|
||||||
|
__u32 cap1 = caps >> 32;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = capget(&hdr, data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (old_caps)
|
||||||
|
*old_caps = (__u64)(data[1].effective) << 32 | data[0].effective;
|
||||||
|
|
||||||
|
if (!(data[0].effective & cap0) && !(data[1].effective & cap1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data[0].effective &= ~cap0;
|
||||||
|
data[1].effective &= ~cap1;
|
||||||
|
err = capset(&hdr, data);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
19
tools/testing/selftests/bpf/cap_helpers.h
Normal file
19
tools/testing/selftests/bpf/cap_helpers.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef __CAP_HELPERS_H
|
||||||
|
#define __CAP_HELPERS_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/capability.h>
|
||||||
|
|
||||||
|
#ifndef CAP_PERFMON
|
||||||
|
#define CAP_PERFMON 38
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CAP_BPF
|
||||||
|
#define CAP_BPF 39
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cap_enable_effective(__u64 caps, __u64 *old_caps);
|
||||||
|
int cap_disable_effective(__u64 caps, __u64 *old_caps);
|
||||||
|
|
||||||
|
#endif
|
@ -4,9 +4,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/capability.h>
|
|
||||||
|
|
||||||
#include "test_progs.h"
|
#include "test_progs.h"
|
||||||
|
#include "cap_helpers.h"
|
||||||
#include "bind_perm.skel.h"
|
#include "bind_perm.skel.h"
|
||||||
|
|
||||||
static int duration;
|
static int duration;
|
||||||
@ -49,41 +49,11 @@ close_socket:
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cap_net_bind_service(cap_flag_value_t flag)
|
|
||||||
{
|
|
||||||
const cap_value_t cap_net_bind_service = CAP_NET_BIND_SERVICE;
|
|
||||||
cap_flag_value_t original_value;
|
|
||||||
bool was_effective = false;
|
|
||||||
cap_t caps;
|
|
||||||
|
|
||||||
caps = cap_get_proc();
|
|
||||||
if (CHECK(!caps, "cap_get_proc", "errno %d", errno))
|
|
||||||
goto free_caps;
|
|
||||||
|
|
||||||
if (CHECK(cap_get_flag(caps, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE,
|
|
||||||
&original_value),
|
|
||||||
"cap_get_flag", "errno %d", errno))
|
|
||||||
goto free_caps;
|
|
||||||
|
|
||||||
was_effective = (original_value == CAP_SET);
|
|
||||||
|
|
||||||
if (CHECK(cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_bind_service,
|
|
||||||
flag),
|
|
||||||
"cap_set_flag", "errno %d", errno))
|
|
||||||
goto free_caps;
|
|
||||||
|
|
||||||
if (CHECK(cap_set_proc(caps), "cap_set_proc", "errno %d", errno))
|
|
||||||
goto free_caps;
|
|
||||||
|
|
||||||
free_caps:
|
|
||||||
CHECK(cap_free(caps), "cap_free", "errno %d", errno);
|
|
||||||
return was_effective;
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_bind_perm(void)
|
void test_bind_perm(void)
|
||||||
{
|
{
|
||||||
bool cap_was_effective;
|
const __u64 net_bind_svc_cap = 1ULL << CAP_NET_BIND_SERVICE;
|
||||||
struct bind_perm *skel;
|
struct bind_perm *skel;
|
||||||
|
__u64 old_caps = 0;
|
||||||
int cgroup_fd;
|
int cgroup_fd;
|
||||||
|
|
||||||
if (create_netns())
|
if (create_netns())
|
||||||
@ -105,7 +75,8 @@ void test_bind_perm(void)
|
|||||||
if (!ASSERT_OK_PTR(skel, "bind_v6_prog"))
|
if (!ASSERT_OK_PTR(skel, "bind_v6_prog"))
|
||||||
goto close_skeleton;
|
goto close_skeleton;
|
||||||
|
|
||||||
cap_was_effective = cap_net_bind_service(CAP_CLEAR);
|
ASSERT_OK(cap_disable_effective(net_bind_svc_cap, &old_caps),
|
||||||
|
"cap_disable_effective");
|
||||||
|
|
||||||
try_bind(AF_INET, 110, EACCES);
|
try_bind(AF_INET, 110, EACCES);
|
||||||
try_bind(AF_INET6, 110, EACCES);
|
try_bind(AF_INET6, 110, EACCES);
|
||||||
@ -113,8 +84,9 @@ void test_bind_perm(void)
|
|||||||
try_bind(AF_INET, 111, 0);
|
try_bind(AF_INET, 111, 0);
|
||||||
try_bind(AF_INET6, 111, 0);
|
try_bind(AF_INET6, 111, 0);
|
||||||
|
|
||||||
if (cap_was_effective)
|
if (old_caps & net_bind_svc_cap)
|
||||||
cap_net_bind_service(CAP_SET);
|
ASSERT_OK(cap_enable_effective(net_bind_svc_cap, NULL),
|
||||||
|
"cap_enable_effective");
|
||||||
|
|
||||||
close_skeleton:
|
close_skeleton:
|
||||||
bind_perm__destroy(skel);
|
bind_perm__destroy(skel);
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <sys/capability.h>
|
|
||||||
|
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/bpf_perf_event.h>
|
#include <linux/bpf_perf_event.h>
|
||||||
@ -42,6 +40,7 @@
|
|||||||
# define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
|
# define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
#include "cap_helpers.h"
|
||||||
#include "bpf_rand.h"
|
#include "bpf_rand.h"
|
||||||
#include "bpf_util.h"
|
#include "bpf_util.h"
|
||||||
#include "test_btf.h"
|
#include "test_btf.h"
|
||||||
@ -62,6 +61,10 @@
|
|||||||
#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0)
|
#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0)
|
||||||
#define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1)
|
#define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1)
|
||||||
|
|
||||||
|
/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
|
||||||
|
#define ADMIN_CAPS (1ULL << CAP_NET_ADMIN | \
|
||||||
|
1ULL << CAP_PERFMON | \
|
||||||
|
1ULL << CAP_BPF)
|
||||||
#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
|
#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled"
|
||||||
static bool unpriv_disabled = false;
|
static bool unpriv_disabled = false;
|
||||||
static int skips;
|
static int skips;
|
||||||
@ -973,47 +976,19 @@ struct libcap {
|
|||||||
|
|
||||||
static int set_admin(bool admin)
|
static int set_admin(bool admin)
|
||||||
{
|
{
|
||||||
cap_t caps;
|
int err;
|
||||||
/* need CAP_BPF, CAP_NET_ADMIN, CAP_PERFMON to load progs */
|
|
||||||
const cap_value_t cap_net_admin = CAP_NET_ADMIN;
|
|
||||||
const cap_value_t cap_sys_admin = CAP_SYS_ADMIN;
|
|
||||||
struct libcap *cap;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
caps = cap_get_proc();
|
|
||||||
if (!caps) {
|
|
||||||
perror("cap_get_proc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cap = (struct libcap *)caps;
|
|
||||||
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_sys_admin, CAP_CLEAR)) {
|
|
||||||
perror("cap_set_flag clear admin");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_net_admin,
|
|
||||||
admin ? CAP_SET : CAP_CLEAR)) {
|
|
||||||
perror("cap_set_flag set_or_clear net");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/* libcap is likely old and simply ignores CAP_BPF and CAP_PERFMON,
|
|
||||||
* so update effective bits manually
|
|
||||||
*/
|
|
||||||
if (admin) {
|
if (admin) {
|
||||||
cap->data[1].effective |= 1 << (38 /* CAP_PERFMON */ - 32);
|
err = cap_enable_effective(ADMIN_CAPS, NULL);
|
||||||
cap->data[1].effective |= 1 << (39 /* CAP_BPF */ - 32);
|
if (err)
|
||||||
|
perror("cap_enable_effective(ADMIN_CAPS)");
|
||||||
} else {
|
} else {
|
||||||
cap->data[1].effective &= ~(1 << (38 - 32));
|
err = cap_disable_effective(ADMIN_CAPS, NULL);
|
||||||
cap->data[1].effective &= ~(1 << (39 - 32));
|
if (err)
|
||||||
|
perror("cap_disable_effective(ADMIN_CAPS)");
|
||||||
}
|
}
|
||||||
if (cap_set_proc(caps)) {
|
|
||||||
perror("cap_set_proc");
|
return err;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
out:
|
|
||||||
if (cap_free(caps))
|
|
||||||
perror("cap_free");
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
|
static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
|
||||||
@ -1291,31 +1266,18 @@ fail_log:
|
|||||||
|
|
||||||
static bool is_admin(void)
|
static bool is_admin(void)
|
||||||
{
|
{
|
||||||
cap_flag_value_t net_priv = CAP_CLEAR;
|
__u64 caps;
|
||||||
bool perfmon_priv = false;
|
|
||||||
bool bpf_priv = false;
|
|
||||||
struct libcap *cap;
|
|
||||||
cap_t caps;
|
|
||||||
|
|
||||||
#ifdef CAP_IS_SUPPORTED
|
/* The test checks for finer cap as CAP_NET_ADMIN,
|
||||||
if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
|
* CAP_PERFMON, and CAP_BPF instead of CAP_SYS_ADMIN.
|
||||||
perror("cap_get_flag");
|
* Thus, disable CAP_SYS_ADMIN at the beginning.
|
||||||
|
*/
|
||||||
|
if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) {
|
||||||
|
perror("cap_disable_effective(CAP_SYS_ADMIN)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
caps = cap_get_proc();
|
return (caps & ADMIN_CAPS) == ADMIN_CAPS;
|
||||||
if (!caps) {
|
|
||||||
perror("cap_get_proc");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cap = (struct libcap *)caps;
|
|
||||||
bpf_priv = cap->data[1].effective & (1 << (39/* CAP_BPF */ - 32));
|
|
||||||
perfmon_priv = cap->data[1].effective & (1 << (38/* CAP_PERFMON */ - 32));
|
|
||||||
if (cap_get_flag(caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &net_priv))
|
|
||||||
perror("cap_get_flag NET");
|
|
||||||
if (cap_free(caps))
|
|
||||||
perror("cap_free");
|
|
||||||
return bpf_priv && perfmon_priv && net_priv == CAP_SET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_unpriv_disabled()
|
static void get_unpriv_disabled()
|
||||||
|
Loading…
Reference in New Issue
Block a user