linux/kernel/bpf/map_in_map.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2017 Facebook
   3 */
   4#include <linux/slab.h>
   5#include <linux/bpf.h>
   6
   7#include "map_in_map.h"
   8
   9struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
  10{
  11        struct bpf_map *inner_map, *inner_map_meta;
  12        u32 inner_map_meta_size;
  13        struct fd f;
  14
  15        f = fdget(inner_map_ufd);
  16        inner_map = __bpf_map_get(f);
  17        if (IS_ERR(inner_map))
  18                return inner_map;
  19
  20        /* prog_array->aux->{type,jited} is a runtime binding.
  21         * Doing static check alone in the verifier is not enough.
  22         */
  23        if (inner_map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
  24            inner_map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE ||
  25            inner_map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
  26                fdput(f);
  27                return ERR_PTR(-ENOTSUPP);
  28        }
  29
  30        /* Does not support >1 level map-in-map */
  31        if (inner_map->inner_map_meta) {
  32                fdput(f);
  33                return ERR_PTR(-EINVAL);
  34        }
  35
  36        if (map_value_has_spin_lock(inner_map)) {
  37                fdput(f);
  38                return ERR_PTR(-ENOTSUPP);
  39        }
  40
  41        inner_map_meta_size = sizeof(*inner_map_meta);
  42        /* In some cases verifier needs to access beyond just base map. */
  43        if (inner_map->ops == &array_map_ops)
  44                inner_map_meta_size = sizeof(struct bpf_array);
  45
  46        inner_map_meta = kzalloc(inner_map_meta_size, GFP_USER);
  47        if (!inner_map_meta) {
  48                fdput(f);
  49                return ERR_PTR(-ENOMEM);
  50        }
  51
  52        inner_map_meta->map_type = inner_map->map_type;
  53        inner_map_meta->key_size = inner_map->key_size;
  54        inner_map_meta->value_size = inner_map->value_size;
  55        inner_map_meta->map_flags = inner_map->map_flags;
  56        inner_map_meta->max_entries = inner_map->max_entries;
  57        inner_map_meta->spin_lock_off = inner_map->spin_lock_off;
  58
  59        /* Misc members not needed in bpf_map_meta_equal() check. */
  60        inner_map_meta->ops = inner_map->ops;
  61        if (inner_map->ops == &array_map_ops) {
  62                inner_map_meta->unpriv_array = inner_map->unpriv_array;
  63                container_of(inner_map_meta, struct bpf_array, map)->index_mask =
  64                     container_of(inner_map, struct bpf_array, map)->index_mask;
  65        }
  66
  67        fdput(f);
  68        return inner_map_meta;
  69}
  70
  71void bpf_map_meta_free(struct bpf_map *map_meta)
  72{
  73        kfree(map_meta);
  74}
  75
  76bool bpf_map_meta_equal(const struct bpf_map *meta0,
  77                        const struct bpf_map *meta1)
  78{
  79        /* No need to compare ops because it is covered by map_type */
  80        return meta0->map_type == meta1->map_type &&
  81                meta0->key_size == meta1->key_size &&
  82                meta0->value_size == meta1->value_size &&
  83                meta0->map_flags == meta1->map_flags &&
  84                meta0->max_entries == meta1->max_entries;
  85}
  86
  87void *bpf_map_fd_get_ptr(struct bpf_map *map,
  88                         struct file *map_file /* not used */,
  89                         int ufd)
  90{
  91        struct bpf_map *inner_map;
  92        struct fd f;
  93
  94        f = fdget(ufd);
  95        inner_map = __bpf_map_get(f);
  96        if (IS_ERR(inner_map))
  97                return inner_map;
  98
  99        if (bpf_map_meta_equal(map->inner_map_meta, inner_map))
 100                bpf_map_inc(inner_map);
 101        else
 102                inner_map = ERR_PTR(-EINVAL);
 103
 104        fdput(f);
 105        return inner_map;
 106}
 107
 108void bpf_map_fd_put_ptr(void *ptr)
 109{
 110        /* ptr->ops->map_free() has to go through one
 111         * rcu grace period by itself.
 112         */
 113        bpf_map_put(ptr);
 114}
 115
 116u32 bpf_map_fd_sys_lookup_elem(void *ptr)
 117{
 118        return ((struct bpf_map *)ptr)->id;
 119}
 120