Ksym addr access is restricted by ``kptr_restrict``(/proc/sys/kernel/kptr_restrict). On some OS systems(like Android), ksym addr access is not accessed because ``kptr_restrict=2`. And it took me a long time to find the root case. -When ``kptr_restrict==0``, addr is accessed. # echo 0 > /proc/sys/kernel/kptr_restrict # cat /proc/kallsyms | grep bpf_link_fops ffffffd6bfd3fb60 d bpf_link_fops -When ``kptr_restrict==2``, addr is replaced by ZERO. # echo 2 > /proc/sys/kernel/kptr_restrict # cat /proc/kallsyms | grep bpf_link_fops 0000000000000000 d bpf_link_fops -When ``kptr_restrict==1``, addr is accessed for user having CAP_SYSLOG. So we should perform a check to remind users for these conditions before reading /proc/kallsyms. [before]: # echo 2 > /proc/sys/kernel/kptr_restrict # ./test_progs -t ksyms #133 ksyms:FAIL [after]: # echo 2 > /proc/sys/kernel/kptr_restrict # ./test_progs -t ksym ksyms restricted, please check /proc/sys/kernel/kptr_restrict #133 ksyms:FAIL Signed-off-by: Lin Yikai <yikai.lin@xxxxxxxx> --- tools/testing/selftests/bpf/Makefile | 7 ++- tools/testing/selftests/bpf/trace_helpers.c | 63 +++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 04716a5e43f1..369c5ad8fc4a 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -183,7 +183,7 @@ NON_CHECK_FEAT_TARGETS := clean docs-clean CHECK_FEAT := $(filter-out $(NON_CHECK_FEAT_TARGETS),$(or $(MAKECMDGOALS), "none")) ifneq ($(CHECK_FEAT),) FEATURE_USER := .selftests -FEATURE_TESTS := llvm +FEATURE_TESTS := llvm libcap FEATURE_DISPLAY := $(FEATURE_TESTS) # Makefile.feature expects OUTPUT to end with a slash @@ -208,6 +208,11 @@ ifeq ($(feature-llvm),1) LLVM_LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags) endif +ifeq ($(feature-libcap), 1) + CFLAGS += -DHAVE_LIBCAP_SUPPORT + LDLIBS += -lcap +endif + SCRATCH_DIR := $(OUTPUT)/tools BUILD_DIR := $(SCRATCH_DIR)/build INCLUDE_DIR := $(SCRATCH_DIR)/include diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c index 2d742fdac6b9..8d2f951464ff 100644 --- a/tools/testing/selftests/bpf/trace_helpers.c +++ b/tools/testing/selftests/bpf/trace_helpers.c @@ -17,6 +17,10 @@ #include <linux/limits.h> #include <libelf.h> #include <gelf.h> +#include <stdbool.h> +#include <linux/capability.h> +#include <linux/compiler.h> +#include <sys/types.h> #include "bpf/libbpf_internal.h" #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe" @@ -31,6 +35,55 @@ struct ksyms { static struct ksyms *ksyms; static pthread_mutex_t ksyms_mutex = PTHREAD_MUTEX_INITIALIZER; +#ifdef HAVE_LIBCAP_SUPPORT +#include <sys/capability.h> +static bool bpf_cap__capable(cap_value_t cap) +{ + cap_flag_value_t val; + cap_t caps = cap_get_proc(); + + if (!caps) + return false; + + if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0) + val = CAP_CLEAR; + + if (cap_free(caps) != 0) + return false; + + return val == CAP_SET; +} +#else +static inline bool bpf_cap__capable(int cap __maybe_unused) +{ + return geteuid() == 0; +} +#endif /* HAVE_LIBCAP_SUPPORT */ + +/* For older systems */ +#ifndef CAP_SYSLOG +#define CAP_SYSLOG 34 +#endif + +static bool ksyms__kptr_restrict(void) +{ + bool value = false; + FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); + + if (fp != NULL) { + char line[8]; + + if (fgets(line, sizeof(line), fp) != NULL) + value = bpf_cap__capable(CAP_SYSLOG) ? + (atoi(line) >= 2) : + (atoi(line) != 0); + + fclose(fp); + } + + return value; +} + static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned long addr) { @@ -72,6 +125,11 @@ static struct ksyms *load_kallsyms_local_common(ksym_cmp_t cmp_cb) int ret; struct ksyms *ksyms; + if (ksyms__kptr_restrict()) { + printf("ksyms restricted, please check /proc/sys/kernel/kptr_restrict\n"); + return NULL; + } + f = fopen("/proc/kallsyms", "r"); if (!f) return NULL; @@ -218,6 +276,11 @@ int kallsyms_find(const char *sym, unsigned long long *addr) int err = 0; FILE *f; + if (ksyms__kptr_restrict()) { + printf("ksyms restricted, please check /proc/sys/kernel/kptr_restrict\n"); + return -EINVAL; + } + f = fopen("/proc/kallsyms", "r"); if (!f) return -EINVAL; -- 2.34.1