156f668dfSMartin KaFai Lau /* Copyright (c) 2017 Facebook 256f668dfSMartin KaFai Lau * 356f668dfSMartin KaFai Lau * This program is free software; you can redistribute it and/or 456f668dfSMartin KaFai Lau * modify it under the terms of version 2 of the GNU General Public 556f668dfSMartin KaFai Lau * License as published by the Free Software Foundation. 656f668dfSMartin KaFai Lau */ 756f668dfSMartin KaFai Lau #include <linux/slab.h> 856f668dfSMartin KaFai Lau #include <linux/bpf.h> 956f668dfSMartin KaFai Lau 1056f668dfSMartin KaFai Lau #include "map_in_map.h" 1156f668dfSMartin KaFai Lau 1256f668dfSMartin KaFai Lau struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) 1356f668dfSMartin KaFai Lau { 1456f668dfSMartin KaFai Lau struct bpf_map *inner_map, *inner_map_meta; 1556f668dfSMartin KaFai Lau struct fd f; 1656f668dfSMartin KaFai Lau 1756f668dfSMartin KaFai Lau f = fdget(inner_map_ufd); 1856f668dfSMartin KaFai Lau inner_map = __bpf_map_get(f); 1956f668dfSMartin KaFai Lau if (IS_ERR(inner_map)) 2056f668dfSMartin KaFai Lau return inner_map; 2156f668dfSMartin KaFai Lau 2256f668dfSMartin KaFai Lau /* prog_array->owner_prog_type and owner_jited 2356f668dfSMartin KaFai Lau * is a runtime binding. Doing static check alone 2456f668dfSMartin KaFai Lau * in the verifier is not enough. 2556f668dfSMartin KaFai Lau */ 267b5dd2bdSRoman Gushchin if (inner_map->map_type == BPF_MAP_TYPE_PROG_ARRAY || 27*c6fdcd6eSRoman Gushchin inner_map->map_type == BPF_MAP_TYPE_CGROUP_STORAGE || 28*c6fdcd6eSRoman Gushchin inner_map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) { 2956f668dfSMartin KaFai Lau fdput(f); 3056f668dfSMartin KaFai Lau return ERR_PTR(-ENOTSUPP); 3156f668dfSMartin KaFai Lau } 3256f668dfSMartin KaFai Lau 3356f668dfSMartin KaFai Lau /* Does not support >1 level map-in-map */ 3456f668dfSMartin KaFai Lau if (inner_map->inner_map_meta) { 3556f668dfSMartin KaFai Lau fdput(f); 3656f668dfSMartin KaFai Lau return ERR_PTR(-EINVAL); 3756f668dfSMartin KaFai Lau } 3856f668dfSMartin KaFai Lau 3956f668dfSMartin KaFai Lau inner_map_meta = kzalloc(sizeof(*inner_map_meta), GFP_USER); 4056f668dfSMartin KaFai Lau if (!inner_map_meta) { 4156f668dfSMartin KaFai Lau fdput(f); 4256f668dfSMartin KaFai Lau return ERR_PTR(-ENOMEM); 4356f668dfSMartin KaFai Lau } 4456f668dfSMartin KaFai Lau 4556f668dfSMartin KaFai Lau inner_map_meta->map_type = inner_map->map_type; 4656f668dfSMartin KaFai Lau inner_map_meta->key_size = inner_map->key_size; 4756f668dfSMartin KaFai Lau inner_map_meta->value_size = inner_map->value_size; 4856f668dfSMartin KaFai Lau inner_map_meta->map_flags = inner_map->map_flags; 4956f668dfSMartin KaFai Lau inner_map_meta->ops = inner_map->ops; 5056f668dfSMartin KaFai Lau inner_map_meta->max_entries = inner_map->max_entries; 5156f668dfSMartin KaFai Lau 5256f668dfSMartin KaFai Lau fdput(f); 5356f668dfSMartin KaFai Lau return inner_map_meta; 5456f668dfSMartin KaFai Lau } 5556f668dfSMartin KaFai Lau 5656f668dfSMartin KaFai Lau void bpf_map_meta_free(struct bpf_map *map_meta) 5756f668dfSMartin KaFai Lau { 5856f668dfSMartin KaFai Lau kfree(map_meta); 5956f668dfSMartin KaFai Lau } 6056f668dfSMartin KaFai Lau 6156f668dfSMartin KaFai Lau bool bpf_map_meta_equal(const struct bpf_map *meta0, 6256f668dfSMartin KaFai Lau const struct bpf_map *meta1) 6356f668dfSMartin KaFai Lau { 6456f668dfSMartin KaFai Lau /* No need to compare ops because it is covered by map_type */ 6556f668dfSMartin KaFai Lau return meta0->map_type == meta1->map_type && 6656f668dfSMartin KaFai Lau meta0->key_size == meta1->key_size && 6756f668dfSMartin KaFai Lau meta0->value_size == meta1->value_size && 6856f668dfSMartin KaFai Lau meta0->map_flags == meta1->map_flags && 6956f668dfSMartin KaFai Lau meta0->max_entries == meta1->max_entries; 7056f668dfSMartin KaFai Lau } 7156f668dfSMartin KaFai Lau 7256f668dfSMartin KaFai Lau void *bpf_map_fd_get_ptr(struct bpf_map *map, 7356f668dfSMartin KaFai Lau struct file *map_file /* not used */, 7456f668dfSMartin KaFai Lau int ufd) 7556f668dfSMartin KaFai Lau { 7656f668dfSMartin KaFai Lau struct bpf_map *inner_map; 7756f668dfSMartin KaFai Lau struct fd f; 7856f668dfSMartin KaFai Lau 7956f668dfSMartin KaFai Lau f = fdget(ufd); 8056f668dfSMartin KaFai Lau inner_map = __bpf_map_get(f); 8156f668dfSMartin KaFai Lau if (IS_ERR(inner_map)) 8256f668dfSMartin KaFai Lau return inner_map; 8356f668dfSMartin KaFai Lau 8456f668dfSMartin KaFai Lau if (bpf_map_meta_equal(map->inner_map_meta, inner_map)) 8556f668dfSMartin KaFai Lau inner_map = bpf_map_inc(inner_map, false); 8656f668dfSMartin KaFai Lau else 8756f668dfSMartin KaFai Lau inner_map = ERR_PTR(-EINVAL); 8856f668dfSMartin KaFai Lau 8956f668dfSMartin KaFai Lau fdput(f); 9056f668dfSMartin KaFai Lau return inner_map; 9156f668dfSMartin KaFai Lau } 9256f668dfSMartin KaFai Lau 9356f668dfSMartin KaFai Lau void bpf_map_fd_put_ptr(void *ptr) 9456f668dfSMartin KaFai Lau { 9556f668dfSMartin KaFai Lau /* ptr->ops->map_free() has to go through one 9656f668dfSMartin KaFai Lau * rcu grace period by itself. 9756f668dfSMartin KaFai Lau */ 9856f668dfSMartin KaFai Lau bpf_map_put(ptr); 9956f668dfSMartin KaFai Lau } 10014dc6f04SMartin KaFai Lau 10114dc6f04SMartin KaFai Lau u32 bpf_map_fd_sys_lookup_elem(void *ptr) 10214dc6f04SMartin KaFai Lau { 10314dc6f04SMartin KaFai Lau return ((struct bpf_map *)ptr)->id; 10414dc6f04SMartin KaFai Lau } 105