Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Centralize permissions checks for all BPF map types

This allows to do more centralized decisions later on, and generally
makes it very explicit which maps are privileged and which are not
(e.g., LRU_HASH and LRU_PERCPU_HASH, which are privileged HASH variants,
as opposed to unprivileged HASH and HASH_PERCPU; now this is explicit
and easy to verify).

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/bpf/20230613223533.3689589-4-andrii@kernel.org

authored by

Andrii Nakryiko and committed by
Daniel Borkmann
6c3eba1c 22db4122

+52 -44
-3
kernel/bpf/bloom_filter.c
··· 86 86 int numa_node = bpf_map_attr_numa_node(attr); 87 87 struct bpf_bloom_filter *bloom; 88 88 89 - if (!bpf_capable()) 90 - return ERR_PTR(-EPERM); 91 - 92 89 if (attr->key_size != 0 || attr->value_size == 0 || 93 90 attr->max_entries == 0 || 94 91 attr->map_flags & ~BLOOM_CREATE_FLAG_MASK ||
-3
kernel/bpf/bpf_local_storage.c
··· 723 723 !attr->btf_key_type_id || !attr->btf_value_type_id) 724 724 return -EINVAL; 725 725 726 - if (!bpf_capable()) 727 - return -EPERM; 728 - 729 726 if (attr->value_size > BPF_LOCAL_STORAGE_MAX_VALUE_SIZE) 730 727 return -E2BIG; 731 728
-3
kernel/bpf/bpf_struct_ops.c
··· 655 655 const struct btf_type *t, *vt; 656 656 struct bpf_map *map; 657 657 658 - if (!bpf_capable()) 659 - return ERR_PTR(-EPERM); 660 - 661 658 st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); 662 659 if (!st_ops) 663 660 return ERR_PTR(-ENOTSUPP);
-4
kernel/bpf/cpumap.c
··· 28 28 #include <linux/sched.h> 29 29 #include <linux/workqueue.h> 30 30 #include <linux/kthread.h> 31 - #include <linux/capability.h> 32 31 #include <trace/events/xdp.h> 33 32 #include <linux/btf_ids.h> 34 33 ··· 87 88 { 88 89 u32 value_size = attr->value_size; 89 90 struct bpf_cpu_map *cmap; 90 - 91 - if (!bpf_capable()) 92 - return ERR_PTR(-EPERM); 93 91 94 92 /* check sanity of attributes */ 95 93 if (attr->max_entries == 0 || attr->key_size != 4 ||
-3
kernel/bpf/devmap.c
··· 160 160 struct bpf_dtab *dtab; 161 161 int err; 162 162 163 - if (!capable(CAP_NET_ADMIN)) 164 - return ERR_PTR(-EPERM); 165 - 166 163 dtab = bpf_map_area_alloc(sizeof(*dtab), NUMA_NO_NODE); 167 164 if (!dtab) 168 165 return ERR_PTR(-ENOMEM);
-6
kernel/bpf/hashtab.c
··· 422 422 BUILD_BUG_ON(offsetof(struct htab_elem, fnode.next) != 423 423 offsetof(struct htab_elem, hash_node.pprev)); 424 424 425 - if (lru && !bpf_capable()) 426 - /* LRU implementation is much complicated than other 427 - * maps. Hence, limit to CAP_BPF. 428 - */ 429 - return -EPERM; 430 - 431 425 if (zero_seed && !capable(CAP_SYS_ADMIN)) 432 426 /* Guard against local DoS, and discourage production use. */ 433 427 return -EPERM;
-3
kernel/bpf/lpm_trie.c
··· 544 544 { 545 545 struct lpm_trie *trie; 546 546 547 - if (!bpf_capable()) 548 - return ERR_PTR(-EPERM); 549 - 550 547 /* check sanity of attributes */ 551 548 if (attr->max_entries == 0 || 552 549 !(attr->map_flags & BPF_F_NO_PREALLOC) ||
-4
kernel/bpf/queue_stack_maps.c
··· 7 7 #include <linux/bpf.h> 8 8 #include <linux/list.h> 9 9 #include <linux/slab.h> 10 - #include <linux/capability.h> 11 10 #include <linux/btf_ids.h> 12 11 #include "percpu_freelist.h" 13 12 ··· 45 46 /* Called from syscall */ 46 47 static int queue_stack_map_alloc_check(union bpf_attr *attr) 47 48 { 48 - if (!bpf_capable()) 49 - return -EPERM; 50 - 51 49 /* check sanity of attributes */ 52 50 if (attr->max_entries == 0 || attr->key_size != 0 || 53 51 attr->value_size == 0 ||
-3
kernel/bpf/reuseport_array.c
··· 151 151 int numa_node = bpf_map_attr_numa_node(attr); 152 152 struct reuseport_array *array; 153 153 154 - if (!bpf_capable()) 155 - return ERR_PTR(-EPERM); 156 - 157 154 /* allocate all map elements and zero-initialize them */ 158 155 array = bpf_map_area_alloc(struct_size(array, ptrs, attr->max_entries), numa_node); 159 156 if (!array)
-3
kernel/bpf/stackmap.c
··· 74 74 u64 cost, n_buckets; 75 75 int err; 76 76 77 - if (!bpf_capable()) 78 - return ERR_PTR(-EPERM); 79 - 80 77 if (attr->map_flags & ~STACK_CREATE_FLAG_MASK) 81 78 return ERR_PTR(-EINVAL); 82 79
+47
kernel/bpf/syscall.c
··· 1156 1156 if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) 1157 1157 return -EPERM; 1158 1158 1159 + /* check privileged map type permissions */ 1160 + switch (map_type) { 1161 + case BPF_MAP_TYPE_ARRAY: 1162 + case BPF_MAP_TYPE_PERCPU_ARRAY: 1163 + case BPF_MAP_TYPE_PROG_ARRAY: 1164 + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: 1165 + case BPF_MAP_TYPE_CGROUP_ARRAY: 1166 + case BPF_MAP_TYPE_ARRAY_OF_MAPS: 1167 + case BPF_MAP_TYPE_HASH: 1168 + case BPF_MAP_TYPE_PERCPU_HASH: 1169 + case BPF_MAP_TYPE_HASH_OF_MAPS: 1170 + case BPF_MAP_TYPE_RINGBUF: 1171 + case BPF_MAP_TYPE_USER_RINGBUF: 1172 + case BPF_MAP_TYPE_CGROUP_STORAGE: 1173 + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: 1174 + /* unprivileged */ 1175 + break; 1176 + case BPF_MAP_TYPE_SK_STORAGE: 1177 + case BPF_MAP_TYPE_INODE_STORAGE: 1178 + case BPF_MAP_TYPE_TASK_STORAGE: 1179 + case BPF_MAP_TYPE_CGRP_STORAGE: 1180 + case BPF_MAP_TYPE_BLOOM_FILTER: 1181 + case BPF_MAP_TYPE_LPM_TRIE: 1182 + case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: 1183 + case BPF_MAP_TYPE_STACK_TRACE: 1184 + case BPF_MAP_TYPE_QUEUE: 1185 + case BPF_MAP_TYPE_STACK: 1186 + case BPF_MAP_TYPE_LRU_HASH: 1187 + case BPF_MAP_TYPE_LRU_PERCPU_HASH: 1188 + case BPF_MAP_TYPE_STRUCT_OPS: 1189 + case BPF_MAP_TYPE_CPUMAP: 1190 + if (!bpf_capable()) 1191 + return -EPERM; 1192 + break; 1193 + case BPF_MAP_TYPE_SOCKMAP: 1194 + case BPF_MAP_TYPE_SOCKHASH: 1195 + case BPF_MAP_TYPE_DEVMAP: 1196 + case BPF_MAP_TYPE_DEVMAP_HASH: 1197 + case BPF_MAP_TYPE_XSKMAP: 1198 + if (!capable(CAP_NET_ADMIN)) 1199 + return -EPERM; 1200 + break; 1201 + default: 1202 + WARN(1, "unsupported map type %d", map_type); 1203 + return -EPERM; 1204 + } 1205 + 1159 1206 map = ops->map_alloc(attr); 1160 1207 if (IS_ERR(map)) 1161 1208 return PTR_ERR(map);
-4
net/core/sock_map.c
··· 32 32 { 33 33 struct bpf_stab *stab; 34 34 35 - if (!capable(CAP_NET_ADMIN)) 36 - return ERR_PTR(-EPERM); 37 35 if (attr->max_entries == 0 || 38 36 attr->key_size != 4 || 39 37 (attr->value_size != sizeof(u32) && ··· 1083 1085 struct bpf_shtab *htab; 1084 1086 int i, err; 1085 1087 1086 - if (!capable(CAP_NET_ADMIN)) 1087 - return ERR_PTR(-EPERM); 1088 1088 if (attr->max_entries == 0 || 1089 1089 attr->key_size == 0 || 1090 1090 (attr->value_size != sizeof(u32) &&
-4
net/xdp/xskmap.c
··· 5 5 6 6 #include <linux/bpf.h> 7 7 #include <linux/filter.h> 8 - #include <linux/capability.h> 9 8 #include <net/xdp_sock.h> 10 9 #include <linux/slab.h> 11 10 #include <linux/sched.h> ··· 66 67 struct xsk_map *m; 67 68 int numa_node; 68 69 u64 size; 69 - 70 - if (!capable(CAP_NET_ADMIN)) 71 - return ERR_PTR(-EPERM); 72 70 73 71 if (attr->max_entries == 0 || attr->key_size != 4 || 74 72 attr->value_size != 4 ||
+5 -1
tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c
··· 171 171 prog_insns, prog_insn_cnt, &load_opts), 172 172 -EPERM, "prog_load_fails"); 173 173 174 - for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_BLOOM_FILTER; i++) 174 + /* some map types require particular correct parameters which could be 175 + * sanity-checked before enforcing -EPERM, so only validate that 176 + * the simple ARRAY and HASH maps are failing with -EPERM 177 + */ 178 + for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_ARRAY; i++) 175 179 ASSERT_EQ(bpf_map_create(i, NULL, sizeof(int), sizeof(int), 1, NULL), 176 180 -EPERM, "map_create_fails"); 177 181