Remove remaining direct queries to perfmon_capable() and bpf_capable() in BPF verifier logic and instead use prog->aux->{bpf,perfmon}_capable values. This enables to have one place where permissions are checked and granted for any given BPF program, and after that BPF subsystem will consistently use the decision. Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx> --- include/linux/bpf.h | 16 ++++++++-------- include/linux/filter.h | 2 +- kernel/bpf/core.c | 2 +- kernel/bpf/verifier.c | 17 ++++++++++------- net/core/filter.c | 4 ++-- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 785b720358f5..8a2af67039fc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2048,26 +2048,26 @@ bpf_map_alloc_percpu(const struct bpf_map *map, size_t size, size_t align, extern int sysctl_unprivileged_bpf_disabled; -static inline bool bpf_allow_ptr_leaks(void) +static inline bool bpf_allow_ptr_leaks(const struct bpf_prog *prog) { - return perfmon_capable(); + return prog->aux->perfmon_capable; } -static inline bool bpf_allow_uninit_stack(void) +static inline bool bpf_allow_uninit_stack(const struct bpf_prog *prog) { - return perfmon_capable(); + return prog->aux->perfmon_capable; } -static inline bool bpf_bypass_spec_v1(void) +static inline bool bpf_bypass_spec_v1(const struct bpf_prog *prog) { - return perfmon_capable(); + return prog->aux->perfmon_capable; } int bpf_array_adjust_for_spec_v1(union bpf_attr *attr); -static inline bool bpf_bypass_spec_v4(void) +static inline bool bpf_bypass_spec_v4(const struct bpf_prog *prog) { - return perfmon_capable(); + return prog->aux->perfmon_capable; } int bpf_map_new_fd(struct bpf_map *map, int flags); diff --git a/include/linux/filter.h b/include/linux/filter.h index 9c207d9848e9..95ce7c4ab28d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1112,7 +1112,7 @@ static inline bool bpf_jit_blinding_enabled(struct bpf_prog *prog) return false; if (!bpf_jit_harden) return false; - if (bpf_jit_harden == 1 && bpf_capable()) + if (bpf_jit_harden == 1 && prog->aux->bpf_capable) return false; return true; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 4d057d39c286..c0d60da7e0e0 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -661,7 +661,7 @@ static bool bpf_prog_kallsyms_candidate(const struct bpf_prog *fp) void bpf_prog_kallsyms_add(struct bpf_prog *fp) { if (!bpf_prog_kallsyms_candidate(fp) || - !bpf_capable()) + !fp->aux->bpf_capable) return; bpf_prog_ksym_set_addr(fp); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 481aaf189183..7be0abc196db 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17194,6 +17194,10 @@ static int jit_subprogs(struct bpf_verifier_env *env) func[i]->aux->poke_tab = prog->aux->poke_tab; func[i]->aux->size_poke_tab = prog->aux->size_poke_tab; + /* inherit main prog's effective capabilities */ + func[i]->aux->bpf_capable = prog->aux->bpf_capable; + func[i]->aux->perfmon_capable = prog->aux->perfmon_capable; + for (j = 0; j < prog->aux->size_poke_tab; j++) { struct bpf_jit_poke_descriptor *poke; @@ -18878,7 +18882,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 env->prog = *prog; env->ops = bpf_verifier_ops[env->prog->type]; env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel); - is_priv = bpf_capable(); + + env->allow_ptr_leaks = bpf_allow_ptr_leaks(*prog); + env->allow_uninit_stack = bpf_allow_uninit_stack(*prog); + env->bypass_spec_v1 = bpf_bypass_spec_v1(*prog); + env->bypass_spec_v4 = bpf_bypass_spec_v4(*prog); + env->bpf_capable = is_priv = (*prog)->aux->bpf_capable; bpf_get_btf_vmlinux(); @@ -18910,12 +18919,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (attr->prog_flags & BPF_F_ANY_ALIGNMENT) env->strict_alignment = false; - env->allow_ptr_leaks = bpf_allow_ptr_leaks(); - env->allow_uninit_stack = bpf_allow_uninit_stack(); - env->bypass_spec_v1 = bpf_bypass_spec_v1(); - env->bypass_spec_v4 = bpf_bypass_spec_v4(); - env->bpf_capable = bpf_capable(); - if (is_priv) env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ; diff --git a/net/core/filter.c b/net/core/filter.c index 8e282797e658..8a7e86230f2a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8432,7 +8432,7 @@ static bool cg_skb_is_valid_access(int off, int size, return false; case bpf_ctx_range(struct __sk_buff, data): case bpf_ctx_range(struct __sk_buff, data_end): - if (!bpf_capable()) + if (!prog->aux->bpf_capable) return false; break; } @@ -8444,7 +8444,7 @@ static bool cg_skb_is_valid_access(int off, int size, case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]): break; case bpf_ctx_range(struct __sk_buff, tstamp): - if (!bpf_capable()) + if (!prog->aux->bpf_capable) return false; break; default: -- 2.34.1