On Wed, Sep 27, 2023 at 03:58:00PM -0700, Andrii Nakryiko wrote: SNIP > -#define BPF_MAP_CREATE_LAST_FIELD map_extra > +#define BPF_MAP_CREATE_LAST_FIELD map_token_fd > /* called via syscall */ > static int map_create(union bpf_attr *attr) > { > const struct bpf_map_ops *ops; > + struct bpf_token *token = NULL; > int numa_node = bpf_map_attr_numa_node(attr); > u32 map_type = attr->map_type; > struct bpf_map *map; > @@ -1157,14 +1158,32 @@ static int map_create(union bpf_attr *attr) > if (!ops->map_mem_usage) > return -EINVAL; > > + if (attr->map_token_fd) { > + token = bpf_token_get_from_fd(attr->map_token_fd); > + if (IS_ERR(token)) > + return PTR_ERR(token); > + > + /* if current token doesn't grant map creation permissions, > + * then we can't use this token, so ignore it and rely on > + * system-wide capabilities checks > + */ > + if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) || > + !bpf_token_allow_map_type(token, attr->map_type)) { > + bpf_token_put(token); > + token = NULL; > + } > + } > + > + err = -EPERM; > + > /* Intent here is for unprivileged_bpf_disabled to block BPF map > * creation for unprivileged users; other actions depend > * on fd availability and access to bpffs, so are dependent on > * object creation success. Even with unprivileged BPF disabled, > * capability checks are still carried out. > */ > - if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) > - return -EPERM; > + if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF)) > + goto put_token; > > /* check privileged map type permissions */ > switch (map_type) { > @@ -1197,25 +1216,27 @@ static int map_create(union bpf_attr *attr) > case BPF_MAP_TYPE_LRU_PERCPU_HASH: > case BPF_MAP_TYPE_STRUCT_OPS: > case BPF_MAP_TYPE_CPUMAP: > - if (!bpf_capable()) > - return -EPERM; > + if (!bpf_token_capable(token, CAP_BPF)) > + goto put_token; > break; > case BPF_MAP_TYPE_SOCKMAP: > case BPF_MAP_TYPE_SOCKHASH: > case BPF_MAP_TYPE_DEVMAP: > case BPF_MAP_TYPE_DEVMAP_HASH: > case BPF_MAP_TYPE_XSKMAP: > - if (!bpf_net_capable()) > - return -EPERM; > + if (!bpf_token_capable(token, CAP_NET_ADMIN)) > + goto put_token; > break; > default: > WARN(1, "unsupported map type %d", map_type); > - return -EPERM; > + goto put_token; > } > > map = ops->map_alloc(attr); > - if (IS_ERR(map)) > - return PTR_ERR(map); > + if (IS_ERR(map)) { > + err = PTR_ERR(map); > + goto put_token; > + } > map->ops = ops; > map->map_type = map_type; > > @@ -1252,7 +1273,7 @@ static int map_create(union bpf_attr *attr) > map->btf = btf; > > if (attr->btf_value_type_id) { > - err = map_check_btf(map, btf, attr->btf_key_type_id, > + err = map_check_btf(map, token, btf, attr->btf_key_type_id, > attr->btf_value_type_id); > if (err) > goto free_map; I might be missing something, but should we call bpf_token_put(token) on non-error path as well? probably after bpf_map_save_memcg call jirka > @@ -1293,6 +1314,8 @@ static int map_create(union bpf_attr *attr) > free_map: > btf_put(map->btf); > map->ops->map_free(map); > +put_token: > + bpf_token_put(token); > return err; > } > SNIP