On Tue, Oct 10, 2023 at 1:35 AM Jiri Olsa <olsajiri@xxxxxxxxx> wrote: > > 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 Not missing anything. I used to keep token reference inside struct bpf_map on success, but I ripped that out, so yes, token has to be put properly even on success. Thanks for catching this! And yes, right after bpf_map_save_memcg() seems like the best spot. > > 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