Commit ed1ad5a7 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

bpf: Align CAP_NET_ADMIN checks with bpf_capable() approach

Within BPF syscall handling code CAP_NET_ADMIN checks stand out a bit
compared to CAP_BPF and CAP_PERFMON checks. For the latter, CAP_BPF or
CAP_PERFMON are checked first, but if they are not set, CAP_SYS_ADMIN
takes over and grants whatever part of BPF syscall is required.

Similar kind of checks that involve CAP_NET_ADMIN are not so consistent.
One out of four uses does follow CAP_BPF/CAP_PERFMON model: during
BPF_PROG_LOAD, if the type of BPF program is "network-related" either
CAP_NET_ADMIN or CAP_SYS_ADMIN is required to proceed.

But in three other cases CAP_NET_ADMIN is required even if CAP_SYS_ADMIN
is set:
  - when creating DEVMAP/XDKMAP/CPU_MAP maps;
  - when attaching CGROUP_SKB programs;
  - when handling BPF_PROG_QUERY command.

This patch is changing the latter three cases to follow BPF_PROG_LOAD
model, that is allowing to proceed under either CAP_NET_ADMIN or
CAP_SYS_ADMIN.

This also makes it cleaner in subsequent BPF token patches to switch
wholesomely to a generic bpf_token_capable(int cap) check, that always
falls back to CAP_SYS_ADMIN if requested capability is missing.
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarYafang Shao <laoar.shao@gmail.com>
Link: https://lore.kernel.org/bpf/20240124022127.2379740-2-andrii@kernel.org
parent c9f11556
...@@ -1123,6 +1123,11 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf, ...@@ -1123,6 +1123,11 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,
return ret; return ret;
} }
static bool bpf_net_capable(void)
{
return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
}
#define BPF_MAP_CREATE_LAST_FIELD value_type_btf_obj_fd #define BPF_MAP_CREATE_LAST_FIELD value_type_btf_obj_fd
/* called via syscall */ /* called via syscall */
static int map_create(union bpf_attr *attr) static int map_create(union bpf_attr *attr)
...@@ -1226,7 +1231,7 @@ static int map_create(union bpf_attr *attr) ...@@ -1226,7 +1231,7 @@ static int map_create(union bpf_attr *attr)
case BPF_MAP_TYPE_DEVMAP: case BPF_MAP_TYPE_DEVMAP:
case BPF_MAP_TYPE_DEVMAP_HASH: case BPF_MAP_TYPE_DEVMAP_HASH:
case BPF_MAP_TYPE_XSKMAP: case BPF_MAP_TYPE_XSKMAP:
if (!capable(CAP_NET_ADMIN)) if (!bpf_net_capable())
return -EPERM; return -EPERM;
break; break;
default: default:
...@@ -2636,7 +2641,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) ...@@ -2636,7 +2641,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
!bpf_capable()) !bpf_capable())
return -EPERM; return -EPERM;
if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) if (is_net_admin_prog_type(type) && !bpf_net_capable())
return -EPERM; return -EPERM;
if (is_perfmon_prog_type(type) && !perfmon_capable()) if (is_perfmon_prog_type(type) && !perfmon_capable())
return -EPERM; return -EPERM;
...@@ -3822,7 +3827,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog, ...@@ -3822,7 +3827,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
case BPF_PROG_TYPE_SK_LOOKUP: case BPF_PROG_TYPE_SK_LOOKUP:
return attach_type == prog->expected_attach_type ? 0 : -EINVAL; return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
case BPF_PROG_TYPE_CGROUP_SKB: case BPF_PROG_TYPE_CGROUP_SKB:
if (!capable(CAP_NET_ADMIN)) if (!bpf_net_capable())
/* cg-skb progs can be loaded by unpriv user. /* cg-skb progs can be loaded by unpriv user.
* check permissions at attach time. * check permissions at attach time.
*/ */
...@@ -4025,7 +4030,7 @@ static int bpf_prog_detach(const union bpf_attr *attr) ...@@ -4025,7 +4030,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
static int bpf_prog_query(const union bpf_attr *attr, static int bpf_prog_query(const union bpf_attr *attr,
union bpf_attr __user *uattr) union bpf_attr __user *uattr)
{ {
if (!capable(CAP_NET_ADMIN)) if (!bpf_net_capable())
return -EPERM; return -EPERM;
if (CHECK_ATTR(BPF_PROG_QUERY)) if (CHECK_ATTR(BPF_PROG_QUERY))
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment