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> 1399c55f7dSAlexei Starovoitov #include <linux/syscalls.h> 1499c55f7dSAlexei Starovoitov #include <linux/slab.h> 1599c55f7dSAlexei Starovoitov #include <linux/anon_inodes.h> 16db20fd2bSAlexei Starovoitov #include <linux/file.h> 1709756af4SAlexei Starovoitov #include <linux/license.h> 1809756af4SAlexei Starovoitov #include <linux/filter.h> 192541517cSAlexei Starovoitov #include <linux/version.h> 2099c55f7dSAlexei Starovoitov 21b121d1e7SAlexei Starovoitov DEFINE_PER_CPU(int, bpf_prog_active); 22b121d1e7SAlexei Starovoitov 231be7f75dSAlexei Starovoitov int sysctl_unprivileged_bpf_disabled __read_mostly; 241be7f75dSAlexei Starovoitov 2599c55f7dSAlexei Starovoitov static LIST_HEAD(bpf_map_types); 2699c55f7dSAlexei Starovoitov 2799c55f7dSAlexei Starovoitov static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) 2899c55f7dSAlexei Starovoitov { 2999c55f7dSAlexei Starovoitov struct bpf_map_type_list *tl; 3099c55f7dSAlexei Starovoitov struct bpf_map *map; 3199c55f7dSAlexei Starovoitov 3299c55f7dSAlexei Starovoitov list_for_each_entry(tl, &bpf_map_types, list_node) { 3399c55f7dSAlexei Starovoitov if (tl->type == attr->map_type) { 3499c55f7dSAlexei Starovoitov map = tl->ops->map_alloc(attr); 3599c55f7dSAlexei Starovoitov if (IS_ERR(map)) 3699c55f7dSAlexei Starovoitov return map; 3799c55f7dSAlexei Starovoitov map->ops = tl->ops; 3899c55f7dSAlexei Starovoitov map->map_type = attr->map_type; 3999c55f7dSAlexei Starovoitov return map; 4099c55f7dSAlexei Starovoitov } 4199c55f7dSAlexei Starovoitov } 4299c55f7dSAlexei Starovoitov return ERR_PTR(-EINVAL); 4399c55f7dSAlexei Starovoitov } 4499c55f7dSAlexei Starovoitov 4599c55f7dSAlexei Starovoitov /* boot time registration of different map implementations */ 4699c55f7dSAlexei Starovoitov void bpf_register_map_type(struct bpf_map_type_list *tl) 4799c55f7dSAlexei Starovoitov { 4899c55f7dSAlexei Starovoitov list_add(&tl->list_node, &bpf_map_types); 4999c55f7dSAlexei Starovoitov } 5099c55f7dSAlexei Starovoitov 516c905981SAlexei Starovoitov int bpf_map_precharge_memlock(u32 pages) 526c905981SAlexei Starovoitov { 536c905981SAlexei Starovoitov struct user_struct *user = get_current_user(); 546c905981SAlexei Starovoitov unsigned long memlock_limit, cur; 556c905981SAlexei Starovoitov 566c905981SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 576c905981SAlexei Starovoitov cur = atomic_long_read(&user->locked_vm); 586c905981SAlexei Starovoitov free_uid(user); 596c905981SAlexei Starovoitov if (cur + pages > memlock_limit) 606c905981SAlexei Starovoitov return -EPERM; 616c905981SAlexei Starovoitov return 0; 626c905981SAlexei Starovoitov } 636c905981SAlexei Starovoitov 64aaac3ba9SAlexei Starovoitov static int bpf_map_charge_memlock(struct bpf_map *map) 65aaac3ba9SAlexei Starovoitov { 66aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 67aaac3ba9SAlexei Starovoitov unsigned long memlock_limit; 68aaac3ba9SAlexei Starovoitov 69aaac3ba9SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 70aaac3ba9SAlexei Starovoitov 71aaac3ba9SAlexei Starovoitov atomic_long_add(map->pages, &user->locked_vm); 72aaac3ba9SAlexei Starovoitov 73aaac3ba9SAlexei Starovoitov if (atomic_long_read(&user->locked_vm) > memlock_limit) { 74aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 75aaac3ba9SAlexei Starovoitov free_uid(user); 76aaac3ba9SAlexei Starovoitov return -EPERM; 77aaac3ba9SAlexei Starovoitov } 78aaac3ba9SAlexei Starovoitov map->user = user; 79aaac3ba9SAlexei Starovoitov return 0; 80aaac3ba9SAlexei Starovoitov } 81aaac3ba9SAlexei Starovoitov 82aaac3ba9SAlexei Starovoitov static void bpf_map_uncharge_memlock(struct bpf_map *map) 83aaac3ba9SAlexei Starovoitov { 84aaac3ba9SAlexei Starovoitov struct user_struct *user = map->user; 85aaac3ba9SAlexei Starovoitov 86aaac3ba9SAlexei Starovoitov atomic_long_sub(map->pages, &user->locked_vm); 87aaac3ba9SAlexei Starovoitov free_uid(user); 88aaac3ba9SAlexei Starovoitov } 89aaac3ba9SAlexei Starovoitov 9099c55f7dSAlexei Starovoitov /* called from workqueue */ 9199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work) 9299c55f7dSAlexei Starovoitov { 9399c55f7dSAlexei Starovoitov struct bpf_map *map = container_of(work, struct bpf_map, work); 9499c55f7dSAlexei Starovoitov 95aaac3ba9SAlexei Starovoitov bpf_map_uncharge_memlock(map); 9699c55f7dSAlexei Starovoitov /* implementation dependent freeing */ 9799c55f7dSAlexei Starovoitov map->ops->map_free(map); 9899c55f7dSAlexei Starovoitov } 9999c55f7dSAlexei Starovoitov 100c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map) 101c9da161cSDaniel Borkmann { 102c9da161cSDaniel Borkmann if (atomic_dec_and_test(&map->usercnt)) { 103c9da161cSDaniel Borkmann if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) 104c9da161cSDaniel Borkmann bpf_fd_array_map_clear(map); 105c9da161cSDaniel Borkmann } 106c9da161cSDaniel Borkmann } 107c9da161cSDaniel Borkmann 10899c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue 10999c55f7dSAlexei Starovoitov * (unrelying map implementation ops->map_free() might sleep) 11099c55f7dSAlexei Starovoitov */ 11199c55f7dSAlexei Starovoitov void bpf_map_put(struct bpf_map *map) 11299c55f7dSAlexei Starovoitov { 11399c55f7dSAlexei Starovoitov if (atomic_dec_and_test(&map->refcnt)) { 11499c55f7dSAlexei Starovoitov INIT_WORK(&map->work, bpf_map_free_deferred); 11599c55f7dSAlexei Starovoitov schedule_work(&map->work); 11699c55f7dSAlexei Starovoitov } 11799c55f7dSAlexei Starovoitov } 11899c55f7dSAlexei Starovoitov 119c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map) 120c9da161cSDaniel Borkmann { 121c9da161cSDaniel Borkmann bpf_map_put_uref(map); 122c9da161cSDaniel Borkmann bpf_map_put(map); 123c9da161cSDaniel Borkmann } 124c9da161cSDaniel Borkmann 12599c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp) 12699c55f7dSAlexei Starovoitov { 12761d1b6a4SDaniel Borkmann struct bpf_map *map = filp->private_data; 12861d1b6a4SDaniel Borkmann 12961d1b6a4SDaniel Borkmann if (map->ops->map_release) 13061d1b6a4SDaniel Borkmann map->ops->map_release(map, filp); 13161d1b6a4SDaniel Borkmann 13261d1b6a4SDaniel Borkmann bpf_map_put_with_uref(map); 13399c55f7dSAlexei Starovoitov return 0; 13499c55f7dSAlexei Starovoitov } 13599c55f7dSAlexei Starovoitov 136f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 137f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp) 138f99bf205SDaniel Borkmann { 139f99bf205SDaniel Borkmann const struct bpf_map *map = filp->private_data; 140f99bf205SDaniel Borkmann 141f99bf205SDaniel Borkmann seq_printf(m, 142f99bf205SDaniel Borkmann "map_type:\t%u\n" 143f99bf205SDaniel Borkmann "key_size:\t%u\n" 144f99bf205SDaniel Borkmann "value_size:\t%u\n" 145322cea2fSDaniel Borkmann "max_entries:\t%u\n" 146322cea2fSDaniel Borkmann "map_flags:\t%#x\n", 147f99bf205SDaniel Borkmann map->map_type, 148f99bf205SDaniel Borkmann map->key_size, 149f99bf205SDaniel Borkmann map->value_size, 150322cea2fSDaniel Borkmann map->max_entries, 151322cea2fSDaniel Borkmann map->map_flags); 152f99bf205SDaniel Borkmann } 153f99bf205SDaniel Borkmann #endif 154f99bf205SDaniel Borkmann 15599c55f7dSAlexei Starovoitov static const struct file_operations bpf_map_fops = { 156f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS 157f99bf205SDaniel Borkmann .show_fdinfo = bpf_map_show_fdinfo, 158f99bf205SDaniel Borkmann #endif 15999c55f7dSAlexei Starovoitov .release = bpf_map_release, 16099c55f7dSAlexei Starovoitov }; 16199c55f7dSAlexei Starovoitov 162b2197755SDaniel Borkmann int bpf_map_new_fd(struct bpf_map *map) 163aa79781bSDaniel Borkmann { 164aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-map", &bpf_map_fops, map, 165aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 166aa79781bSDaniel Borkmann } 167aa79781bSDaniel Borkmann 16899c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */ 16999c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \ 17099c55f7dSAlexei Starovoitov memchr_inv((void *) &attr->CMD##_LAST_FIELD + \ 17199c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD), 0, \ 17299c55f7dSAlexei Starovoitov sizeof(*attr) - \ 17399c55f7dSAlexei Starovoitov offsetof(union bpf_attr, CMD##_LAST_FIELD) - \ 17499c55f7dSAlexei Starovoitov sizeof(attr->CMD##_LAST_FIELD)) != NULL 17599c55f7dSAlexei Starovoitov 1766c905981SAlexei Starovoitov #define BPF_MAP_CREATE_LAST_FIELD map_flags 17799c55f7dSAlexei Starovoitov /* called via syscall */ 17899c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr) 17999c55f7dSAlexei Starovoitov { 18099c55f7dSAlexei Starovoitov struct bpf_map *map; 18199c55f7dSAlexei Starovoitov int err; 18299c55f7dSAlexei Starovoitov 18399c55f7dSAlexei Starovoitov err = CHECK_ATTR(BPF_MAP_CREATE); 18499c55f7dSAlexei Starovoitov if (err) 18599c55f7dSAlexei Starovoitov return -EINVAL; 18699c55f7dSAlexei Starovoitov 18799c55f7dSAlexei Starovoitov /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ 18899c55f7dSAlexei Starovoitov map = find_and_alloc_map(attr); 18999c55f7dSAlexei Starovoitov if (IS_ERR(map)) 19099c55f7dSAlexei Starovoitov return PTR_ERR(map); 19199c55f7dSAlexei Starovoitov 19299c55f7dSAlexei Starovoitov atomic_set(&map->refcnt, 1); 193c9da161cSDaniel Borkmann atomic_set(&map->usercnt, 1); 19499c55f7dSAlexei Starovoitov 195aaac3ba9SAlexei Starovoitov err = bpf_map_charge_memlock(map); 196aaac3ba9SAlexei Starovoitov if (err) 197aaac3ba9SAlexei Starovoitov goto free_map; 198aaac3ba9SAlexei Starovoitov 199aa79781bSDaniel Borkmann err = bpf_map_new_fd(map); 20099c55f7dSAlexei Starovoitov if (err < 0) 20199c55f7dSAlexei Starovoitov /* failed to allocate fd */ 20299c55f7dSAlexei Starovoitov goto free_map; 20399c55f7dSAlexei Starovoitov 20499c55f7dSAlexei Starovoitov return err; 20599c55f7dSAlexei Starovoitov 20699c55f7dSAlexei Starovoitov free_map: 20799c55f7dSAlexei Starovoitov map->ops->map_free(map); 20899c55f7dSAlexei Starovoitov return err; 20999c55f7dSAlexei Starovoitov } 21099c55f7dSAlexei Starovoitov 211db20fd2bSAlexei Starovoitov /* if error is returned, fd is released. 212db20fd2bSAlexei Starovoitov * On success caller should complete fd access with matching fdput() 213db20fd2bSAlexei Starovoitov */ 214c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f) 215db20fd2bSAlexei Starovoitov { 216db20fd2bSAlexei Starovoitov if (!f.file) 217db20fd2bSAlexei Starovoitov return ERR_PTR(-EBADF); 218db20fd2bSAlexei Starovoitov if (f.file->f_op != &bpf_map_fops) { 219db20fd2bSAlexei Starovoitov fdput(f); 220db20fd2bSAlexei Starovoitov return ERR_PTR(-EINVAL); 221db20fd2bSAlexei Starovoitov } 222db20fd2bSAlexei Starovoitov 223c2101297SDaniel Borkmann return f.file->private_data; 224c2101297SDaniel Borkmann } 225c2101297SDaniel Borkmann 22692117d84SAlexei Starovoitov /* prog's and map's refcnt limit */ 22792117d84SAlexei Starovoitov #define BPF_MAX_REFCNT 32768 22892117d84SAlexei Starovoitov 22992117d84SAlexei Starovoitov struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) 230c9da161cSDaniel Borkmann { 23192117d84SAlexei Starovoitov if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { 23292117d84SAlexei Starovoitov atomic_dec(&map->refcnt); 23392117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 23492117d84SAlexei Starovoitov } 235c9da161cSDaniel Borkmann if (uref) 236c9da161cSDaniel Borkmann atomic_inc(&map->usercnt); 23792117d84SAlexei Starovoitov return map; 238c9da161cSDaniel Borkmann } 239c9da161cSDaniel Borkmann 240c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd) 241c2101297SDaniel Borkmann { 242c2101297SDaniel Borkmann struct fd f = fdget(ufd); 243c2101297SDaniel Borkmann struct bpf_map *map; 244c2101297SDaniel Borkmann 245c2101297SDaniel Borkmann map = __bpf_map_get(f); 246c2101297SDaniel Borkmann if (IS_ERR(map)) 247c2101297SDaniel Borkmann return map; 248c2101297SDaniel Borkmann 24992117d84SAlexei Starovoitov map = bpf_map_inc(map, true); 250c2101297SDaniel Borkmann fdput(f); 251db20fd2bSAlexei Starovoitov 252db20fd2bSAlexei Starovoitov return map; 253db20fd2bSAlexei Starovoitov } 254db20fd2bSAlexei Starovoitov 255db20fd2bSAlexei Starovoitov /* helper to convert user pointers passed inside __aligned_u64 fields */ 256db20fd2bSAlexei Starovoitov static void __user *u64_to_ptr(__u64 val) 257db20fd2bSAlexei Starovoitov { 258db20fd2bSAlexei Starovoitov return (void __user *) (unsigned long) val; 259db20fd2bSAlexei Starovoitov } 260db20fd2bSAlexei Starovoitov 261b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value) 262b8cdc051SAlexei Starovoitov { 263b8cdc051SAlexei Starovoitov return -ENOTSUPP; 264b8cdc051SAlexei Starovoitov } 265b8cdc051SAlexei Starovoitov 266db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 267db20fd2bSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 268db20fd2bSAlexei Starovoitov 269db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr) 270db20fd2bSAlexei Starovoitov { 271db20fd2bSAlexei Starovoitov void __user *ukey = u64_to_ptr(attr->key); 272db20fd2bSAlexei Starovoitov void __user *uvalue = u64_to_ptr(attr->value); 273db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 274db20fd2bSAlexei Starovoitov struct bpf_map *map; 2758ebe667cSAlexei Starovoitov void *key, *value, *ptr; 27615a07b33SAlexei Starovoitov u32 value_size; 277592867bfSDaniel Borkmann struct fd f; 278db20fd2bSAlexei Starovoitov int err; 279db20fd2bSAlexei Starovoitov 280db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 281db20fd2bSAlexei Starovoitov return -EINVAL; 282db20fd2bSAlexei Starovoitov 283592867bfSDaniel Borkmann f = fdget(ufd); 284c2101297SDaniel Borkmann map = __bpf_map_get(f); 285db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 286db20fd2bSAlexei Starovoitov return PTR_ERR(map); 287db20fd2bSAlexei Starovoitov 288db20fd2bSAlexei Starovoitov err = -ENOMEM; 289db20fd2bSAlexei Starovoitov key = kmalloc(map->key_size, GFP_USER); 290db20fd2bSAlexei Starovoitov if (!key) 291db20fd2bSAlexei Starovoitov goto err_put; 292db20fd2bSAlexei Starovoitov 293db20fd2bSAlexei Starovoitov err = -EFAULT; 294db20fd2bSAlexei Starovoitov if (copy_from_user(key, ukey, map->key_size) != 0) 295db20fd2bSAlexei Starovoitov goto free_key; 296db20fd2bSAlexei Starovoitov 29715a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 29815a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 29915a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 30015a07b33SAlexei Starovoitov else 30115a07b33SAlexei Starovoitov value_size = map->value_size; 30215a07b33SAlexei Starovoitov 3038ebe667cSAlexei Starovoitov err = -ENOMEM; 30415a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 305db20fd2bSAlexei Starovoitov if (!value) 3068ebe667cSAlexei Starovoitov goto free_key; 3078ebe667cSAlexei Starovoitov 30815a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) { 30915a07b33SAlexei Starovoitov err = bpf_percpu_hash_copy(map, key, value); 31015a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 31115a07b33SAlexei Starovoitov err = bpf_percpu_array_copy(map, key, value); 312557c0c6eSAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) { 313557c0c6eSAlexei Starovoitov err = bpf_stackmap_copy(map, key, value); 31415a07b33SAlexei Starovoitov } else { 3158ebe667cSAlexei Starovoitov rcu_read_lock(); 3168ebe667cSAlexei Starovoitov ptr = map->ops->map_lookup_elem(map, key); 3178ebe667cSAlexei Starovoitov if (ptr) 31815a07b33SAlexei Starovoitov memcpy(value, ptr, value_size); 3198ebe667cSAlexei Starovoitov rcu_read_unlock(); 32015a07b33SAlexei Starovoitov err = ptr ? 0 : -ENOENT; 32115a07b33SAlexei Starovoitov } 3228ebe667cSAlexei Starovoitov 32315a07b33SAlexei Starovoitov if (err) 3248ebe667cSAlexei Starovoitov goto free_value; 325db20fd2bSAlexei Starovoitov 326db20fd2bSAlexei Starovoitov err = -EFAULT; 32715a07b33SAlexei Starovoitov if (copy_to_user(uvalue, value, value_size) != 0) 3288ebe667cSAlexei Starovoitov goto free_value; 329db20fd2bSAlexei Starovoitov 330db20fd2bSAlexei Starovoitov err = 0; 331db20fd2bSAlexei Starovoitov 3328ebe667cSAlexei Starovoitov free_value: 3338ebe667cSAlexei Starovoitov kfree(value); 334db20fd2bSAlexei Starovoitov free_key: 335db20fd2bSAlexei Starovoitov kfree(key); 336db20fd2bSAlexei Starovoitov err_put: 337db20fd2bSAlexei Starovoitov fdput(f); 338db20fd2bSAlexei Starovoitov return err; 339db20fd2bSAlexei Starovoitov } 340db20fd2bSAlexei Starovoitov 3413274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags 342db20fd2bSAlexei Starovoitov 343db20fd2bSAlexei Starovoitov static int map_update_elem(union bpf_attr *attr) 344db20fd2bSAlexei Starovoitov { 345db20fd2bSAlexei Starovoitov void __user *ukey = u64_to_ptr(attr->key); 346db20fd2bSAlexei Starovoitov void __user *uvalue = u64_to_ptr(attr->value); 347db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 348db20fd2bSAlexei Starovoitov struct bpf_map *map; 349db20fd2bSAlexei Starovoitov void *key, *value; 35015a07b33SAlexei Starovoitov u32 value_size; 351592867bfSDaniel Borkmann struct fd f; 352db20fd2bSAlexei Starovoitov int err; 353db20fd2bSAlexei Starovoitov 354db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) 355db20fd2bSAlexei Starovoitov return -EINVAL; 356db20fd2bSAlexei Starovoitov 357592867bfSDaniel Borkmann f = fdget(ufd); 358c2101297SDaniel Borkmann map = __bpf_map_get(f); 359db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 360db20fd2bSAlexei Starovoitov return PTR_ERR(map); 361db20fd2bSAlexei Starovoitov 362db20fd2bSAlexei Starovoitov err = -ENOMEM; 363db20fd2bSAlexei Starovoitov key = kmalloc(map->key_size, GFP_USER); 364db20fd2bSAlexei Starovoitov if (!key) 365db20fd2bSAlexei Starovoitov goto err_put; 366db20fd2bSAlexei Starovoitov 367db20fd2bSAlexei Starovoitov err = -EFAULT; 368db20fd2bSAlexei Starovoitov if (copy_from_user(key, ukey, map->key_size) != 0) 369db20fd2bSAlexei Starovoitov goto free_key; 370db20fd2bSAlexei Starovoitov 37115a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || 37215a07b33SAlexei Starovoitov map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) 37315a07b33SAlexei Starovoitov value_size = round_up(map->value_size, 8) * num_possible_cpus(); 37415a07b33SAlexei Starovoitov else 37515a07b33SAlexei Starovoitov value_size = map->value_size; 37615a07b33SAlexei Starovoitov 377db20fd2bSAlexei Starovoitov err = -ENOMEM; 37815a07b33SAlexei Starovoitov value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); 379db20fd2bSAlexei Starovoitov if (!value) 380db20fd2bSAlexei Starovoitov goto free_key; 381db20fd2bSAlexei Starovoitov 382db20fd2bSAlexei Starovoitov err = -EFAULT; 38315a07b33SAlexei Starovoitov if (copy_from_user(value, uvalue, value_size) != 0) 384db20fd2bSAlexei Starovoitov goto free_value; 385db20fd2bSAlexei Starovoitov 386b121d1e7SAlexei Starovoitov /* must increment bpf_prog_active to avoid kprobe+bpf triggering from 387b121d1e7SAlexei Starovoitov * inside bpf map update or delete otherwise deadlocks are possible 388b121d1e7SAlexei Starovoitov */ 389b121d1e7SAlexei Starovoitov preempt_disable(); 390b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 39115a07b33SAlexei Starovoitov if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) { 39215a07b33SAlexei Starovoitov err = bpf_percpu_hash_update(map, key, value, attr->flags); 39315a07b33SAlexei Starovoitov } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { 39415a07b33SAlexei Starovoitov err = bpf_percpu_array_update(map, key, value, attr->flags); 395*d056a788SDaniel Borkmann } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || 396*d056a788SDaniel Borkmann map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { 397*d056a788SDaniel Borkmann rcu_read_lock(); 398*d056a788SDaniel Borkmann err = bpf_fd_array_map_update_elem(map, f.file, key, value, 399*d056a788SDaniel Borkmann attr->flags); 400*d056a788SDaniel Borkmann rcu_read_unlock(); 40115a07b33SAlexei Starovoitov } else { 402db20fd2bSAlexei Starovoitov rcu_read_lock(); 4033274f520SAlexei Starovoitov err = map->ops->map_update_elem(map, key, value, attr->flags); 404db20fd2bSAlexei Starovoitov rcu_read_unlock(); 40515a07b33SAlexei Starovoitov } 406b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 407b121d1e7SAlexei Starovoitov preempt_enable(); 408db20fd2bSAlexei Starovoitov 409db20fd2bSAlexei Starovoitov free_value: 410db20fd2bSAlexei Starovoitov kfree(value); 411db20fd2bSAlexei Starovoitov free_key: 412db20fd2bSAlexei Starovoitov kfree(key); 413db20fd2bSAlexei Starovoitov err_put: 414db20fd2bSAlexei Starovoitov fdput(f); 415db20fd2bSAlexei Starovoitov return err; 416db20fd2bSAlexei Starovoitov } 417db20fd2bSAlexei Starovoitov 418db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key 419db20fd2bSAlexei Starovoitov 420db20fd2bSAlexei Starovoitov static int map_delete_elem(union bpf_attr *attr) 421db20fd2bSAlexei Starovoitov { 422db20fd2bSAlexei Starovoitov void __user *ukey = u64_to_ptr(attr->key); 423db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 424db20fd2bSAlexei Starovoitov struct bpf_map *map; 425592867bfSDaniel Borkmann struct fd f; 426db20fd2bSAlexei Starovoitov void *key; 427db20fd2bSAlexei Starovoitov int err; 428db20fd2bSAlexei Starovoitov 429db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) 430db20fd2bSAlexei Starovoitov return -EINVAL; 431db20fd2bSAlexei Starovoitov 432592867bfSDaniel Borkmann f = fdget(ufd); 433c2101297SDaniel Borkmann map = __bpf_map_get(f); 434db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 435db20fd2bSAlexei Starovoitov return PTR_ERR(map); 436db20fd2bSAlexei Starovoitov 437db20fd2bSAlexei Starovoitov err = -ENOMEM; 438db20fd2bSAlexei Starovoitov key = kmalloc(map->key_size, GFP_USER); 439db20fd2bSAlexei Starovoitov if (!key) 440db20fd2bSAlexei Starovoitov goto err_put; 441db20fd2bSAlexei Starovoitov 442db20fd2bSAlexei Starovoitov err = -EFAULT; 443db20fd2bSAlexei Starovoitov if (copy_from_user(key, ukey, map->key_size) != 0) 444db20fd2bSAlexei Starovoitov goto free_key; 445db20fd2bSAlexei Starovoitov 446b121d1e7SAlexei Starovoitov preempt_disable(); 447b121d1e7SAlexei Starovoitov __this_cpu_inc(bpf_prog_active); 448db20fd2bSAlexei Starovoitov rcu_read_lock(); 449db20fd2bSAlexei Starovoitov err = map->ops->map_delete_elem(map, key); 450db20fd2bSAlexei Starovoitov rcu_read_unlock(); 451b121d1e7SAlexei Starovoitov __this_cpu_dec(bpf_prog_active); 452b121d1e7SAlexei Starovoitov preempt_enable(); 453db20fd2bSAlexei Starovoitov 454db20fd2bSAlexei Starovoitov free_key: 455db20fd2bSAlexei Starovoitov kfree(key); 456db20fd2bSAlexei Starovoitov err_put: 457db20fd2bSAlexei Starovoitov fdput(f); 458db20fd2bSAlexei Starovoitov return err; 459db20fd2bSAlexei Starovoitov } 460db20fd2bSAlexei Starovoitov 461db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 462db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key 463db20fd2bSAlexei Starovoitov 464db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr) 465db20fd2bSAlexei Starovoitov { 466db20fd2bSAlexei Starovoitov void __user *ukey = u64_to_ptr(attr->key); 467db20fd2bSAlexei Starovoitov void __user *unext_key = u64_to_ptr(attr->next_key); 468db20fd2bSAlexei Starovoitov int ufd = attr->map_fd; 469db20fd2bSAlexei Starovoitov struct bpf_map *map; 470db20fd2bSAlexei Starovoitov void *key, *next_key; 471592867bfSDaniel Borkmann struct fd f; 472db20fd2bSAlexei Starovoitov int err; 473db20fd2bSAlexei Starovoitov 474db20fd2bSAlexei Starovoitov if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) 475db20fd2bSAlexei Starovoitov return -EINVAL; 476db20fd2bSAlexei Starovoitov 477592867bfSDaniel Borkmann f = fdget(ufd); 478c2101297SDaniel Borkmann map = __bpf_map_get(f); 479db20fd2bSAlexei Starovoitov if (IS_ERR(map)) 480db20fd2bSAlexei Starovoitov return PTR_ERR(map); 481db20fd2bSAlexei Starovoitov 482db20fd2bSAlexei Starovoitov err = -ENOMEM; 483db20fd2bSAlexei Starovoitov key = kmalloc(map->key_size, GFP_USER); 484db20fd2bSAlexei Starovoitov if (!key) 485db20fd2bSAlexei Starovoitov goto err_put; 486db20fd2bSAlexei Starovoitov 487db20fd2bSAlexei Starovoitov err = -EFAULT; 488db20fd2bSAlexei Starovoitov if (copy_from_user(key, ukey, map->key_size) != 0) 489db20fd2bSAlexei Starovoitov goto free_key; 490db20fd2bSAlexei Starovoitov 491db20fd2bSAlexei Starovoitov err = -ENOMEM; 492db20fd2bSAlexei Starovoitov next_key = kmalloc(map->key_size, GFP_USER); 493db20fd2bSAlexei Starovoitov if (!next_key) 494db20fd2bSAlexei Starovoitov goto free_key; 495db20fd2bSAlexei Starovoitov 496db20fd2bSAlexei Starovoitov rcu_read_lock(); 497db20fd2bSAlexei Starovoitov err = map->ops->map_get_next_key(map, key, next_key); 498db20fd2bSAlexei Starovoitov rcu_read_unlock(); 499db20fd2bSAlexei Starovoitov if (err) 500db20fd2bSAlexei Starovoitov goto free_next_key; 501db20fd2bSAlexei Starovoitov 502db20fd2bSAlexei Starovoitov err = -EFAULT; 503db20fd2bSAlexei Starovoitov if (copy_to_user(unext_key, next_key, map->key_size) != 0) 504db20fd2bSAlexei Starovoitov goto free_next_key; 505db20fd2bSAlexei Starovoitov 506db20fd2bSAlexei Starovoitov err = 0; 507db20fd2bSAlexei Starovoitov 508db20fd2bSAlexei Starovoitov free_next_key: 509db20fd2bSAlexei Starovoitov kfree(next_key); 510db20fd2bSAlexei Starovoitov free_key: 511db20fd2bSAlexei Starovoitov kfree(key); 512db20fd2bSAlexei Starovoitov err_put: 513db20fd2bSAlexei Starovoitov fdput(f); 514db20fd2bSAlexei Starovoitov return err; 515db20fd2bSAlexei Starovoitov } 516db20fd2bSAlexei Starovoitov 51709756af4SAlexei Starovoitov static LIST_HEAD(bpf_prog_types); 51809756af4SAlexei Starovoitov 51909756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog) 52009756af4SAlexei Starovoitov { 52109756af4SAlexei Starovoitov struct bpf_prog_type_list *tl; 52209756af4SAlexei Starovoitov 52309756af4SAlexei Starovoitov list_for_each_entry(tl, &bpf_prog_types, list_node) { 52409756af4SAlexei Starovoitov if (tl->type == type) { 52509756af4SAlexei Starovoitov prog->aux->ops = tl->ops; 52624701eceSDaniel Borkmann prog->type = type; 52709756af4SAlexei Starovoitov return 0; 52809756af4SAlexei Starovoitov } 52909756af4SAlexei Starovoitov } 53024701eceSDaniel Borkmann 53109756af4SAlexei Starovoitov return -EINVAL; 53209756af4SAlexei Starovoitov } 53309756af4SAlexei Starovoitov 53409756af4SAlexei Starovoitov void bpf_register_prog_type(struct bpf_prog_type_list *tl) 53509756af4SAlexei Starovoitov { 53609756af4SAlexei Starovoitov list_add(&tl->list_node, &bpf_prog_types); 53709756af4SAlexei Starovoitov } 53809756af4SAlexei Starovoitov 5390a542a86SAlexei Starovoitov /* fixup insn->imm field of bpf_call instructions: 5400a542a86SAlexei Starovoitov * if (insn->imm == BPF_FUNC_map_lookup_elem) 5410a542a86SAlexei Starovoitov * insn->imm = bpf_map_lookup_elem - __bpf_call_base; 5420a542a86SAlexei Starovoitov * else if (insn->imm == BPF_FUNC_map_update_elem) 5430a542a86SAlexei Starovoitov * insn->imm = bpf_map_update_elem - __bpf_call_base; 5440a542a86SAlexei Starovoitov * else ... 5450a542a86SAlexei Starovoitov * 5460a542a86SAlexei Starovoitov * this function is called after eBPF program passed verification 5470a542a86SAlexei Starovoitov */ 5480a542a86SAlexei Starovoitov static void fixup_bpf_calls(struct bpf_prog *prog) 5490a542a86SAlexei Starovoitov { 5500a542a86SAlexei Starovoitov const struct bpf_func_proto *fn; 5510a542a86SAlexei Starovoitov int i; 5520a542a86SAlexei Starovoitov 5530a542a86SAlexei Starovoitov for (i = 0; i < prog->len; i++) { 5540a542a86SAlexei Starovoitov struct bpf_insn *insn = &prog->insnsi[i]; 5550a542a86SAlexei Starovoitov 5560a542a86SAlexei Starovoitov if (insn->code == (BPF_JMP | BPF_CALL)) { 5570a542a86SAlexei Starovoitov /* we reach here when program has bpf_call instructions 5580a542a86SAlexei Starovoitov * and it passed bpf_check(), means that 5590a542a86SAlexei Starovoitov * ops->get_func_proto must have been supplied, check it 5600a542a86SAlexei Starovoitov */ 5610a542a86SAlexei Starovoitov BUG_ON(!prog->aux->ops->get_func_proto); 5620a542a86SAlexei Starovoitov 563c46646d0SDaniel Borkmann if (insn->imm == BPF_FUNC_get_route_realm) 564c46646d0SDaniel Borkmann prog->dst_needed = 1; 5653ad00405SDaniel Borkmann if (insn->imm == BPF_FUNC_get_prandom_u32) 5663ad00405SDaniel Borkmann bpf_user_rnd_init_once(); 56704fd61abSAlexei Starovoitov if (insn->imm == BPF_FUNC_tail_call) { 56804fd61abSAlexei Starovoitov /* mark bpf_tail_call as different opcode 56904fd61abSAlexei Starovoitov * to avoid conditional branch in 57004fd61abSAlexei Starovoitov * interpeter for every normal call 57104fd61abSAlexei Starovoitov * and to prevent accidental JITing by 57204fd61abSAlexei Starovoitov * JIT compiler that doesn't support 57304fd61abSAlexei Starovoitov * bpf_tail_call yet 57404fd61abSAlexei Starovoitov */ 57504fd61abSAlexei Starovoitov insn->imm = 0; 57604fd61abSAlexei Starovoitov insn->code |= BPF_X; 57704fd61abSAlexei Starovoitov continue; 57804fd61abSAlexei Starovoitov } 57904fd61abSAlexei Starovoitov 5800a542a86SAlexei Starovoitov fn = prog->aux->ops->get_func_proto(insn->imm); 5810a542a86SAlexei Starovoitov /* all functions that have prototype and verifier allowed 5820a542a86SAlexei Starovoitov * programs to call them, must be real in-kernel functions 5830a542a86SAlexei Starovoitov */ 5840a542a86SAlexei Starovoitov BUG_ON(!fn->func); 5850a542a86SAlexei Starovoitov insn->imm = fn->func - __bpf_call_base; 5860a542a86SAlexei Starovoitov } 5870a542a86SAlexei Starovoitov } 5880a542a86SAlexei Starovoitov } 5890a542a86SAlexei Starovoitov 59009756af4SAlexei Starovoitov /* drop refcnt on maps used by eBPF program and free auxilary data */ 59109756af4SAlexei Starovoitov static void free_used_maps(struct bpf_prog_aux *aux) 59209756af4SAlexei Starovoitov { 59309756af4SAlexei Starovoitov int i; 59409756af4SAlexei Starovoitov 59509756af4SAlexei Starovoitov for (i = 0; i < aux->used_map_cnt; i++) 59609756af4SAlexei Starovoitov bpf_map_put(aux->used_maps[i]); 59709756af4SAlexei Starovoitov 59809756af4SAlexei Starovoitov kfree(aux->used_maps); 59909756af4SAlexei Starovoitov } 60009756af4SAlexei Starovoitov 601aaac3ba9SAlexei Starovoitov static int bpf_prog_charge_memlock(struct bpf_prog *prog) 602aaac3ba9SAlexei Starovoitov { 603aaac3ba9SAlexei Starovoitov struct user_struct *user = get_current_user(); 604aaac3ba9SAlexei Starovoitov unsigned long memlock_limit; 605aaac3ba9SAlexei Starovoitov 606aaac3ba9SAlexei Starovoitov memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; 607aaac3ba9SAlexei Starovoitov 608aaac3ba9SAlexei Starovoitov atomic_long_add(prog->pages, &user->locked_vm); 609aaac3ba9SAlexei Starovoitov if (atomic_long_read(&user->locked_vm) > memlock_limit) { 610aaac3ba9SAlexei Starovoitov atomic_long_sub(prog->pages, &user->locked_vm); 611aaac3ba9SAlexei Starovoitov free_uid(user); 612aaac3ba9SAlexei Starovoitov return -EPERM; 613aaac3ba9SAlexei Starovoitov } 614aaac3ba9SAlexei Starovoitov prog->aux->user = user; 615aaac3ba9SAlexei Starovoitov return 0; 616aaac3ba9SAlexei Starovoitov } 617aaac3ba9SAlexei Starovoitov 618aaac3ba9SAlexei Starovoitov static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) 619aaac3ba9SAlexei Starovoitov { 620aaac3ba9SAlexei Starovoitov struct user_struct *user = prog->aux->user; 621aaac3ba9SAlexei Starovoitov 622aaac3ba9SAlexei Starovoitov atomic_long_sub(prog->pages, &user->locked_vm); 623aaac3ba9SAlexei Starovoitov free_uid(user); 624aaac3ba9SAlexei Starovoitov } 625aaac3ba9SAlexei Starovoitov 626e9d8afa9SDaniel Borkmann static void __prog_put_common(struct rcu_head *rcu) 627abf2e7d6SAlexei Starovoitov { 628abf2e7d6SAlexei Starovoitov struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); 629abf2e7d6SAlexei Starovoitov 630abf2e7d6SAlexei Starovoitov free_used_maps(aux); 631aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(aux->prog); 632abf2e7d6SAlexei Starovoitov bpf_prog_free(aux->prog); 633abf2e7d6SAlexei Starovoitov } 634abf2e7d6SAlexei Starovoitov 635abf2e7d6SAlexei Starovoitov /* version of bpf_prog_put() that is called after a grace period */ 636abf2e7d6SAlexei Starovoitov void bpf_prog_put_rcu(struct bpf_prog *prog) 637abf2e7d6SAlexei Starovoitov { 638e9d8afa9SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) 639e9d8afa9SDaniel Borkmann call_rcu(&prog->aux->rcu, __prog_put_common); 640abf2e7d6SAlexei Starovoitov } 641abf2e7d6SAlexei Starovoitov 64209756af4SAlexei Starovoitov void bpf_prog_put(struct bpf_prog *prog) 64309756af4SAlexei Starovoitov { 644e9d8afa9SDaniel Borkmann if (atomic_dec_and_test(&prog->aux->refcnt)) 645e9d8afa9SDaniel Borkmann __prog_put_common(&prog->aux->rcu); 64609756af4SAlexei Starovoitov } 647e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put); 64809756af4SAlexei Starovoitov 64909756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp) 65009756af4SAlexei Starovoitov { 65109756af4SAlexei Starovoitov struct bpf_prog *prog = filp->private_data; 65209756af4SAlexei Starovoitov 653abf2e7d6SAlexei Starovoitov bpf_prog_put_rcu(prog); 65409756af4SAlexei Starovoitov return 0; 65509756af4SAlexei Starovoitov } 65609756af4SAlexei Starovoitov 65709756af4SAlexei Starovoitov static const struct file_operations bpf_prog_fops = { 65809756af4SAlexei Starovoitov .release = bpf_prog_release, 65909756af4SAlexei Starovoitov }; 66009756af4SAlexei Starovoitov 661b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog) 662aa79781bSDaniel Borkmann { 663aa79781bSDaniel Borkmann return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, 664aa79781bSDaniel Borkmann O_RDWR | O_CLOEXEC); 665aa79781bSDaniel Borkmann } 666aa79781bSDaniel Borkmann 667c2101297SDaniel Borkmann static struct bpf_prog *__bpf_prog_get(struct fd f) 66809756af4SAlexei Starovoitov { 66909756af4SAlexei Starovoitov if (!f.file) 67009756af4SAlexei Starovoitov return ERR_PTR(-EBADF); 67109756af4SAlexei Starovoitov if (f.file->f_op != &bpf_prog_fops) { 67209756af4SAlexei Starovoitov fdput(f); 67309756af4SAlexei Starovoitov return ERR_PTR(-EINVAL); 67409756af4SAlexei Starovoitov } 67509756af4SAlexei Starovoitov 676c2101297SDaniel Borkmann return f.file->private_data; 67709756af4SAlexei Starovoitov } 67809756af4SAlexei Starovoitov 67992117d84SAlexei Starovoitov struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) 68092117d84SAlexei Starovoitov { 68192117d84SAlexei Starovoitov if (atomic_inc_return(&prog->aux->refcnt) > BPF_MAX_REFCNT) { 68292117d84SAlexei Starovoitov atomic_dec(&prog->aux->refcnt); 68392117d84SAlexei Starovoitov return ERR_PTR(-EBUSY); 68492117d84SAlexei Starovoitov } 68592117d84SAlexei Starovoitov return prog; 68692117d84SAlexei Starovoitov } 68792117d84SAlexei Starovoitov 68809756af4SAlexei Starovoitov /* called by sockets/tracing/seccomp before attaching program to an event 68909756af4SAlexei Starovoitov * pairs with bpf_prog_put() 69009756af4SAlexei Starovoitov */ 69109756af4SAlexei Starovoitov struct bpf_prog *bpf_prog_get(u32 ufd) 69209756af4SAlexei Starovoitov { 69309756af4SAlexei Starovoitov struct fd f = fdget(ufd); 69409756af4SAlexei Starovoitov struct bpf_prog *prog; 69509756af4SAlexei Starovoitov 696c2101297SDaniel Borkmann prog = __bpf_prog_get(f); 69709756af4SAlexei Starovoitov if (IS_ERR(prog)) 69809756af4SAlexei Starovoitov return prog; 69909756af4SAlexei Starovoitov 70092117d84SAlexei Starovoitov prog = bpf_prog_inc(prog); 70109756af4SAlexei Starovoitov fdput(f); 702c2101297SDaniel Borkmann 70309756af4SAlexei Starovoitov return prog; 70409756af4SAlexei Starovoitov } 705e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_get); 70609756af4SAlexei Starovoitov 70709756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */ 7082541517cSAlexei Starovoitov #define BPF_PROG_LOAD_LAST_FIELD kern_version 70909756af4SAlexei Starovoitov 71009756af4SAlexei Starovoitov static int bpf_prog_load(union bpf_attr *attr) 71109756af4SAlexei Starovoitov { 71209756af4SAlexei Starovoitov enum bpf_prog_type type = attr->prog_type; 71309756af4SAlexei Starovoitov struct bpf_prog *prog; 71409756af4SAlexei Starovoitov int err; 71509756af4SAlexei Starovoitov char license[128]; 71609756af4SAlexei Starovoitov bool is_gpl; 71709756af4SAlexei Starovoitov 71809756af4SAlexei Starovoitov if (CHECK_ATTR(BPF_PROG_LOAD)) 71909756af4SAlexei Starovoitov return -EINVAL; 72009756af4SAlexei Starovoitov 72109756af4SAlexei Starovoitov /* copy eBPF program license from user space */ 72209756af4SAlexei Starovoitov if (strncpy_from_user(license, u64_to_ptr(attr->license), 72309756af4SAlexei Starovoitov sizeof(license) - 1) < 0) 72409756af4SAlexei Starovoitov return -EFAULT; 72509756af4SAlexei Starovoitov license[sizeof(license) - 1] = 0; 72609756af4SAlexei Starovoitov 72709756af4SAlexei Starovoitov /* eBPF programs must be GPL compatible to use GPL-ed functions */ 72809756af4SAlexei Starovoitov is_gpl = license_is_gpl_compatible(license); 72909756af4SAlexei Starovoitov 73009756af4SAlexei Starovoitov if (attr->insn_cnt >= BPF_MAXINSNS) 73109756af4SAlexei Starovoitov return -EINVAL; 73209756af4SAlexei Starovoitov 7332541517cSAlexei Starovoitov if (type == BPF_PROG_TYPE_KPROBE && 7342541517cSAlexei Starovoitov attr->kern_version != LINUX_VERSION_CODE) 7352541517cSAlexei Starovoitov return -EINVAL; 7362541517cSAlexei Starovoitov 7371be7f75dSAlexei Starovoitov if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN)) 7381be7f75dSAlexei Starovoitov return -EPERM; 7391be7f75dSAlexei Starovoitov 74009756af4SAlexei Starovoitov /* plain bpf_prog allocation */ 74109756af4SAlexei Starovoitov prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 74209756af4SAlexei Starovoitov if (!prog) 74309756af4SAlexei Starovoitov return -ENOMEM; 74409756af4SAlexei Starovoitov 745aaac3ba9SAlexei Starovoitov err = bpf_prog_charge_memlock(prog); 746aaac3ba9SAlexei Starovoitov if (err) 747aaac3ba9SAlexei Starovoitov goto free_prog_nouncharge; 748aaac3ba9SAlexei Starovoitov 74909756af4SAlexei Starovoitov prog->len = attr->insn_cnt; 75009756af4SAlexei Starovoitov 75109756af4SAlexei Starovoitov err = -EFAULT; 75209756af4SAlexei Starovoitov if (copy_from_user(prog->insns, u64_to_ptr(attr->insns), 75309756af4SAlexei Starovoitov prog->len * sizeof(struct bpf_insn)) != 0) 75409756af4SAlexei Starovoitov goto free_prog; 75509756af4SAlexei Starovoitov 75609756af4SAlexei Starovoitov prog->orig_prog = NULL; 757a91263d5SDaniel Borkmann prog->jited = 0; 75809756af4SAlexei Starovoitov 75909756af4SAlexei Starovoitov atomic_set(&prog->aux->refcnt, 1); 760a91263d5SDaniel Borkmann prog->gpl_compatible = is_gpl ? 1 : 0; 76109756af4SAlexei Starovoitov 76209756af4SAlexei Starovoitov /* find program type: socket_filter vs tracing_filter */ 76309756af4SAlexei Starovoitov err = find_prog_type(type, prog); 76409756af4SAlexei Starovoitov if (err < 0) 76509756af4SAlexei Starovoitov goto free_prog; 76609756af4SAlexei Starovoitov 76709756af4SAlexei Starovoitov /* run eBPF verifier */ 7689bac3d6dSAlexei Starovoitov err = bpf_check(&prog, attr); 76909756af4SAlexei Starovoitov if (err < 0) 77009756af4SAlexei Starovoitov goto free_used_maps; 77109756af4SAlexei Starovoitov 7720a542a86SAlexei Starovoitov /* fixup BPF_CALL->imm field */ 7730a542a86SAlexei Starovoitov fixup_bpf_calls(prog); 7740a542a86SAlexei Starovoitov 77509756af4SAlexei Starovoitov /* eBPF program is ready to be JITed */ 776d1c55ab5SDaniel Borkmann prog = bpf_prog_select_runtime(prog, &err); 77704fd61abSAlexei Starovoitov if (err < 0) 77804fd61abSAlexei Starovoitov goto free_used_maps; 77909756af4SAlexei Starovoitov 780aa79781bSDaniel Borkmann err = bpf_prog_new_fd(prog); 78109756af4SAlexei Starovoitov if (err < 0) 78209756af4SAlexei Starovoitov /* failed to allocate fd */ 78309756af4SAlexei Starovoitov goto free_used_maps; 78409756af4SAlexei Starovoitov 78509756af4SAlexei Starovoitov return err; 78609756af4SAlexei Starovoitov 78709756af4SAlexei Starovoitov free_used_maps: 78809756af4SAlexei Starovoitov free_used_maps(prog->aux); 78909756af4SAlexei Starovoitov free_prog: 790aaac3ba9SAlexei Starovoitov bpf_prog_uncharge_memlock(prog); 791aaac3ba9SAlexei Starovoitov free_prog_nouncharge: 79209756af4SAlexei Starovoitov bpf_prog_free(prog); 79309756af4SAlexei Starovoitov return err; 79409756af4SAlexei Starovoitov } 79509756af4SAlexei Starovoitov 796b2197755SDaniel Borkmann #define BPF_OBJ_LAST_FIELD bpf_fd 797b2197755SDaniel Borkmann 798b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr) 799b2197755SDaniel Borkmann { 800b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ)) 801b2197755SDaniel Borkmann return -EINVAL; 802b2197755SDaniel Borkmann 803b2197755SDaniel Borkmann return bpf_obj_pin_user(attr->bpf_fd, u64_to_ptr(attr->pathname)); 804b2197755SDaniel Borkmann } 805b2197755SDaniel Borkmann 806b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr) 807b2197755SDaniel Borkmann { 808b2197755SDaniel Borkmann if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0) 809b2197755SDaniel Borkmann return -EINVAL; 810b2197755SDaniel Borkmann 811b2197755SDaniel Borkmann return bpf_obj_get_user(u64_to_ptr(attr->pathname)); 812b2197755SDaniel Borkmann } 813b2197755SDaniel Borkmann 81499c55f7dSAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 81599c55f7dSAlexei Starovoitov { 81699c55f7dSAlexei Starovoitov union bpf_attr attr = {}; 81799c55f7dSAlexei Starovoitov int err; 81899c55f7dSAlexei Starovoitov 8191be7f75dSAlexei Starovoitov if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) 82099c55f7dSAlexei Starovoitov return -EPERM; 82199c55f7dSAlexei Starovoitov 82299c55f7dSAlexei Starovoitov if (!access_ok(VERIFY_READ, uattr, 1)) 82399c55f7dSAlexei Starovoitov return -EFAULT; 82499c55f7dSAlexei Starovoitov 82599c55f7dSAlexei Starovoitov if (size > PAGE_SIZE) /* silly large */ 82699c55f7dSAlexei Starovoitov return -E2BIG; 82799c55f7dSAlexei Starovoitov 82899c55f7dSAlexei Starovoitov /* If we're handed a bigger struct than we know of, 82999c55f7dSAlexei Starovoitov * ensure all the unknown bits are 0 - i.e. new 83099c55f7dSAlexei Starovoitov * user-space does not rely on any kernel feature 83199c55f7dSAlexei Starovoitov * extensions we dont know about yet. 83299c55f7dSAlexei Starovoitov */ 83399c55f7dSAlexei Starovoitov if (size > sizeof(attr)) { 83499c55f7dSAlexei Starovoitov unsigned char __user *addr; 83599c55f7dSAlexei Starovoitov unsigned char __user *end; 83699c55f7dSAlexei Starovoitov unsigned char val; 83799c55f7dSAlexei Starovoitov 83899c55f7dSAlexei Starovoitov addr = (void __user *)uattr + sizeof(attr); 83999c55f7dSAlexei Starovoitov end = (void __user *)uattr + size; 84099c55f7dSAlexei Starovoitov 84199c55f7dSAlexei Starovoitov for (; addr < end; addr++) { 84299c55f7dSAlexei Starovoitov err = get_user(val, addr); 84399c55f7dSAlexei Starovoitov if (err) 84499c55f7dSAlexei Starovoitov return err; 84599c55f7dSAlexei Starovoitov if (val) 84699c55f7dSAlexei Starovoitov return -E2BIG; 84799c55f7dSAlexei Starovoitov } 84899c55f7dSAlexei Starovoitov size = sizeof(attr); 84999c55f7dSAlexei Starovoitov } 85099c55f7dSAlexei Starovoitov 85199c55f7dSAlexei Starovoitov /* copy attributes from user space, may be less than sizeof(bpf_attr) */ 85299c55f7dSAlexei Starovoitov if (copy_from_user(&attr, uattr, size) != 0) 85399c55f7dSAlexei Starovoitov return -EFAULT; 85499c55f7dSAlexei Starovoitov 85599c55f7dSAlexei Starovoitov switch (cmd) { 85699c55f7dSAlexei Starovoitov case BPF_MAP_CREATE: 85799c55f7dSAlexei Starovoitov err = map_create(&attr); 85899c55f7dSAlexei Starovoitov break; 859db20fd2bSAlexei Starovoitov case BPF_MAP_LOOKUP_ELEM: 860db20fd2bSAlexei Starovoitov err = map_lookup_elem(&attr); 861db20fd2bSAlexei Starovoitov break; 862db20fd2bSAlexei Starovoitov case BPF_MAP_UPDATE_ELEM: 863db20fd2bSAlexei Starovoitov err = map_update_elem(&attr); 864db20fd2bSAlexei Starovoitov break; 865db20fd2bSAlexei Starovoitov case BPF_MAP_DELETE_ELEM: 866db20fd2bSAlexei Starovoitov err = map_delete_elem(&attr); 867db20fd2bSAlexei Starovoitov break; 868db20fd2bSAlexei Starovoitov case BPF_MAP_GET_NEXT_KEY: 869db20fd2bSAlexei Starovoitov err = map_get_next_key(&attr); 870db20fd2bSAlexei Starovoitov break; 87109756af4SAlexei Starovoitov case BPF_PROG_LOAD: 87209756af4SAlexei Starovoitov err = bpf_prog_load(&attr); 87309756af4SAlexei Starovoitov break; 874b2197755SDaniel Borkmann case BPF_OBJ_PIN: 875b2197755SDaniel Borkmann err = bpf_obj_pin(&attr); 876b2197755SDaniel Borkmann break; 877b2197755SDaniel Borkmann case BPF_OBJ_GET: 878b2197755SDaniel Borkmann err = bpf_obj_get(&attr); 879b2197755SDaniel Borkmann break; 88099c55f7dSAlexei Starovoitov default: 88199c55f7dSAlexei Starovoitov err = -EINVAL; 88299c55f7dSAlexei Starovoitov break; 88399c55f7dSAlexei Starovoitov } 88499c55f7dSAlexei Starovoitov 88599c55f7dSAlexei Starovoitov return err; 88699c55f7dSAlexei Starovoitov } 887