Determine and remember effective capabilities of the process at the BPF_PROG_LOAD command time. We store those in prog->aux, so we can check and use them throughout various places (like BPF verifier) that perform various checks and enforce various extra conditions on BPF program based on its effective capabilities. Currently we have explicit calls to bpf_capable(), perfmon_capable() and capable() spread out throughout code base, but we'll be refactoring this over next few patches to consistently use prog->aux->{bpf,perfmon}_capable fields to perform decisions. This ensures we have a consistent set of restrictions checked and recorded in one consistent place. Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx> --- include/linux/bpf.h | 5 +++++ kernel/bpf/syscall.c | 23 +++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 479657bb113e..44ccfea0f73b 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1370,6 +1370,11 @@ struct bpf_prog_aux { u32 ctx_arg_info_size; u32 max_rdonly_access; u32 max_rdwr_access; + + /* effective capabilities that were given to BPF program at load time */ + bool bpf_capable; + bool perfmon_capable; + struct btf *attach_btf; const struct bpf_ctx_arg_aux *ctx_arg_info; struct mutex dst_mutex; /* protects dst_* pointers below, *after* prog becomes visible */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d960eb476754..839f69d75297 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2568,6 +2568,7 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) { + bool bpf_cap, net_admin_cap, sys_admin_cap, perfmon_cap; enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog, *dst_prog = NULL; struct btf *attach_btf = NULL; @@ -2586,6 +2587,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) BPF_F_XDP_DEV_BOUND_ONLY)) return -EINVAL; + /* remember set of effective capabilities to be used throughout */ + bpf_cap = bpf_capable(); + perfmon_cap = perfmon_capable(); + net_admin_cap = capable(CAP_NET_ADMIN); + sys_admin_cap = capable(CAP_SYS_ADMIN); + /* Intent here is for unprivileged_bpf_disabled to block key object * creation commands for unprivileged users; other actions depend * of fd availability and access to bpffs, so are dependent on @@ -2594,25 +2601,25 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) * BPF disabled, capability checks are still carried out for these * and other operations. */ - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) + if (sysctl_unprivileged_bpf_disabled && !bpf_cap) return -EPERM; if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && - !bpf_capable()) + !bpf_cap) return -EPERM; if (attr->insn_cnt == 0 || - attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) + attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) return -E2BIG; if (type != BPF_PROG_TYPE_SOCKET_FILTER && type != BPF_PROG_TYPE_CGROUP_SKB && - !bpf_capable()) + !bpf_cap) return -EPERM; - if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) + if (is_net_admin_prog_type(type) && !net_admin_cap && !sys_admin_cap) return -EPERM; - if (is_perfmon_prog_type(type) && !perfmon_capable()) + if (is_perfmon_prog_type(type) && !perfmon_cap) return -EPERM; /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog @@ -2672,6 +2679,10 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS; + /* remember effective capabilities prog was given */ + prog->aux->bpf_capable = bpf_cap; + prog->aux->perfmon_capable = perfmon_cap; + err = security_bpf_prog_alloc(prog->aux); if (err) goto free_prog; -- 2.34.1