return -ENOTSUPP;
 }
 
-static int map_check_btf(struct bpf_map *map, const struct btf *btf,
-                        u32 btf_key_id, u32 btf_value_id)
+static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
+                        const struct btf *btf, u32 btf_key_id, u32 btf_value_id)
 {
        const struct btf_type *key_type, *value_type;
        u32 key_size, value_size;
        if (!IS_ERR_OR_NULL(map->record)) {
                int i;
 
-               if (!bpf_capable()) {
+               if (!bpf_token_capable(token, CAP_BPF)) {
                        ret = -EPERM;
                        goto free_map_tab;
                }
        return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
 }
 
-#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;
        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) {
        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;
 
                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;
                goto free_map_sec;
 
        bpf_map_save_memcg(map);
+       bpf_token_put(token);
 
        err = bpf_map_new_fd(map, f_flags);
        if (err < 0) {
 free_map:
        btf_put(map->btf);
        map->ops->map_free(map);
+put_token:
+       bpf_token_put(token);
        return err;
 }
 
 
                seq_printf(m, "allowed_cmds:\tany\n");
        else
                seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds);
+
+       BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64);
+       mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
+       if ((token->allowed_maps & mask) == mask)
+               seq_printf(m, "allowed_maps:\tany\n");
+       else
+               seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps);
 }
 
 #define BPF_TOKEN_INODE_NAME "bpf-token"
 
        mnt_opts = path.dentry->d_sb->s_fs_info;
        token->allowed_cmds = mnt_opts->delegate_cmds;
+       token->allowed_maps = mnt_opts->delegate_maps;
 
        fd = get_unused_fd_flags(O_CLOEXEC);
        if (fd < 0) {
 
        return token->allowed_cmds & (1ULL << cmd);
 }
+
+bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type)
+{
+       if (!token || type >= __MAX_BPF_MAP_TYPE)
+               return false;
+
+       return token->allowed_maps & (1ULL << type);
+}