199c55f7dSAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 299c55f7dSAlexei Starovoitov * 399c55f7dSAlexei Starovoitov * This program is free software; you can redistribute it and/or 499c55f7dSAlexei Starovoitov * modify it under the terms of version 2 of the GNU General Public 599c55f7dSAlexei Starovoitov * License as published by the Free Software Foundation. 699c55f7dSAlexei Starovoitov * 799c55f7dSAlexei Starovoitov * This program is distributed in the hope that it will be useful, but 899c55f7dSAlexei Starovoitov * WITHOUT ANY WARRANTY; without even the implied warranty of 999c55f7dSAlexei Starovoitov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1099c55f7dSAlexei Starovoitov * General Public License for more details. 1199c55f7dSAlexei Starovoitov */ 1299c55f7dSAlexei Starovoitov #include <linux/bpf.h> 13a67edbf4SDaniel Borkmann #include <linux/bpf_trace.h> 1499c55f7dSAlexei Starovoitov #include <linux/syscalls.h> 1599c55f7dSAlexei Starovoitov #include <linux/slab.h> 163f07c014SIngo Molnar #include <linux/sched/signal.h> 17d407bd25SDaniel Borkmann #include <linux/vmalloc.h> 18d407bd25SDaniel Borkmann #include <linux/mmzone.h> 1999c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h> 20db20fd2bSAlexei Starovoitov #include <linux/file.h> 2109756af4SAlexei Starovoitov #include <linux/license.h> 2209756af4SAlexei Starovoitov #include <linux/filter.h> 232541517cSAlexei Starovoitov #include <linux/version.h> 24535e7b4bSMickaël Salaün #include <linux/kernel.h> 25dc4bb0e2SMartin KaFai Lau #include <linux/idr.h> 2699c55f7dSAlexei Starovoitov 2714dc6f04SMartin KaFai Lau #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PROG_ARRAY || \ 2814dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ 2914dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ 3014dc6f04SMartin KaFai Lau (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) 3114dc6f04SMartin KaFai Lau #define IS_FD_HASH(map) ((map)->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) 3214dc6f04SMartin KaFai Lau #define IS_FD_MAP(map) (IS_FD_ARRAY(map) || IS_FD_HASH(map)) 3314dc6f04SMartin KaFai Lau 34b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 35dc4bb0e2SMartin KaFai Lau static DEFINE_IDR(prog_idr); 36dc4bb0e2SMartin KaFai Lau static DEFINE_SPINLOCK(prog_idr_lock); 37f3f1c054SMartin KaFai Lau static DEFINE_IDR(map_idr); 38f3f1c054SMartin KaFai Lau static DEFINE_SPINLOCK(map_idr_lock); 39b121d1e7SAlexei Starovoitov 401be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly; 411be7f75dSAlexei Starovoitov 4240077e0cSJohannes Berg static const struct bpf_map_ops * const bpf_map_types[] = { 4340077e0cSJohannes Berg #define BPF_PROG_TYPE(_id, _ops) 4440077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) \ 4540077e0cSJohannes Berg [_id] = &_ops, 4640077e0cSJohannes Berg #include <linux/bpf_types.h> 4740077e0cSJohannes Berg #undef BPF_PROG_TYPE 4840077e0cSJohannes Berg #undef BPF_MAP_TYPE 4940077e0cSJohannes Berg }; 5099c55f7dSAlexei Starovoitov 5199c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 5299c55f7dSAlexei Starovoitov { 5399c55f7dSAlexei Starovoitov struct bpf_map *map; 5499c55f7dSAlexei Starovoitov 5540077e0cSJohannes Berg if (attr->map_type >= ARRAY_SIZE(bpf_map_types) || 5640077e0cSJohannes Berg !bpf_map_types[attr->map_type]) 5740077e0cSJohannes Berg return ERR_PTR(-EINVAL); 5840077e0cSJohannes Berg 5940077e0cSJohannes Berg map = bpf_map_types[attr->map_type]->map_alloc(attr); 6099c55f7dSAlexei Starovoitov if (IS_ERR(map)) 6199c55f7dSAlexei Starovoitov return map; 6240077e0cSJohannes Berg map->ops = bpf_map_types[attr->map_type]; 6399c55f7dSAlexei Starovoitov map->map_type = attr->map_type; 6499c55f7dSAlexei Starovoitov return map; 6599c55f7dSAlexei Starovoitov } 6699c55f7dSAlexei Starovoitov 67d407bd25SDaniel Borkmann void *bpf_map_area_alloc(size_t size) 68d407bd25SDaniel Borkmann { 69d407bd25SDaniel Borkmann /* We definitely need __GFP_NORETRY, so OOM killer doesn't 70d407bd25SDaniel Borkmann * trigger under memory pressure as we really just want to 71d407bd25SDaniel Borkmann * fail instead. 72d407bd25SDaniel Borkmann */ 73d407bd25SDaniel Borkmann const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO; 74d407bd25SDaniel Borkmann void *area; 75d407bd25SDaniel Borkmann 76d407bd25SDaniel Borkmann if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { 77d407bd25SDaniel Borkmann area = kmalloc(size, GFP_USER | flags); 78d407bd25SDaniel Borkmann if (area != NULL) 79d407bd25SDaniel Borkmann return area; 80d407bd25SDaniel Borkmann } 81d407bd25SDaniel Borkmann 8219809c2dSMichal Hocko return __vmalloc(size, GFP_KERNEL | flags, PAGE_KERNEL); 83d407bd25SDaniel Borkmann } 84d407bd25SDaniel Borkmann 85d407bd25SDaniel Borkmann void bpf_map_area_free(void *area) 86d407bd25SDaniel Borkmann { 87d407bd25SDaniel Borkmann kvfree(area); 88d407bd25SDaniel Borkmann } 89d407bd25SDaniel Borkmann 906c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages) 916c905981SAlexei Starovoitov { 926c905981SAlexei Starovoitov struct user_struct *user = get_current_user(); 936c905981SAlexei Starovoitov unsigned long memlock_limit, cur; 946c905981SAlexei Starovoitov 956c905981SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 966c905981SAlexei Starovoitov cur = atomic_long_read(&user->locked_vm); 976c905981SAlexei Starovoitov free_uid(user); 986c905981SAlexei Starovoitov if (cur + pages > memlock_limit) 996c905981SAlexei Starovoitov return -EPERM; 1006c905981SAlexei Starovoitov return 0; 1016c905981SAlexei Starovoitov } 1026c905981SAlexei Starovoitov 103aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map) 104aaac3ba9SAlexei Starovoitov { 105aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 106aaac3ba9SAlexei Starovoitov unsigned long memlock_limit; 107aaac3ba9SAlexei Starovoitov 108aaac3ba9SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 109aaac3ba9SAlexei Starovoitov 110aaac3ba9SAlexei Starovoitov atomic_long_add(map->pages, &user->locked_vm); 111aaac3ba9SAlexei Starovoitov 112aaac3ba9SAlexei Starovoitov if (atomic_long_read(&user->locked_vm) > memlock_limit) { 113aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 114aaac3ba9SAlexei Starovoitov free_uid(user); 115aaac3ba9SAlexei Starovoitov return -EPERM; 116aaac3ba9SAlexei Starovoitov } 117aaac3ba9SAlexei Starovoitov map->user = user; 118aaac3ba9SAlexei Starovoitov return 0; 119aaac3ba9SAlexei Starovoitov } 120aaac3ba9SAlexei Starovoitov 121aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map) 122aaac3ba9SAlexei Starovoitov { 123aaac3ba9SAlexei Starovoitov struct user_struct *user = map->user; 124aaac3ba9SAlexei Starovoitov 125aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 126aaac3ba9SAlexei Starovoitov free_uid(user); 127aaac3ba9SAlexei Starovoitov } 128aaac3ba9SAlexei Starovoitov 129f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map) 130f3f1c054SMartin KaFai Lau { 131f3f1c054SMartin KaFai Lau int id; 132f3f1c054SMartin KaFai Lau 133f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 134f3f1c054SMartin KaFai Lau id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC); 135f3f1c054SMartin KaFai Lau if (id > 0) 136f3f1c054SMartin KaFai Lau map->id = id; 137f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 138f3f1c054SMartin KaFai Lau 139f3f1c054SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 140f3f1c054SMartin KaFai Lau return -ENOSPC; 141f3f1c054SMartin KaFai Lau 142f3f1c054SMartin KaFai Lau return id > 0 ? 0 : id; 143f3f1c054SMartin KaFai Lau } 144f3f1c054SMartin KaFai Lau 145bd5f5f4eSMartin KaFai Lau static void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) 146f3f1c054SMartin KaFai Lau { 147bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 148f3f1c054SMartin KaFai Lau spin_lock_bh(&map_idr_lock); 149bd5f5f4eSMartin KaFai Lau else 150bd5f5f4eSMartin KaFai Lau __acquire(&map_idr_lock); 151bd5f5f4eSMartin KaFai Lau 152f3f1c054SMartin KaFai Lau idr_remove(&map_idr, map->id); 153bd5f5f4eSMartin KaFai Lau 154bd5f5f4eSMartin KaFai Lau if (do_idr_lock) 155f3f1c054SMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 156bd5f5f4eSMartin KaFai Lau else 157bd5f5f4eSMartin KaFai Lau __release(&map_idr_lock); 158f3f1c054SMartin KaFai Lau } 159f3f1c054SMartin KaFai Lau 16099c55f7dSAlexei Starovoitov /* called from workqueue */ 16199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 16299c55f7dSAlexei Starovoitov { 16399c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 16499c55f7dSAlexei Starovoitov 165aaac3ba9SAlexei Starovoitov bpf_map_uncharge_memlock(map); 16699c55f7dSAlexei Starovoitov /* implementation dependent freeing */ 16799c55f7dSAlexei Starovoitov map->ops->map_free(map); 16899c55f7dSAlexei Starovoitov } 16999c55f7dSAlexei Starovoitov 170c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 171c9da161cSDaniel Borkmann { 172c9da161cSDaniel Borkmann if (atomic_dec_and_test(&map->usercnt)) { 173c9da161cSDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) 174c9da161cSDaniel Borkmann bpf_fd_array_map_clear(map); 175c9da161cSDaniel Borkmann } 176c9da161cSDaniel Borkmann } 177c9da161cSDaniel Borkmann 17899c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 17999c55f7dSAlexei Starovoitov * (unrelying map implementation ops->map_free() might sleep) 18099c55f7dSAlexei Starovoitov */ 181bd5f5f4eSMartin KaFai Lau static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) 18299c55f7dSAlexei Starovoitov { 18399c55f7dSAlexei Starovoitov if (atomic_dec_and_test(&map->refcnt)) { 18434ad5580SMartin KaFai Lau /* bpf_map_free_id() must be called first */ 185bd5f5f4eSMartin KaFai Lau bpf_map_free_id(map, do_idr_lock); 18699c55f7dSAlexei Starovoitov INIT_WORK(&map->work, bpf_map_free_deferred); 18799c55f7dSAlexei Starovoitov schedule_work(&map->work); 18899c55f7dSAlexei Starovoitov } 18999c55f7dSAlexei Starovoitov } 19099c55f7dSAlexei Starovoitov 191bd5f5f4eSMartin KaFai Lau void bpf_map_put(struct bpf_map *map) 192bd5f5f4eSMartin KaFai Lau { 193bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, true); 194bd5f5f4eSMartin KaFai Lau } 195bd5f5f4eSMartin KaFai Lau 196c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 197c9da161cSDaniel Borkmann { 198c9da161cSDaniel Borkmann bpf_map_put_uref(map); 199c9da161cSDaniel Borkmann bpf_map_put(map); 200c9da161cSDaniel Borkmann } 201c9da161cSDaniel Borkmann 20299c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 20399c55f7dSAlexei Starovoitov { 20461d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 20561d1b6a4SDaniel Borkmann 20661d1b6a4SDaniel Borkmann if (map->ops->map_release) 20761d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 20861d1b6a4SDaniel Borkmann 20961d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 21099c55f7dSAlexei Starovoitov return 0; 21199c55f7dSAlexei Starovoitov } 21299c55f7dSAlexei Starovoitov 213f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 214f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 215f99bf205SDaniel Borkmann { 216f99bf205SDaniel Borkmann const struct bpf_map *map = filp->private_data; 21721116b70SDaniel Borkmann const struct bpf_array *array; 21821116b70SDaniel Borkmann u32 owner_prog_type = 0; 2199780c0abSDaniel Borkmann u32 owner_jited = 0; 22021116b70SDaniel Borkmann 22121116b70SDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 22221116b70SDaniel Borkmann array = container_of(map, struct bpf_array, map); 22321116b70SDaniel Borkmann owner_prog_type = array->owner_prog_type; 2249780c0abSDaniel Borkmann owner_jited = array->owner_jited; 22521116b70SDaniel Borkmann } 226f99bf205SDaniel Borkmann 227f99bf205SDaniel Borkmann seq_printf(m, 228f99bf205SDaniel Borkmann "map_type:\t%u\n" 229f99bf205SDaniel Borkmann "key_size:\t%u\n" 230f99bf205SDaniel Borkmann "value_size:\t%u\n" 231322cea2fSDaniel Borkmann "max_entries:\t%u\n" 23221116b70SDaniel Borkmann "map_flags:\t%#x\n" 23321116b70SDaniel Borkmann "memlock:\t%llu\n", 234f99bf205SDaniel Borkmann map->map_type, 235f99bf205SDaniel Borkmann map->key_size, 236f99bf205SDaniel Borkmann map->value_size, 237322cea2fSDaniel Borkmann map->max_entries, 23821116b70SDaniel Borkmann map->map_flags, 23921116b70SDaniel Borkmann map->pages * 1ULL << PAGE_SHIFT); 24021116b70SDaniel Borkmann 2419780c0abSDaniel Borkmann if (owner_prog_type) { 24221116b70SDaniel Borkmann seq_printf(m, "owner_prog_type:\t%u\n", 24321116b70SDaniel Borkmann owner_prog_type); 2449780c0abSDaniel Borkmann seq_printf(m, "owner_jited:\t%u\n", 2459780c0abSDaniel Borkmann owner_jited); 2469780c0abSDaniel Borkmann } 247f99bf205SDaniel Borkmann } 248f99bf205SDaniel Borkmann #endif 249f99bf205SDaniel Borkmann 25099c55f7dSAlexei Starovoitov static const struct file_operations bpf_map_fops = { 251f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 252f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 253f99bf205SDaniel Borkmann #endif 25499c55f7dSAlexei Starovoitov .release = bpf_map_release, 25599c55f7dSAlexei Starovoitov }; 25699c55f7dSAlexei Starovoitov 257b2197755SDaniel Borkmann int bpf_map_new_fd(struct bpf_map *map) 258aa79781bSDaniel Borkmann { 259aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 260aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 261aa79781bSDaniel Borkmann } 262aa79781bSDaniel Borkmann 26399c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 26499c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 26599c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 26699c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 26799c55f7dSAlexei Starovoitov sizeof(*attr) - \ 26899c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 26999c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 27099c55f7dSAlexei Starovoitov 27156f668dfSMartin KaFai Lau #define BPF_MAP_CREATE_LAST_FIELD inner_map_fd 27299c55f7dSAlexei Starovoitov /* called via syscall */ 27399c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 27499c55f7dSAlexei Starovoitov { 27599c55f7dSAlexei Starovoitov struct bpf_map *map; 27699c55f7dSAlexei Starovoitov int err; 27799c55f7dSAlexei Starovoitov 27899c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 27999c55f7dSAlexei Starovoitov if (err) 28099c55f7dSAlexei Starovoitov return -EINVAL; 28199c55f7dSAlexei Starovoitov 28299c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 28399c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 28499c55f7dSAlexei Starovoitov if (IS_ERR(map)) 28599c55f7dSAlexei Starovoitov return PTR_ERR(map); 28699c55f7dSAlexei Starovoitov 28799c55f7dSAlexei Starovoitov atomic_set(&map->refcnt, 1); 288c9da161cSDaniel Borkmann atomic_set(&map->usercnt, 1); 28999c55f7dSAlexei Starovoitov 290aaac3ba9SAlexei Starovoitov err = bpf_map_charge_memlock(map); 291aaac3ba9SAlexei Starovoitov if (err) 29220b2b24fSDaniel Borkmann goto free_map_nouncharge; 293aaac3ba9SAlexei Starovoitov 294f3f1c054SMartin KaFai Lau err = bpf_map_alloc_id(map); 295f3f1c054SMartin KaFai Lau if (err) 296f3f1c054SMartin KaFai Lau goto free_map; 297f3f1c054SMartin KaFai Lau 298aa79781bSDaniel Borkmann err = bpf_map_new_fd(map); 299bd5f5f4eSMartin KaFai Lau if (err < 0) { 300bd5f5f4eSMartin KaFai Lau /* failed to allocate fd. 301bd5f5f4eSMartin KaFai Lau * bpf_map_put() is needed because the above 302bd5f5f4eSMartin KaFai Lau * bpf_map_alloc_id() has published the map 303bd5f5f4eSMartin KaFai Lau * to the userspace and the userspace may 304bd5f5f4eSMartin KaFai Lau * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID. 305bd5f5f4eSMartin KaFai Lau */ 306bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 307bd5f5f4eSMartin KaFai Lau return err; 308bd5f5f4eSMartin KaFai Lau } 30999c55f7dSAlexei Starovoitov 310a67edbf4SDaniel Borkmann trace_bpf_map_create(map, err); 31199c55f7dSAlexei Starovoitov return err; 31299c55f7dSAlexei Starovoitov 31399c55f7dSAlexei Starovoitov free_map: 31420b2b24fSDaniel Borkmann bpf_map_uncharge_memlock(map); 31520b2b24fSDaniel Borkmann free_map_nouncharge: 31699c55f7dSAlexei Starovoitov map->ops->map_free(map); 31799c55f7dSAlexei Starovoitov return err; 31899c55f7dSAlexei Starovoitov } 31999c55f7dSAlexei Starovoitov 320db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 321db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 322db20fd2bSAlexei Starovoitov */ 323c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 324db20fd2bSAlexei Starovoitov { 325db20fd2bSAlexei Starovoitov if (!f.file) 326db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 327db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 328db20fd2bSAlexei Starovoitov fdput(f); 329db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 330db20fd2bSAlexei Starovoitov } 331db20fd2bSAlexei Starovoitov 332c2101297SDaniel Borkmann return f.file->private_data; 333c2101297SDaniel Borkmann } 334c2101297SDaniel Borkmann 33592117d84SAlexei Starovoitov /* prog's and map's refcnt limit */ 33692117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768 33792117d84SAlexei Starovoitov 33892117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) 339c9da161cSDaniel Borkmann { 34092117d84SAlexei Starovoitov if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { 34192117d84SAlexei Starovoitov atomic_dec(&map->refcnt); 34292117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 34392117d84SAlexei Starovoitov } 344c9da161cSDaniel Borkmann if (uref) 345c9da161cSDaniel Borkmann atomic_inc(&map->usercnt); 34692117d84SAlexei Starovoitov return map; 347c9da161cSDaniel Borkmann } 348c9da161cSDaniel Borkmann 349c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 350c2101297SDaniel Borkmann { 351c2101297SDaniel Borkmann struct fd f = fdget(ufd); 352c2101297SDaniel Borkmann struct bpf_map *map; 353c2101297SDaniel Borkmann 354c2101297SDaniel Borkmann map = __bpf_map_get(f); 355c2101297SDaniel Borkmann if (IS_ERR(map)) 356c2101297SDaniel Borkmann return map; 357c2101297SDaniel Borkmann 35892117d84SAlexei Starovoitov map = bpf_map_inc(map, true); 359c2101297SDaniel Borkmann fdput(f); 360db20fd2bSAlexei Starovoitov 361db20fd2bSAlexei Starovoitov return map; 362db20fd2bSAlexei Starovoitov } 363db20fd2bSAlexei Starovoitov 364bd5f5f4eSMartin KaFai Lau /* map_idr_lock should have been held */ 365bd5f5f4eSMartin KaFai Lau static struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map, 366bd5f5f4eSMartin KaFai Lau bool uref) 367bd5f5f4eSMartin KaFai Lau { 368bd5f5f4eSMartin KaFai Lau int refold; 369bd5f5f4eSMartin KaFai Lau 370bd5f5f4eSMartin KaFai Lau refold = __atomic_add_unless(&map->refcnt, 1, 0); 371bd5f5f4eSMartin KaFai Lau 372bd5f5f4eSMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 373bd5f5f4eSMartin KaFai Lau __bpf_map_put(map, false); 374bd5f5f4eSMartin KaFai Lau return ERR_PTR(-EBUSY); 375bd5f5f4eSMartin KaFai Lau } 376bd5f5f4eSMartin KaFai Lau 377bd5f5f4eSMartin KaFai Lau if (!refold) 378bd5f5f4eSMartin KaFai Lau return ERR_PTR(-ENOENT); 379bd5f5f4eSMartin KaFai Lau 380bd5f5f4eSMartin KaFai Lau if (uref) 381bd5f5f4eSMartin KaFai Lau atomic_inc(&map->usercnt); 382bd5f5f4eSMartin KaFai Lau 383bd5f5f4eSMartin KaFai Lau return map; 384bd5f5f4eSMartin KaFai Lau } 385bd5f5f4eSMartin KaFai Lau 386b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 387b8cdc051SAlexei Starovoitov { 388b8cdc051SAlexei Starovoitov return -ENOTSUPP; 389b8cdc051SAlexei Starovoitov } 390b8cdc051SAlexei Starovoitov 391db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 392db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 393db20fd2bSAlexei Starovoitov 394db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 395db20fd2bSAlexei Starovoitov { 396535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 397535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 398db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 399db20fd2bSAlexei Starovoitov struct bpf_map *map; 4008ebe667cSAlexei Starovoitov void *key, *value, *ptr; 40115a07b33SAlexei Starovoitov u32 value_size; 402592867bfSDaniel Borkmann struct fd f; 403db20fd2bSAlexei Starovoitov int err; 404db20fd2bSAlexei Starovoitov 405db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 406db20fd2bSAlexei Starovoitov return -EINVAL; 407db20fd2bSAlexei Starovoitov 408592867bfSDaniel Borkmann f = fdget(ufd); 409c2101297SDaniel Borkmann map = __bpf_map_get(f); 410db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 411db20fd2bSAlexei Starovoitov return PTR_ERR(map); 412db20fd2bSAlexei Starovoitov 413e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 414e4448ed8SAl Viro if (IS_ERR(key)) { 415e4448ed8SAl Viro err = PTR_ERR(key); 416db20fd2bSAlexei Starovoitov goto err_put; 417e4448ed8SAl Viro } 418db20fd2bSAlexei Starovoitov 41915a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4208f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 42115a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 42215a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 42314dc6f04SMartin KaFai Lau else if (IS_FD_MAP(map)) 42414dc6f04SMartin KaFai Lau value_size = sizeof(u32); 42515a07b33SAlexei Starovoitov else 42615a07b33SAlexei Starovoitov value_size = map->value_size; 42715a07b33SAlexei Starovoitov 4288ebe667cSAlexei Starovoitov err = -ENOMEM; 42915a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 430db20fd2bSAlexei Starovoitov if (!value) 4318ebe667cSAlexei Starovoitov goto free_key; 4328ebe667cSAlexei Starovoitov 4338f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 4348f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 43515a07b33SAlexei Starovoitov err = bpf_percpu_hash_copy(map, key, value); 43615a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 43715a07b33SAlexei Starovoitov err = bpf_percpu_array_copy(map, key, value); 438557c0c6eSAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 439557c0c6eSAlexei Starovoitov err = bpf_stackmap_copy(map, key, value); 44014dc6f04SMartin KaFai Lau } else if (IS_FD_ARRAY(map)) { 44114dc6f04SMartin KaFai Lau err = bpf_fd_array_map_lookup_elem(map, key, value); 44214dc6f04SMartin KaFai Lau } else if (IS_FD_HASH(map)) { 44314dc6f04SMartin KaFai Lau err = bpf_fd_htab_map_lookup_elem(map, key, value); 44415a07b33SAlexei Starovoitov } else { 4458ebe667cSAlexei Starovoitov rcu_read_lock(); 4468ebe667cSAlexei Starovoitov ptr = map->ops->map_lookup_elem(map, key); 4478ebe667cSAlexei Starovoitov if (ptr) 44815a07b33SAlexei Starovoitov memcpy(value, ptr, value_size); 4498ebe667cSAlexei Starovoitov rcu_read_unlock(); 45015a07b33SAlexei Starovoitov err = ptr ? 0 : -ENOENT; 45115a07b33SAlexei Starovoitov } 4528ebe667cSAlexei Starovoitov 45315a07b33SAlexei Starovoitov if (err) 4548ebe667cSAlexei Starovoitov goto free_value; 455db20fd2bSAlexei Starovoitov 456db20fd2bSAlexei Starovoitov err = -EFAULT; 45715a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 4588ebe667cSAlexei Starovoitov goto free_value; 459db20fd2bSAlexei Starovoitov 460a67edbf4SDaniel Borkmann trace_bpf_map_lookup_elem(map, ufd, key, value); 461db20fd2bSAlexei Starovoitov err = 0; 462db20fd2bSAlexei Starovoitov 4638ebe667cSAlexei Starovoitov free_value: 4648ebe667cSAlexei Starovoitov kfree(value); 465db20fd2bSAlexei Starovoitov free_key: 466db20fd2bSAlexei Starovoitov kfree(key); 467db20fd2bSAlexei Starovoitov err_put: 468db20fd2bSAlexei Starovoitov fdput(f); 469db20fd2bSAlexei Starovoitov return err; 470db20fd2bSAlexei Starovoitov } 471db20fd2bSAlexei Starovoitov 4723274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 473db20fd2bSAlexei Starovoitov 474db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 475db20fd2bSAlexei Starovoitov { 476535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 477535e7b4bSMickaël Salaün void __user *uvalue = u64_to_user_ptr(attr->value); 478db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 479db20fd2bSAlexei Starovoitov struct bpf_map *map; 480db20fd2bSAlexei Starovoitov void *key, *value; 48115a07b33SAlexei Starovoitov u32 value_size; 482592867bfSDaniel Borkmann struct fd f; 483db20fd2bSAlexei Starovoitov int err; 484db20fd2bSAlexei Starovoitov 485db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 486db20fd2bSAlexei Starovoitov return -EINVAL; 487db20fd2bSAlexei Starovoitov 488592867bfSDaniel Borkmann f = fdget(ufd); 489c2101297SDaniel Borkmann map = __bpf_map_get(f); 490db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 491db20fd2bSAlexei Starovoitov return PTR_ERR(map); 492db20fd2bSAlexei Starovoitov 493e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 494e4448ed8SAl Viro if (IS_ERR(key)) { 495e4448ed8SAl Viro err = PTR_ERR(key); 496db20fd2bSAlexei Starovoitov goto err_put; 497e4448ed8SAl Viro } 498db20fd2bSAlexei Starovoitov 49915a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5008f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH || 50115a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 50215a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 50315a07b33SAlexei Starovoitov else 50415a07b33SAlexei Starovoitov value_size = map->value_size; 50515a07b33SAlexei Starovoitov 506db20fd2bSAlexei Starovoitov err = -ENOMEM; 50715a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 508db20fd2bSAlexei Starovoitov if (!value) 509db20fd2bSAlexei Starovoitov goto free_key; 510db20fd2bSAlexei Starovoitov 511db20fd2bSAlexei Starovoitov err = -EFAULT; 51215a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 513db20fd2bSAlexei Starovoitov goto free_value; 514db20fd2bSAlexei Starovoitov 515b121d1e7SAlexei Starovoitov /* must increment bpf_prog_active to avoid kprobe+bpf triggering from 516b121d1e7SAlexei Starovoitov * inside bpf map update or delete otherwise deadlocks are possible 517b121d1e7SAlexei Starovoitov */ 518b121d1e7SAlexei Starovoitov preempt_disable(); 519b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 5208f844938SMartin KaFai Lau if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 5218f844938SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { 52215a07b33SAlexei Starovoitov err = bpf_percpu_hash_update(map, key, value, attr->flags); 52315a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 52415a07b33SAlexei Starovoitov err = bpf_percpu_array_update(map, key, value, attr->flags); 525d056a788SDaniel Borkmann } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || 5264ed8ec52SMartin KaFai Lau map->map_type == BPF_MAP_TYPE_PROG_ARRAY || 52756f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || 52856f668dfSMartin KaFai Lau map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { 529d056a788SDaniel Borkmann rcu_read_lock(); 530d056a788SDaniel Borkmann err = bpf_fd_array_map_update_elem(map, f.file, key, value, 531d056a788SDaniel Borkmann attr->flags); 532d056a788SDaniel Borkmann rcu_read_unlock(); 533bcc6b1b7SMartin KaFai Lau } else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { 534bcc6b1b7SMartin KaFai Lau rcu_read_lock(); 535bcc6b1b7SMartin KaFai Lau err = bpf_fd_htab_map_update_elem(map, f.file, key, value, 536bcc6b1b7SMartin KaFai Lau attr->flags); 537bcc6b1b7SMartin KaFai Lau rcu_read_unlock(); 53815a07b33SAlexei Starovoitov } else { 539db20fd2bSAlexei Starovoitov rcu_read_lock(); 5403274f520SAlexei Starovoitov err = map->ops->map_update_elem(map, key, value, attr->flags); 541db20fd2bSAlexei Starovoitov rcu_read_unlock(); 54215a07b33SAlexei Starovoitov } 543b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 544b121d1e7SAlexei Starovoitov preempt_enable(); 545db20fd2bSAlexei Starovoitov 546a67edbf4SDaniel Borkmann if (!err) 547a67edbf4SDaniel Borkmann trace_bpf_map_update_elem(map, ufd, key, value); 548db20fd2bSAlexei Starovoitov free_value: 549db20fd2bSAlexei Starovoitov kfree(value); 550db20fd2bSAlexei Starovoitov free_key: 551db20fd2bSAlexei Starovoitov kfree(key); 552db20fd2bSAlexei Starovoitov err_put: 553db20fd2bSAlexei Starovoitov fdput(f); 554db20fd2bSAlexei Starovoitov return err; 555db20fd2bSAlexei Starovoitov } 556db20fd2bSAlexei Starovoitov 557db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 558db20fd2bSAlexei Starovoitov 559db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 560db20fd2bSAlexei Starovoitov { 561535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 562db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 563db20fd2bSAlexei Starovoitov struct bpf_map *map; 564592867bfSDaniel Borkmann struct fd f; 565db20fd2bSAlexei Starovoitov void *key; 566db20fd2bSAlexei Starovoitov int err; 567db20fd2bSAlexei Starovoitov 568db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 569db20fd2bSAlexei Starovoitov return -EINVAL; 570db20fd2bSAlexei Starovoitov 571592867bfSDaniel Borkmann f = fdget(ufd); 572c2101297SDaniel Borkmann map = __bpf_map_get(f); 573db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 574db20fd2bSAlexei Starovoitov return PTR_ERR(map); 575db20fd2bSAlexei Starovoitov 576e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 577e4448ed8SAl Viro if (IS_ERR(key)) { 578e4448ed8SAl Viro err = PTR_ERR(key); 579db20fd2bSAlexei Starovoitov goto err_put; 580e4448ed8SAl Viro } 581db20fd2bSAlexei Starovoitov 582b121d1e7SAlexei Starovoitov preempt_disable(); 583b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 584db20fd2bSAlexei Starovoitov rcu_read_lock(); 585db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 586db20fd2bSAlexei Starovoitov rcu_read_unlock(); 587b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 588b121d1e7SAlexei Starovoitov preempt_enable(); 589db20fd2bSAlexei Starovoitov 590a67edbf4SDaniel Borkmann if (!err) 591a67edbf4SDaniel Borkmann trace_bpf_map_delete_elem(map, ufd, key); 592db20fd2bSAlexei Starovoitov kfree(key); 593db20fd2bSAlexei Starovoitov err_put: 594db20fd2bSAlexei Starovoitov fdput(f); 595db20fd2bSAlexei Starovoitov return err; 596db20fd2bSAlexei Starovoitov } 597db20fd2bSAlexei Starovoitov 598db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 599db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 600db20fd2bSAlexei Starovoitov 601db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 602db20fd2bSAlexei Starovoitov { 603535e7b4bSMickaël Salaün void __user *ukey = u64_to_user_ptr(attr->key); 604535e7b4bSMickaël Salaün void __user *unext_key = u64_to_user_ptr(attr->next_key); 605db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 606db20fd2bSAlexei Starovoitov struct bpf_map *map; 607db20fd2bSAlexei Starovoitov void *key, *next_key; 608592867bfSDaniel Borkmann struct fd f; 609db20fd2bSAlexei Starovoitov int err; 610db20fd2bSAlexei Starovoitov 611db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 612db20fd2bSAlexei Starovoitov return -EINVAL; 613db20fd2bSAlexei Starovoitov 614592867bfSDaniel Borkmann f = fdget(ufd); 615c2101297SDaniel Borkmann map = __bpf_map_get(f); 616db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 617db20fd2bSAlexei Starovoitov return PTR_ERR(map); 618db20fd2bSAlexei Starovoitov 6198fe45924STeng Qin if (ukey) { 620e4448ed8SAl Viro key = memdup_user(ukey, map->key_size); 621e4448ed8SAl Viro if (IS_ERR(key)) { 622e4448ed8SAl Viro err = PTR_ERR(key); 623db20fd2bSAlexei Starovoitov goto err_put; 624e4448ed8SAl Viro } 6258fe45924STeng Qin } else { 6268fe45924STeng Qin key = NULL; 6278fe45924STeng Qin } 628db20fd2bSAlexei Starovoitov 629db20fd2bSAlexei Starovoitov err = -ENOMEM; 630db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 631db20fd2bSAlexei Starovoitov if (!next_key) 632db20fd2bSAlexei Starovoitov goto free_key; 633db20fd2bSAlexei Starovoitov 634db20fd2bSAlexei Starovoitov rcu_read_lock(); 635db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 636db20fd2bSAlexei Starovoitov rcu_read_unlock(); 637db20fd2bSAlexei Starovoitov if (err) 638db20fd2bSAlexei Starovoitov goto free_next_key; 639db20fd2bSAlexei Starovoitov 640db20fd2bSAlexei Starovoitov err = -EFAULT; 641db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 642db20fd2bSAlexei Starovoitov goto free_next_key; 643db20fd2bSAlexei Starovoitov 644a67edbf4SDaniel Borkmann trace_bpf_map_next_key(map, ufd, key, next_key); 645db20fd2bSAlexei Starovoitov err = 0; 646db20fd2bSAlexei Starovoitov 647db20fd2bSAlexei Starovoitov free_next_key: 648db20fd2bSAlexei Starovoitov kfree(next_key); 649db20fd2bSAlexei Starovoitov free_key: 650db20fd2bSAlexei Starovoitov kfree(key); 651db20fd2bSAlexei Starovoitov err_put: 652db20fd2bSAlexei Starovoitov fdput(f); 653db20fd2bSAlexei Starovoitov return err; 654db20fd2bSAlexei Starovoitov } 655db20fd2bSAlexei Starovoitov 656be9370a7SJohannes Berg static const struct bpf_verifier_ops * const bpf_prog_types[] = { 657be9370a7SJohannes Berg #define BPF_PROG_TYPE(_id, _ops) \ 658be9370a7SJohannes Berg [_id] = &_ops, 65940077e0cSJohannes Berg #define BPF_MAP_TYPE(_id, _ops) 660be9370a7SJohannes Berg #include <linux/bpf_types.h> 661be9370a7SJohannes Berg #undef BPF_PROG_TYPE 66240077e0cSJohannes Berg #undef BPF_MAP_TYPE 663be9370a7SJohannes Berg }; 66409756af4SAlexei Starovoitov 66509756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 66609756af4SAlexei Starovoitov { 667be9370a7SJohannes Berg if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type]) 668be9370a7SJohannes Berg return -EINVAL; 66909756af4SAlexei Starovoitov 670be9370a7SJohannes Berg prog->aux->ops = bpf_prog_types[type]; 67124701eceSDaniel Borkmann prog->type = type; 67209756af4SAlexei Starovoitov return 0; 67309756af4SAlexei Starovoitov } 67409756af4SAlexei Starovoitov 67509756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */ 67609756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux) 67709756af4SAlexei Starovoitov { 67809756af4SAlexei Starovoitov int i; 67909756af4SAlexei Starovoitov 68009756af4SAlexei Starovoitov for (i = 0; i < aux->used_map_cnt; i++) 68109756af4SAlexei Starovoitov bpf_map_put(aux->used_maps[i]); 68209756af4SAlexei Starovoitov 68309756af4SAlexei Starovoitov kfree(aux->used_maps); 68409756af4SAlexei Starovoitov } 68509756af4SAlexei Starovoitov 6865ccb071eSDaniel Borkmann int __bpf_prog_charge(struct user_struct *user, u32 pages) 6875ccb071eSDaniel Borkmann { 6885ccb071eSDaniel Borkmann unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 6895ccb071eSDaniel Borkmann unsigned long user_bufs; 6905ccb071eSDaniel Borkmann 6915ccb071eSDaniel Borkmann if (user) { 6925ccb071eSDaniel Borkmann user_bufs = atomic_long_add_return(pages, &user->locked_vm); 6935ccb071eSDaniel Borkmann if (user_bufs > memlock_limit) { 6945ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 6955ccb071eSDaniel Borkmann return -EPERM; 6965ccb071eSDaniel Borkmann } 6975ccb071eSDaniel Borkmann } 6985ccb071eSDaniel Borkmann 6995ccb071eSDaniel Borkmann return 0; 7005ccb071eSDaniel Borkmann } 7015ccb071eSDaniel Borkmann 7025ccb071eSDaniel Borkmann void __bpf_prog_uncharge(struct user_struct *user, u32 pages) 7035ccb071eSDaniel Borkmann { 7045ccb071eSDaniel Borkmann if (user) 7055ccb071eSDaniel Borkmann atomic_long_sub(pages, &user->locked_vm); 7065ccb071eSDaniel Borkmann } 7075ccb071eSDaniel Borkmann 708aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 709aaac3ba9SAlexei Starovoitov { 710aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 7115ccb071eSDaniel Borkmann int ret; 712aaac3ba9SAlexei Starovoitov 7135ccb071eSDaniel Borkmann ret = __bpf_prog_charge(user, prog->pages); 7145ccb071eSDaniel Borkmann if (ret) { 715aaac3ba9SAlexei Starovoitov free_uid(user); 7165ccb071eSDaniel Borkmann return ret; 717aaac3ba9SAlexei Starovoitov } 7185ccb071eSDaniel Borkmann 719aaac3ba9SAlexei Starovoitov prog->aux->user = user; 720aaac3ba9SAlexei Starovoitov return 0; 721aaac3ba9SAlexei Starovoitov } 722aaac3ba9SAlexei Starovoitov 723aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 724aaac3ba9SAlexei Starovoitov { 725aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 726aaac3ba9SAlexei Starovoitov 7275ccb071eSDaniel Borkmann __bpf_prog_uncharge(user, prog->pages); 728aaac3ba9SAlexei Starovoitov free_uid(user); 729aaac3ba9SAlexei Starovoitov } 730aaac3ba9SAlexei Starovoitov 731dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog) 732dc4bb0e2SMartin KaFai Lau { 733dc4bb0e2SMartin KaFai Lau int id; 734dc4bb0e2SMartin KaFai Lau 735dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 736dc4bb0e2SMartin KaFai Lau id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); 737dc4bb0e2SMartin KaFai Lau if (id > 0) 738dc4bb0e2SMartin KaFai Lau prog->aux->id = id; 739dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 740dc4bb0e2SMartin KaFai Lau 741dc4bb0e2SMartin KaFai Lau /* id is in [1, INT_MAX) */ 742dc4bb0e2SMartin KaFai Lau if (WARN_ON_ONCE(!id)) 743dc4bb0e2SMartin KaFai Lau return -ENOSPC; 744dc4bb0e2SMartin KaFai Lau 745dc4bb0e2SMartin KaFai Lau return id > 0 ? 0 : id; 746dc4bb0e2SMartin KaFai Lau } 747dc4bb0e2SMartin KaFai Lau 748b16d9aa4SMartin KaFai Lau static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 749dc4bb0e2SMartin KaFai Lau { 750dc4bb0e2SMartin KaFai Lau /* cBPF to eBPF migrations are currently not in the idr store. */ 751dc4bb0e2SMartin KaFai Lau if (!prog->aux->id) 752dc4bb0e2SMartin KaFai Lau return; 753dc4bb0e2SMartin KaFai Lau 754b16d9aa4SMartin KaFai Lau if (do_idr_lock) 755dc4bb0e2SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 756b16d9aa4SMartin KaFai Lau else 757b16d9aa4SMartin KaFai Lau __acquire(&prog_idr_lock); 758b16d9aa4SMartin KaFai Lau 759dc4bb0e2SMartin KaFai Lau idr_remove(&prog_idr, prog->aux->id); 760b16d9aa4SMartin KaFai Lau 761b16d9aa4SMartin KaFai Lau if (do_idr_lock) 762dc4bb0e2SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 763b16d9aa4SMartin KaFai Lau else 764b16d9aa4SMartin KaFai Lau __release(&prog_idr_lock); 765dc4bb0e2SMartin KaFai Lau } 766dc4bb0e2SMartin KaFai Lau 7671aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu) 768abf2e7d6SAlexei Starovoitov { 769abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 770abf2e7d6SAlexei Starovoitov 771abf2e7d6SAlexei Starovoitov free_used_maps(aux); 772aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 773abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 774abf2e7d6SAlexei Starovoitov } 775abf2e7d6SAlexei Starovoitov 776b16d9aa4SMartin KaFai Lau static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 77709756af4SAlexei Starovoitov { 778a67edbf4SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) { 779a67edbf4SDaniel Borkmann trace_bpf_prog_put_rcu(prog); 78034ad5580SMartin KaFai Lau /* bpf_prog_free_id() must be called first */ 781b16d9aa4SMartin KaFai Lau bpf_prog_free_id(prog, do_idr_lock); 78274451e66SDaniel Borkmann bpf_prog_kallsyms_del(prog); 7831aacde3dSDaniel Borkmann call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 78409756af4SAlexei Starovoitov } 785a67edbf4SDaniel Borkmann } 786b16d9aa4SMartin KaFai Lau 787b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog) 788b16d9aa4SMartin KaFai Lau { 789b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, true); 790b16d9aa4SMartin KaFai Lau } 791e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 79209756af4SAlexei Starovoitov 79309756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 79409756af4SAlexei Starovoitov { 79509756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 79609756af4SAlexei Starovoitov 7971aacde3dSDaniel Borkmann bpf_prog_put(prog); 79809756af4SAlexei Starovoitov return 0; 79909756af4SAlexei Starovoitov } 80009756af4SAlexei Starovoitov 8017bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8027bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 8037bd509e3SDaniel Borkmann { 8047bd509e3SDaniel Borkmann const struct bpf_prog *prog = filp->private_data; 805f1f7714eSDaniel Borkmann char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; 8067bd509e3SDaniel Borkmann 807f1f7714eSDaniel Borkmann bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); 8087bd509e3SDaniel Borkmann seq_printf(m, 8097bd509e3SDaniel Borkmann "prog_type:\t%u\n" 8107bd509e3SDaniel Borkmann "prog_jited:\t%u\n" 811f1f7714eSDaniel Borkmann "prog_tag:\t%s\n" 8127bd509e3SDaniel Borkmann "memlock:\t%llu\n", 8137bd509e3SDaniel Borkmann prog->type, 8147bd509e3SDaniel Borkmann prog->jited, 815f1f7714eSDaniel Borkmann prog_tag, 8167bd509e3SDaniel Borkmann prog->pages * 1ULL << PAGE_SHIFT); 8177bd509e3SDaniel Borkmann } 8187bd509e3SDaniel Borkmann #endif 8197bd509e3SDaniel Borkmann 82009756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = { 8217bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS 8227bd509e3SDaniel Borkmann .show_fdinfo = bpf_prog_show_fdinfo, 8237bd509e3SDaniel Borkmann #endif 82409756af4SAlexei Starovoitov .release = bpf_prog_release, 82509756af4SAlexei Starovoitov }; 82609756af4SAlexei Starovoitov 827b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 828aa79781bSDaniel Borkmann { 829aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 830aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 831aa79781bSDaniel Borkmann } 832aa79781bSDaniel Borkmann 833113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f) 83409756af4SAlexei Starovoitov { 83509756af4SAlexei Starovoitov if (!f.file) 83609756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 83709756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 83809756af4SAlexei Starovoitov fdput(f); 83909756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 84009756af4SAlexei Starovoitov } 84109756af4SAlexei Starovoitov 842c2101297SDaniel Borkmann return f.file->private_data; 84309756af4SAlexei Starovoitov } 84409756af4SAlexei Starovoitov 84559d3656dSBrenden Blanco struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) 84692117d84SAlexei Starovoitov { 84759d3656dSBrenden Blanco if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { 84859d3656dSBrenden Blanco atomic_sub(i, &prog->aux->refcnt); 84992117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 85092117d84SAlexei Starovoitov } 85192117d84SAlexei Starovoitov return prog; 85292117d84SAlexei Starovoitov } 85359d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add); 85459d3656dSBrenden Blanco 855c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i) 856c540594fSDaniel Borkmann { 857c540594fSDaniel Borkmann /* Only to be used for undoing previous bpf_prog_add() in some 858c540594fSDaniel Borkmann * error path. We still know that another entity in our call 859c540594fSDaniel Borkmann * path holds a reference to the program, thus atomic_sub() can 860c540594fSDaniel Borkmann * be safely used in such cases! 861c540594fSDaniel Borkmann */ 862c540594fSDaniel Borkmann WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); 863c540594fSDaniel Borkmann } 864c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub); 865c540594fSDaniel Borkmann 86659d3656dSBrenden Blanco struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) 86759d3656dSBrenden Blanco { 86859d3656dSBrenden Blanco return bpf_prog_add(prog, 1); 86959d3656dSBrenden Blanco } 87097bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc); 87192117d84SAlexei Starovoitov 872b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */ 873b16d9aa4SMartin KaFai Lau static struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) 874b16d9aa4SMartin KaFai Lau { 875b16d9aa4SMartin KaFai Lau int refold; 876b16d9aa4SMartin KaFai Lau 877b16d9aa4SMartin KaFai Lau refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0); 878b16d9aa4SMartin KaFai Lau 879b16d9aa4SMartin KaFai Lau if (refold >= BPF_MAX_REFCNT) { 880b16d9aa4SMartin KaFai Lau __bpf_prog_put(prog, false); 881b16d9aa4SMartin KaFai Lau return ERR_PTR(-EBUSY); 882b16d9aa4SMartin KaFai Lau } 883b16d9aa4SMartin KaFai Lau 884b16d9aa4SMartin KaFai Lau if (!refold) 885b16d9aa4SMartin KaFai Lau return ERR_PTR(-ENOENT); 886b16d9aa4SMartin KaFai Lau 887b16d9aa4SMartin KaFai Lau return prog; 888b16d9aa4SMartin KaFai Lau } 889b16d9aa4SMartin KaFai Lau 890113214beSDaniel Borkmann static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) 89109756af4SAlexei Starovoitov { 89209756af4SAlexei Starovoitov struct fd f = fdget(ufd); 89309756af4SAlexei Starovoitov struct bpf_prog *prog; 89409756af4SAlexei Starovoitov 895113214beSDaniel Borkmann prog = ____bpf_prog_get(f); 89609756af4SAlexei Starovoitov if (IS_ERR(prog)) 89709756af4SAlexei Starovoitov return prog; 898113214beSDaniel Borkmann if (type && prog->type != *type) { 899113214beSDaniel Borkmann prog = ERR_PTR(-EINVAL); 900113214beSDaniel Borkmann goto out; 901113214beSDaniel Borkmann } 90209756af4SAlexei Starovoitov 90392117d84SAlexei Starovoitov prog = bpf_prog_inc(prog); 904113214beSDaniel Borkmann out: 90509756af4SAlexei Starovoitov fdput(f); 90609756af4SAlexei Starovoitov return prog; 90709756af4SAlexei Starovoitov } 908113214beSDaniel Borkmann 909113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd) 910113214beSDaniel Borkmann { 911113214beSDaniel Borkmann return __bpf_prog_get(ufd, NULL); 912113214beSDaniel Borkmann } 913113214beSDaniel Borkmann 914113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) 915113214beSDaniel Borkmann { 916a67edbf4SDaniel Borkmann struct bpf_prog *prog = __bpf_prog_get(ufd, &type); 917a67edbf4SDaniel Borkmann 918a67edbf4SDaniel Borkmann if (!IS_ERR(prog)) 919a67edbf4SDaniel Borkmann trace_bpf_prog_get_type(prog); 920a67edbf4SDaniel Borkmann return prog; 921113214beSDaniel Borkmann } 922113214beSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get_type); 92309756af4SAlexei Starovoitov 92409756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 925e07b98d9SDavid S. Miller #define BPF_PROG_LOAD_LAST_FIELD prog_flags 92609756af4SAlexei Starovoitov 92709756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr) 92809756af4SAlexei Starovoitov { 92909756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 93009756af4SAlexei Starovoitov struct bpf_prog *prog; 93109756af4SAlexei Starovoitov int err; 93209756af4SAlexei Starovoitov char license[128]; 93309756af4SAlexei Starovoitov bool is_gpl; 93409756af4SAlexei Starovoitov 93509756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 93609756af4SAlexei Starovoitov return -EINVAL; 93709756af4SAlexei Starovoitov 938e07b98d9SDavid S. Miller if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) 939e07b98d9SDavid S. Miller return -EINVAL; 940e07b98d9SDavid S. Miller 94109756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 942535e7b4bSMickaël Salaün if (strncpy_from_user(license, u64_to_user_ptr(attr->license), 94309756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 94409756af4SAlexei Starovoitov return -EFAULT; 94509756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 94609756af4SAlexei Starovoitov 94709756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 94809756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 94909756af4SAlexei Starovoitov 950ef0915caSDaniel Borkmann if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) 951ef0915caSDaniel Borkmann return -E2BIG; 95209756af4SAlexei Starovoitov 9532541517cSAlexei Starovoitov if (type == BPF_PROG_TYPE_KPROBE && 9542541517cSAlexei Starovoitov attr->kern_version != LINUX_VERSION_CODE) 9552541517cSAlexei Starovoitov return -EINVAL; 9562541517cSAlexei Starovoitov 95780b7d819SChenbo Feng if (type != BPF_PROG_TYPE_SOCKET_FILTER && 95880b7d819SChenbo Feng type != BPF_PROG_TYPE_CGROUP_SKB && 95980b7d819SChenbo Feng !capable(CAP_SYS_ADMIN)) 9601be7f75dSAlexei Starovoitov return -EPERM; 9611be7f75dSAlexei Starovoitov 96209756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 96309756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 96409756af4SAlexei Starovoitov if (!prog) 96509756af4SAlexei Starovoitov return -ENOMEM; 96609756af4SAlexei Starovoitov 967aaac3ba9SAlexei Starovoitov err = bpf_prog_charge_memlock(prog); 968aaac3ba9SAlexei Starovoitov if (err) 969aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 970aaac3ba9SAlexei Starovoitov 97109756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 97209756af4SAlexei Starovoitov 97309756af4SAlexei Starovoitov err = -EFAULT; 974535e7b4bSMickaël Salaün if (copy_from_user(prog->insns, u64_to_user_ptr(attr->insns), 975aafe6ae9SDaniel Borkmann bpf_prog_insn_size(prog)) != 0) 97609756af4SAlexei Starovoitov goto free_prog; 97709756af4SAlexei Starovoitov 97809756af4SAlexei Starovoitov prog->orig_prog = NULL; 979a91263d5SDaniel Borkmann prog->jited = 0; 98009756af4SAlexei Starovoitov 98109756af4SAlexei Starovoitov atomic_set(&prog->aux->refcnt, 1); 982a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 98309756af4SAlexei Starovoitov 98409756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 98509756af4SAlexei Starovoitov err = find_prog_type(type, prog); 98609756af4SAlexei Starovoitov if (err < 0) 98709756af4SAlexei Starovoitov goto free_prog; 98809756af4SAlexei Starovoitov 98909756af4SAlexei Starovoitov /* run eBPF verifier */ 9909bac3d6dSAlexei Starovoitov err = bpf_check(&prog, attr); 99109756af4SAlexei Starovoitov if (err < 0) 99209756af4SAlexei Starovoitov goto free_used_maps; 99309756af4SAlexei Starovoitov 99409756af4SAlexei Starovoitov /* eBPF program is ready to be JITed */ 995d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 99604fd61abSAlexei Starovoitov if (err < 0) 99704fd61abSAlexei Starovoitov goto free_used_maps; 99809756af4SAlexei Starovoitov 999dc4bb0e2SMartin KaFai Lau err = bpf_prog_alloc_id(prog); 1000dc4bb0e2SMartin KaFai Lau if (err) 1001dc4bb0e2SMartin KaFai Lau goto free_used_maps; 1002dc4bb0e2SMartin KaFai Lau 1003aa79781bSDaniel Borkmann err = bpf_prog_new_fd(prog); 1004b16d9aa4SMartin KaFai Lau if (err < 0) { 1005b16d9aa4SMartin KaFai Lau /* failed to allocate fd. 1006b16d9aa4SMartin KaFai Lau * bpf_prog_put() is needed because the above 1007b16d9aa4SMartin KaFai Lau * bpf_prog_alloc_id() has published the prog 1008b16d9aa4SMartin KaFai Lau * to the userspace and the userspace may 1009b16d9aa4SMartin KaFai Lau * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. 1010b16d9aa4SMartin KaFai Lau */ 1011b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1012b16d9aa4SMartin KaFai Lau return err; 1013b16d9aa4SMartin KaFai Lau } 101409756af4SAlexei Starovoitov 101574451e66SDaniel Borkmann bpf_prog_kallsyms_add(prog); 1016a67edbf4SDaniel Borkmann trace_bpf_prog_load(prog, err); 101709756af4SAlexei Starovoitov return err; 101809756af4SAlexei Starovoitov 101909756af4SAlexei Starovoitov free_used_maps: 102009756af4SAlexei Starovoitov free_used_maps(prog->aux); 102109756af4SAlexei Starovoitov free_prog: 1022aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 1023aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 102409756af4SAlexei Starovoitov bpf_prog_free(prog); 102509756af4SAlexei Starovoitov return err; 102609756af4SAlexei Starovoitov } 102709756af4SAlexei Starovoitov 1028b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd 1029b2197755SDaniel Borkmann 1030b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 1031b2197755SDaniel Borkmann { 1032b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ)) 1033b2197755SDaniel Borkmann return -EINVAL; 1034b2197755SDaniel Borkmann 1035535e7b4bSMickaël Salaün return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); 1036b2197755SDaniel Borkmann } 1037b2197755SDaniel Borkmann 1038b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 1039b2197755SDaniel Borkmann { 1040b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0) 1041b2197755SDaniel Borkmann return -EINVAL; 1042b2197755SDaniel Borkmann 1043535e7b4bSMickaël Salaün return bpf_obj_get_user(u64_to_user_ptr(attr->pathname)); 1044b2197755SDaniel Borkmann } 1045b2197755SDaniel Borkmann 1046f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1047f4324551SDaniel Mack 10487f677633SAlexei Starovoitov #define BPF_PROG_ATTACH_LAST_FIELD attach_flags 1049f4324551SDaniel Mack 1050f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr) 1051f4324551SDaniel Mack { 10527f677633SAlexei Starovoitov enum bpf_prog_type ptype; 1053f4324551SDaniel Mack struct bpf_prog *prog; 1054f4324551SDaniel Mack struct cgroup *cgrp; 10557f677633SAlexei Starovoitov int ret; 1056f4324551SDaniel Mack 1057f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1058f4324551SDaniel Mack return -EPERM; 1059f4324551SDaniel Mack 1060f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_ATTACH)) 1061f4324551SDaniel Mack return -EINVAL; 1062f4324551SDaniel Mack 10637f677633SAlexei Starovoitov if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE) 10647f677633SAlexei Starovoitov return -EINVAL; 10657f677633SAlexei Starovoitov 1066f4324551SDaniel Mack switch (attr->attach_type) { 1067f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1068f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 1069b2cd1257SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SKB; 1070b2cd1257SDavid Ahern break; 107161023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 107261023658SDavid Ahern ptype = BPF_PROG_TYPE_CGROUP_SOCK; 107361023658SDavid Ahern break; 107440304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 107540304b2aSLawrence Brakmo ptype = BPF_PROG_TYPE_SOCK_OPS; 107640304b2aSLawrence Brakmo break; 1077b2cd1257SDavid Ahern default: 1078b2cd1257SDavid Ahern return -EINVAL; 1079b2cd1257SDavid Ahern } 1080b2cd1257SDavid Ahern 1081b2cd1257SDavid Ahern prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); 1082f4324551SDaniel Mack if (IS_ERR(prog)) 1083f4324551SDaniel Mack return PTR_ERR(prog); 1084f4324551SDaniel Mack 1085f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1086f4324551SDaniel Mack if (IS_ERR(cgrp)) { 1087f4324551SDaniel Mack bpf_prog_put(prog); 1088f4324551SDaniel Mack return PTR_ERR(cgrp); 1089f4324551SDaniel Mack } 1090f4324551SDaniel Mack 10917f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, prog, attr->attach_type, 10927f677633SAlexei Starovoitov attr->attach_flags & BPF_F_ALLOW_OVERRIDE); 10937f677633SAlexei Starovoitov if (ret) 10947f677633SAlexei Starovoitov bpf_prog_put(prog); 1095f4324551SDaniel Mack cgroup_put(cgrp); 1096f4324551SDaniel Mack 10977f677633SAlexei Starovoitov return ret; 1098f4324551SDaniel Mack } 1099f4324551SDaniel Mack 1100f4324551SDaniel Mack #define BPF_PROG_DETACH_LAST_FIELD attach_type 1101f4324551SDaniel Mack 1102f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr) 1103f4324551SDaniel Mack { 1104f4324551SDaniel Mack struct cgroup *cgrp; 11057f677633SAlexei Starovoitov int ret; 1106f4324551SDaniel Mack 1107f4324551SDaniel Mack if (!capable(CAP_NET_ADMIN)) 1108f4324551SDaniel Mack return -EPERM; 1109f4324551SDaniel Mack 1110f4324551SDaniel Mack if (CHECK_ATTR(BPF_PROG_DETACH)) 1111f4324551SDaniel Mack return -EINVAL; 1112f4324551SDaniel Mack 1113f4324551SDaniel Mack switch (attr->attach_type) { 1114f4324551SDaniel Mack case BPF_CGROUP_INET_INGRESS: 1115f4324551SDaniel Mack case BPF_CGROUP_INET_EGRESS: 111661023658SDavid Ahern case BPF_CGROUP_INET_SOCK_CREATE: 111740304b2aSLawrence Brakmo case BPF_CGROUP_SOCK_OPS: 1118f4324551SDaniel Mack cgrp = cgroup_get_from_fd(attr->target_fd); 1119f4324551SDaniel Mack if (IS_ERR(cgrp)) 1120f4324551SDaniel Mack return PTR_ERR(cgrp); 1121f4324551SDaniel Mack 11227f677633SAlexei Starovoitov ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false); 1123f4324551SDaniel Mack cgroup_put(cgrp); 1124f4324551SDaniel Mack break; 1125f4324551SDaniel Mack 1126f4324551SDaniel Mack default: 1127f4324551SDaniel Mack return -EINVAL; 1128f4324551SDaniel Mack } 1129f4324551SDaniel Mack 11307f677633SAlexei Starovoitov return ret; 1131f4324551SDaniel Mack } 113240304b2aSLawrence Brakmo 1133f4324551SDaniel Mack #endif /* CONFIG_CGROUP_BPF */ 1134f4324551SDaniel Mack 11351cf1cae9SAlexei Starovoitov #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration 11361cf1cae9SAlexei Starovoitov 11371cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr, 11381cf1cae9SAlexei Starovoitov union bpf_attr __user *uattr) 11391cf1cae9SAlexei Starovoitov { 11401cf1cae9SAlexei Starovoitov struct bpf_prog *prog; 11411cf1cae9SAlexei Starovoitov int ret = -ENOTSUPP; 11421cf1cae9SAlexei Starovoitov 11431cf1cae9SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_TEST_RUN)) 11441cf1cae9SAlexei Starovoitov return -EINVAL; 11451cf1cae9SAlexei Starovoitov 11461cf1cae9SAlexei Starovoitov prog = bpf_prog_get(attr->test.prog_fd); 11471cf1cae9SAlexei Starovoitov if (IS_ERR(prog)) 11481cf1cae9SAlexei Starovoitov return PTR_ERR(prog); 11491cf1cae9SAlexei Starovoitov 11501cf1cae9SAlexei Starovoitov if (prog->aux->ops->test_run) 11511cf1cae9SAlexei Starovoitov ret = prog->aux->ops->test_run(prog, attr, uattr); 11521cf1cae9SAlexei Starovoitov 11531cf1cae9SAlexei Starovoitov bpf_prog_put(prog); 11541cf1cae9SAlexei Starovoitov return ret; 11551cf1cae9SAlexei Starovoitov } 11561cf1cae9SAlexei Starovoitov 115734ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id 115834ad5580SMartin KaFai Lau 115934ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr, 116034ad5580SMartin KaFai Lau union bpf_attr __user *uattr, 116134ad5580SMartin KaFai Lau struct idr *idr, 116234ad5580SMartin KaFai Lau spinlock_t *lock) 116334ad5580SMartin KaFai Lau { 116434ad5580SMartin KaFai Lau u32 next_id = attr->start_id; 116534ad5580SMartin KaFai Lau int err = 0; 116634ad5580SMartin KaFai Lau 116734ad5580SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) 116834ad5580SMartin KaFai Lau return -EINVAL; 116934ad5580SMartin KaFai Lau 117034ad5580SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 117134ad5580SMartin KaFai Lau return -EPERM; 117234ad5580SMartin KaFai Lau 117334ad5580SMartin KaFai Lau next_id++; 117434ad5580SMartin KaFai Lau spin_lock_bh(lock); 117534ad5580SMartin KaFai Lau if (!idr_get_next(idr, &next_id)) 117634ad5580SMartin KaFai Lau err = -ENOENT; 117734ad5580SMartin KaFai Lau spin_unlock_bh(lock); 117834ad5580SMartin KaFai Lau 117934ad5580SMartin KaFai Lau if (!err) 118034ad5580SMartin KaFai Lau err = put_user(next_id, &uattr->next_id); 118134ad5580SMartin KaFai Lau 118234ad5580SMartin KaFai Lau return err; 118334ad5580SMartin KaFai Lau } 118434ad5580SMartin KaFai Lau 1185b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id 1186b16d9aa4SMartin KaFai Lau 1187b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr) 1188b16d9aa4SMartin KaFai Lau { 1189b16d9aa4SMartin KaFai Lau struct bpf_prog *prog; 1190b16d9aa4SMartin KaFai Lau u32 id = attr->prog_id; 1191b16d9aa4SMartin KaFai Lau int fd; 1192b16d9aa4SMartin KaFai Lau 1193b16d9aa4SMartin KaFai Lau if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID)) 1194b16d9aa4SMartin KaFai Lau return -EINVAL; 1195b16d9aa4SMartin KaFai Lau 1196b16d9aa4SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1197b16d9aa4SMartin KaFai Lau return -EPERM; 1198b16d9aa4SMartin KaFai Lau 1199b16d9aa4SMartin KaFai Lau spin_lock_bh(&prog_idr_lock); 1200b16d9aa4SMartin KaFai Lau prog = idr_find(&prog_idr, id); 1201b16d9aa4SMartin KaFai Lau if (prog) 1202b16d9aa4SMartin KaFai Lau prog = bpf_prog_inc_not_zero(prog); 1203b16d9aa4SMartin KaFai Lau else 1204b16d9aa4SMartin KaFai Lau prog = ERR_PTR(-ENOENT); 1205b16d9aa4SMartin KaFai Lau spin_unlock_bh(&prog_idr_lock); 1206b16d9aa4SMartin KaFai Lau 1207b16d9aa4SMartin KaFai Lau if (IS_ERR(prog)) 1208b16d9aa4SMartin KaFai Lau return PTR_ERR(prog); 1209b16d9aa4SMartin KaFai Lau 1210b16d9aa4SMartin KaFai Lau fd = bpf_prog_new_fd(prog); 1211b16d9aa4SMartin KaFai Lau if (fd < 0) 1212b16d9aa4SMartin KaFai Lau bpf_prog_put(prog); 1213b16d9aa4SMartin KaFai Lau 1214b16d9aa4SMartin KaFai Lau return fd; 1215b16d9aa4SMartin KaFai Lau } 1216b16d9aa4SMartin KaFai Lau 1217bd5f5f4eSMartin KaFai Lau #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD map_id 1218bd5f5f4eSMartin KaFai Lau 1219bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr) 1220bd5f5f4eSMartin KaFai Lau { 1221bd5f5f4eSMartin KaFai Lau struct bpf_map *map; 1222bd5f5f4eSMartin KaFai Lau u32 id = attr->map_id; 1223bd5f5f4eSMartin KaFai Lau int fd; 1224bd5f5f4eSMartin KaFai Lau 1225bd5f5f4eSMartin KaFai Lau if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID)) 1226bd5f5f4eSMartin KaFai Lau return -EINVAL; 1227bd5f5f4eSMartin KaFai Lau 1228bd5f5f4eSMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) 1229bd5f5f4eSMartin KaFai Lau return -EPERM; 1230bd5f5f4eSMartin KaFai Lau 1231bd5f5f4eSMartin KaFai Lau spin_lock_bh(&map_idr_lock); 1232bd5f5f4eSMartin KaFai Lau map = idr_find(&map_idr, id); 1233bd5f5f4eSMartin KaFai Lau if (map) 1234bd5f5f4eSMartin KaFai Lau map = bpf_map_inc_not_zero(map, true); 1235bd5f5f4eSMartin KaFai Lau else 1236bd5f5f4eSMartin KaFai Lau map = ERR_PTR(-ENOENT); 1237bd5f5f4eSMartin KaFai Lau spin_unlock_bh(&map_idr_lock); 1238bd5f5f4eSMartin KaFai Lau 1239bd5f5f4eSMartin KaFai Lau if (IS_ERR(map)) 1240bd5f5f4eSMartin KaFai Lau return PTR_ERR(map); 1241bd5f5f4eSMartin KaFai Lau 1242bd5f5f4eSMartin KaFai Lau fd = bpf_map_new_fd(map); 1243bd5f5f4eSMartin KaFai Lau if (fd < 0) 1244bd5f5f4eSMartin KaFai Lau bpf_map_put(map); 1245bd5f5f4eSMartin KaFai Lau 1246bd5f5f4eSMartin KaFai Lau return fd; 1247bd5f5f4eSMartin KaFai Lau } 1248bd5f5f4eSMartin KaFai Lau 12491e270976SMartin KaFai Lau static int check_uarg_tail_zero(void __user *uaddr, 12501e270976SMartin KaFai Lau size_t expected_size, 12511e270976SMartin KaFai Lau size_t actual_size) 12521e270976SMartin KaFai Lau { 12531e270976SMartin KaFai Lau unsigned char __user *addr; 12541e270976SMartin KaFai Lau unsigned char __user *end; 12551e270976SMartin KaFai Lau unsigned char val; 12561e270976SMartin KaFai Lau int err; 12571e270976SMartin KaFai Lau 12581e270976SMartin KaFai Lau if (actual_size <= expected_size) 12591e270976SMartin KaFai Lau return 0; 12601e270976SMartin KaFai Lau 12611e270976SMartin KaFai Lau addr = uaddr + expected_size; 12621e270976SMartin KaFai Lau end = uaddr + actual_size; 12631e270976SMartin KaFai Lau 12641e270976SMartin KaFai Lau for (; addr < end; addr++) { 12651e270976SMartin KaFai Lau err = get_user(val, addr); 12661e270976SMartin KaFai Lau if (err) 12671e270976SMartin KaFai Lau return err; 12681e270976SMartin KaFai Lau if (val) 12691e270976SMartin KaFai Lau return -E2BIG; 12701e270976SMartin KaFai Lau } 12711e270976SMartin KaFai Lau 12721e270976SMartin KaFai Lau return 0; 12731e270976SMartin KaFai Lau } 12741e270976SMartin KaFai Lau 12751e270976SMartin KaFai Lau static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, 12761e270976SMartin KaFai Lau const union bpf_attr *attr, 12771e270976SMartin KaFai Lau union bpf_attr __user *uattr) 12781e270976SMartin KaFai Lau { 12791e270976SMartin KaFai Lau struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info); 12801e270976SMartin KaFai Lau struct bpf_prog_info info = {}; 12811e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 12821e270976SMartin KaFai Lau char __user *uinsns; 12831e270976SMartin KaFai Lau u32 ulen; 12841e270976SMartin KaFai Lau int err; 12851e270976SMartin KaFai Lau 12861e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 12871e270976SMartin KaFai Lau if (err) 12881e270976SMartin KaFai Lau return err; 12891e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 12901e270976SMartin KaFai Lau 12911e270976SMartin KaFai Lau if (copy_from_user(&info, uinfo, info_len)) 129289b09689SDaniel Borkmann return -EFAULT; 12931e270976SMartin KaFai Lau 12941e270976SMartin KaFai Lau info.type = prog->type; 12951e270976SMartin KaFai Lau info.id = prog->aux->id; 12961e270976SMartin KaFai Lau 12971e270976SMartin KaFai Lau memcpy(info.tag, prog->tag, sizeof(prog->tag)); 12981e270976SMartin KaFai Lau 12991e270976SMartin KaFai Lau if (!capable(CAP_SYS_ADMIN)) { 13001e270976SMartin KaFai Lau info.jited_prog_len = 0; 13011e270976SMartin KaFai Lau info.xlated_prog_len = 0; 13021e270976SMartin KaFai Lau goto done; 13031e270976SMartin KaFai Lau } 13041e270976SMartin KaFai Lau 13051e270976SMartin KaFai Lau ulen = info.jited_prog_len; 13061e270976SMartin KaFai Lau info.jited_prog_len = prog->jited_len; 13071e270976SMartin KaFai Lau if (info.jited_prog_len && ulen) { 13081e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.jited_prog_insns); 13091e270976SMartin KaFai Lau ulen = min_t(u32, info.jited_prog_len, ulen); 13101e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->bpf_func, ulen)) 13111e270976SMartin KaFai Lau return -EFAULT; 13121e270976SMartin KaFai Lau } 13131e270976SMartin KaFai Lau 13141e270976SMartin KaFai Lau ulen = info.xlated_prog_len; 1315*9975a54bSDaniel Borkmann info.xlated_prog_len = bpf_prog_insn_size(prog); 13161e270976SMartin KaFai Lau if (info.xlated_prog_len && ulen) { 13171e270976SMartin KaFai Lau uinsns = u64_to_user_ptr(info.xlated_prog_insns); 13181e270976SMartin KaFai Lau ulen = min_t(u32, info.xlated_prog_len, ulen); 13191e270976SMartin KaFai Lau if (copy_to_user(uinsns, prog->insnsi, ulen)) 13201e270976SMartin KaFai Lau return -EFAULT; 13211e270976SMartin KaFai Lau } 13221e270976SMartin KaFai Lau 13231e270976SMartin KaFai Lau done: 13241e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 13251e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 13261e270976SMartin KaFai Lau return -EFAULT; 13271e270976SMartin KaFai Lau 13281e270976SMartin KaFai Lau return 0; 13291e270976SMartin KaFai Lau } 13301e270976SMartin KaFai Lau 13311e270976SMartin KaFai Lau static int bpf_map_get_info_by_fd(struct bpf_map *map, 13321e270976SMartin KaFai Lau const union bpf_attr *attr, 13331e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13341e270976SMartin KaFai Lau { 13351e270976SMartin KaFai Lau struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info); 13361e270976SMartin KaFai Lau struct bpf_map_info info = {}; 13371e270976SMartin KaFai Lau u32 info_len = attr->info.info_len; 13381e270976SMartin KaFai Lau int err; 13391e270976SMartin KaFai Lau 13401e270976SMartin KaFai Lau err = check_uarg_tail_zero(uinfo, sizeof(info), info_len); 13411e270976SMartin KaFai Lau if (err) 13421e270976SMartin KaFai Lau return err; 13431e270976SMartin KaFai Lau info_len = min_t(u32, sizeof(info), info_len); 13441e270976SMartin KaFai Lau 13451e270976SMartin KaFai Lau info.type = map->map_type; 13461e270976SMartin KaFai Lau info.id = map->id; 13471e270976SMartin KaFai Lau info.key_size = map->key_size; 13481e270976SMartin KaFai Lau info.value_size = map->value_size; 13491e270976SMartin KaFai Lau info.max_entries = map->max_entries; 13501e270976SMartin KaFai Lau info.map_flags = map->map_flags; 13511e270976SMartin KaFai Lau 13521e270976SMartin KaFai Lau if (copy_to_user(uinfo, &info, info_len) || 13531e270976SMartin KaFai Lau put_user(info_len, &uattr->info.info_len)) 13541e270976SMartin KaFai Lau return -EFAULT; 13551e270976SMartin KaFai Lau 13561e270976SMartin KaFai Lau return 0; 13571e270976SMartin KaFai Lau } 13581e270976SMartin KaFai Lau 13591e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info 13601e270976SMartin KaFai Lau 13611e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, 13621e270976SMartin KaFai Lau union bpf_attr __user *uattr) 13631e270976SMartin KaFai Lau { 13641e270976SMartin KaFai Lau int ufd = attr->info.bpf_fd; 13651e270976SMartin KaFai Lau struct fd f; 13661e270976SMartin KaFai Lau int err; 13671e270976SMartin KaFai Lau 13681e270976SMartin KaFai Lau if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD)) 13691e270976SMartin KaFai Lau return -EINVAL; 13701e270976SMartin KaFai Lau 13711e270976SMartin KaFai Lau f = fdget(ufd); 13721e270976SMartin KaFai Lau if (!f.file) 13731e270976SMartin KaFai Lau return -EBADFD; 13741e270976SMartin KaFai Lau 13751e270976SMartin KaFai Lau if (f.file->f_op == &bpf_prog_fops) 13761e270976SMartin KaFai Lau err = bpf_prog_get_info_by_fd(f.file->private_data, attr, 13771e270976SMartin KaFai Lau uattr); 13781e270976SMartin KaFai Lau else if (f.file->f_op == &bpf_map_fops) 13791e270976SMartin KaFai Lau err = bpf_map_get_info_by_fd(f.file->private_data, attr, 13801e270976SMartin KaFai Lau uattr); 13811e270976SMartin KaFai Lau else 13821e270976SMartin KaFai Lau err = -EINVAL; 13831e270976SMartin KaFai Lau 13841e270976SMartin KaFai Lau fdput(f); 13851e270976SMartin KaFai Lau return err; 13861e270976SMartin KaFai Lau } 13871e270976SMartin KaFai Lau 138899c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 138999c55f7dSAlexei Starovoitov { 139099c55f7dSAlexei Starovoitov union bpf_attr attr = {}; 139199c55f7dSAlexei Starovoitov int err; 139299c55f7dSAlexei Starovoitov 13931be7f75dSAlexei Starovoitov if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) 139499c55f7dSAlexei Starovoitov return -EPERM; 139599c55f7dSAlexei Starovoitov 139699c55f7dSAlexei Starovoitov if (!access_ok(VERIFY_READ, uattr, 1)) 139799c55f7dSAlexei Starovoitov return -EFAULT; 139899c55f7dSAlexei Starovoitov 139999c55f7dSAlexei Starovoitov if (size > PAGE_SIZE) /* silly large */ 140099c55f7dSAlexei Starovoitov return -E2BIG; 140199c55f7dSAlexei Starovoitov 140299c55f7dSAlexei Starovoitov /* If we're handed a bigger struct than we know of, 140399c55f7dSAlexei Starovoitov * ensure all the unknown bits are 0 - i.e. new 140499c55f7dSAlexei Starovoitov * user-space does not rely on any kernel feature 140599c55f7dSAlexei Starovoitov * extensions we dont know about yet. 140699c55f7dSAlexei Starovoitov */ 14071e270976SMartin KaFai Lau err = check_uarg_tail_zero(uattr, sizeof(attr), size); 140899c55f7dSAlexei Starovoitov if (err) 140999c55f7dSAlexei Starovoitov return err; 14101e270976SMartin KaFai Lau size = min_t(u32, size, sizeof(attr)); 141199c55f7dSAlexei Starovoitov 141299c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 141399c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 141499c55f7dSAlexei Starovoitov return -EFAULT; 141599c55f7dSAlexei Starovoitov 141699c55f7dSAlexei Starovoitov switch (cmd) { 141799c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 141899c55f7dSAlexei Starovoitov err = map_create(&attr); 141999c55f7dSAlexei Starovoitov break; 1420db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 1421db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 1422db20fd2bSAlexei Starovoitov break; 1423db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 1424db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 1425db20fd2bSAlexei Starovoitov break; 1426db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 1427db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 1428db20fd2bSAlexei Starovoitov break; 1429db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 1430db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 1431db20fd2bSAlexei Starovoitov break; 143209756af4SAlexei Starovoitov case BPF_PROG_LOAD: 143309756af4SAlexei Starovoitov err = bpf_prog_load(&attr); 143409756af4SAlexei Starovoitov break; 1435b2197755SDaniel Borkmann case BPF_OBJ_PIN: 1436b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 1437b2197755SDaniel Borkmann break; 1438b2197755SDaniel Borkmann case BPF_OBJ_GET: 1439b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 1440b2197755SDaniel Borkmann break; 1441f4324551SDaniel Mack #ifdef CONFIG_CGROUP_BPF 1442f4324551SDaniel Mack case BPF_PROG_ATTACH: 1443f4324551SDaniel Mack err = bpf_prog_attach(&attr); 1444f4324551SDaniel Mack break; 1445f4324551SDaniel Mack case BPF_PROG_DETACH: 1446f4324551SDaniel Mack err = bpf_prog_detach(&attr); 1447f4324551SDaniel Mack break; 1448f4324551SDaniel Mack #endif 14491cf1cae9SAlexei Starovoitov case BPF_PROG_TEST_RUN: 14501cf1cae9SAlexei Starovoitov err = bpf_prog_test_run(&attr, uattr); 14511cf1cae9SAlexei Starovoitov break; 145234ad5580SMartin KaFai Lau case BPF_PROG_GET_NEXT_ID: 145334ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 145434ad5580SMartin KaFai Lau &prog_idr, &prog_idr_lock); 145534ad5580SMartin KaFai Lau break; 145634ad5580SMartin KaFai Lau case BPF_MAP_GET_NEXT_ID: 145734ad5580SMartin KaFai Lau err = bpf_obj_get_next_id(&attr, uattr, 145834ad5580SMartin KaFai Lau &map_idr, &map_idr_lock); 145934ad5580SMartin KaFai Lau break; 1460b16d9aa4SMartin KaFai Lau case BPF_PROG_GET_FD_BY_ID: 1461b16d9aa4SMartin KaFai Lau err = bpf_prog_get_fd_by_id(&attr); 1462b16d9aa4SMartin KaFai Lau break; 1463bd5f5f4eSMartin KaFai Lau case BPF_MAP_GET_FD_BY_ID: 1464bd5f5f4eSMartin KaFai Lau err = bpf_map_get_fd_by_id(&attr); 1465bd5f5f4eSMartin KaFai Lau break; 14661e270976SMartin KaFai Lau case BPF_OBJ_GET_INFO_BY_FD: 14671e270976SMartin KaFai Lau err = bpf_obj_get_info_by_fd(&attr, uattr); 14681e270976SMartin KaFai Lau break; 146999c55f7dSAlexei Starovoitov default: 147099c55f7dSAlexei Starovoitov err = -EINVAL; 147199c55f7dSAlexei Starovoitov break; 147299c55f7dSAlexei Starovoitov } 147399c55f7dSAlexei Starovoitov 147499c55f7dSAlexei Starovoitov return err; 147599c55f7dSAlexei Starovoitov } 1476