History

bpf: Fix toctou on read-only map's constant scalar tracking

Commit a23740ec43ba ("bpf: Track contents of read-only maps as scalars") is checking whether maps are read-only both from BPF program side and user space side, and then, given their content is constant, reading out their data via map->ops->map_direct_value_addr() which is then subsequently used as known scalar value for the register, that is, it is marked as __mark_reg_known() with the read value at verification time. Before a23740ec43ba, the register content was marked as an unknown scalar so the verifier could not make any assumptions about the map content. The current implementation however is prone to a TOCTOU race, meaning, the value read as known scalar for the register is not guaranteed to be exactly the same at a later point when the program is executed, and as such, the prior made assumptions of the verifier with regards to the program will be invalid which can cause issues such as OOB access, etc. While the BPF_F_RDONLY_PROG map flag is always fixed and required to be specified at map creation time, the map->frozen property is initially set to false for the map given the map value needs to be populated, e.g. for global data sections. Once complete, the loader "freezes" the map from user space such that no subsequent updates/deletes are possible anymore. For the rest of the lifetime of the map, this freeze one-time trigger cannot be undone anymore after a successful BPF_MAP_FREEZE cmd return. Meaning, any new BPF_* cmd calls which would update/delete map entries will be rejected with -EPERM since map_get_sys_perms() removes the FMODE_CAN_WRITE permission. This also means that pending update/delete map entries must still complete before this guarantee is given. This corner case is not an issue for loaders since they create and prepare such program private map in successive steps. However, a malicious user is able to trigger this TOCTOU race in two different ways: i) via userfaultfd, and ii) via batched updates. For i) userfaultfd is used to expand the competition interval, so that map_update_elem() can modify the contents of the map after map_freeze() and bpf_prog_load() were executed. This works, because userfaultfd halts the parallel thread which triggered a map_update_elem() at the time where we copy key/value from the user buffer and this already passed the FMODE_CAN_WRITE capability test given at that time the map was not "frozen". Then, the main thread performs the map_freeze() and bpf_prog_load(), and once that had completed successfully, the other thread is woken up to complete the pending map_update_elem() which then changes the map content. For ii) the idea of the batched update is similar, meaning, when there are a large number of updates to be processed, it can increase the competition interval between the two. It is therefore possible in practice to modify the contents of the map after executing map_freeze() and bpf_prog_load(). One way to fix both i) and ii) at the same time is to expand the use of the map's map->writecnt. The latter was introduced in fc9702273e2e ("bpf: Add mmap() support for BPF_MAP_TYPE_ARRAY") and further refined in 1f6cb19be2e2 ("bpf: Prevent re-mmap()'ing BPF map as writable for initially r/o mapping") with the rationale to make a writable mmap()'ing of a map mutually exclusive with read-only freezing. The counter indicates writable mmap() mappings and then prevents/fails the freeze operation. Its semantics can be expanded beyond just mmap() by generally indicating ongoing write phases. This would essentially span any parallel regular and batched flavor of update/delete operation and then also have map_freeze() fail with -EBUSY. For the check_mem_access() in the verifier we expand upon the bpf_map_is_rdonly() check ensuring that all last pending writes have completed via bpf_map_write_active() test. Once the map->frozen is set and bpf_map_write_active() indicates a map->writecnt of 0 only then we are really guaranteed to use the map's data as known constants. For map->frozen being set and pending writes in process of still being completed we fall back to marking that register as unknown scalar so we don't end up making assumptions about it. With this, both TOCTOU reproducers from i) and ii) are fixed. Note that the map->writecnt has been converted into a atomic64 in the fix in order to avoid a double freeze_mutex mutex_{un,}lock() pair when updating map->writecnt in the various map update/delete BPF_* cmd flavors. Spanning the freeze_mutex over entire map update/delete operations in syscall side would not be possible due to then causing everything to be serialized. Similarly, something like synchronize_rcu() after setting map->frozen to wait for update/deletes to complete is not possible either since it would also have to span the user copy which can sleep. On the libbpf side, this won't break d66562fba1ce ("libbpf: Add BPF object skeleton support") as the anonymous mmap()-ed "map initialization image" is remapped as a BPF map-backed mmap()-ed memory where for .rodata it's non-writable.

Daniel Borkmann committed 5 years ago

Commit 353050b1 parent 6060a6c3 files · +54 −23Browse files

Unified · Split

3 files
  1. include/linux/bpf.h +2 −1
  2. kernel/bpf/syscall.c +36 −21
  3. kernel/bpf/verifier.c +16 −1
include/linux/bpf.h+2−1
@@ -193,7 +193,7 @@ struct bpf_map { · 192 unmodified lines
193193 atomic64_t usercnt;
194194 struct work_struct work;
195195 struct mutex freeze_mutex;
196− u64 writecnt; /* writable mmap cnt; protected by freeze_mutex */
196+ atomic64_t writecnt;
197197 };
198198
199199 static inline bool map_value_has_spin_lock(const struct bpf_map *map)
@@ -1419,6 +1419,7 @@ void bpf_map_put(struct bpf_map *map); · 1219 unmodified lines
14191419 void *bpf_map_area_alloc(u64 size, int numa_node);
14201420 void *bpf_map_area_mmapable_alloc(u64 size, int numa_node);
14211421 void bpf_map_area_free(void *base);
1422+bool bpf_map_write_active(const struct bpf_map *map);
14221423 void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr);
14231424 int generic_map_lookup_batch(struct bpf_map *map,
14241425 const union bpf_attr *attr,
kernel/bpf/syscall.c+36−21
@@ -132,6 +132,21 @@ static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) · 131 unmodified lines
132132 return map;
133133 }
134134
135+static void bpf_map_write_active_inc(struct bpf_map *map)
136+{
137+ atomic64_inc(&map->writecnt);
138+}
139+
140+static void bpf_map_write_active_dec(struct bpf_map *map)
141+{
142+ atomic64_dec(&map->writecnt);
143+}
144+
145+bool bpf_map_write_active(const struct bpf_map *map)
146+{
147+ return atomic64_read(&map->writecnt) != 0;
148+}
149+
135150 static u32 bpf_map_value_size(const struct bpf_map *map)
136151 {
137152 if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
@@ -601,11 +616,8 @@ static void bpf_map_mmap_open(struct vm_area_struct *vma) · 463 unmodified lines
601616 {
602617 struct bpf_map *map = vma->vm_file->private_data;
603618
604− if (vma->vm_flags & VM_MAYWRITE) {
605− mutex_lock(&map->freeze_mutex);
606− map->writecnt++;
607− mutex_unlock(&map->freeze_mutex);
608− }
619+ if (vma->vm_flags & VM_MAYWRITE)
620+ bpf_map_write_active_inc(map);
609621 }
610622
611623 /* called for all unmapped memory region (including initial) */
@@ -613,11 +625,8 @@ static void bpf_map_mmap_close(struct vm_area_struct *vma) · 1 unmodified line
613625 {
614626 struct bpf_map *map = vma->vm_file->private_data;
615627
616− if (vma->vm_flags & VM_MAYWRITE) {
617− mutex_lock(&map->freeze_mutex);
618− map->writecnt--;
619− mutex_unlock(&map->freeze_mutex);
620− }
628+ if (vma->vm_flags & VM_MAYWRITE)
629+ bpf_map_write_active_dec(map);
621630 }
622631
623632 static const struct vm_operations_struct bpf_map_default_vmops = {
@@ -668,7 +677,7 @@ static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma) · 44 unmodified lines
668677 goto out;
669678
670679 if (vma->vm_flags & VM_MAYWRITE)
671− map->writecnt++;
680+ bpf_map_write_active_inc(map);
672681 out:
673682 mutex_unlock(&map->freeze_mutex);
674683 return err;
@@ -1139,6 +1148,7 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr) · 464 unmodified lines
11391148 map = __bpf_map_get(f);
11401149 if (IS_ERR(map))
11411150 return PTR_ERR(map);
1151+ bpf_map_write_active_inc(map);
11421152 if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
11431153 err = -EPERM;
11441154 goto err_put;
@@ -1174,6 +1184,7 @@ free_value: · 29 unmodified lines
11741184 free_key:
11751185 kvfree(key);
11761186 err_put:
1187+ bpf_map_write_active_dec(map);
11771188 fdput(f);
11781189 return err;
11791190 }
@@ -1196,6 +1207,7 @@ static int map_delete_elem(union bpf_attr *attr) · 16 unmodified lines
11961207 map = __bpf_map_get(f);
11971208 if (IS_ERR(map))
11981209 return PTR_ERR(map);
1210+ bpf_map_write_active_inc(map);
11991211 if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
12001212 err = -EPERM;
12011213 goto err_put;
@@ -1226,6 +1238,7 @@ static int map_delete_elem(union bpf_attr *attr) · 24 unmodified lines
12261238 out:
12271239 kvfree(key);
12281240 err_put:
1241+ bpf_map_write_active_dec(map);
12291242 fdput(f);
12301243 return err;
12311244 }
@@ -1533,6 +1546,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr) · 301 unmodified lines
15331546 map = __bpf_map_get(f);
15341547 if (IS_ERR(map))
15351548 return PTR_ERR(map);
1549+ bpf_map_write_active_inc(map);
15361550 if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
15371551 !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
15381552 err = -EPERM;
@@ -1597,6 +1611,7 @@ free_value: · 58 unmodified lines
15971611 free_key:
15981612 kvfree(key);
15991613 err_put:
1614+ bpf_map_write_active_dec(map);
16001615 fdput(f);
16011616 return err;
16021617 }
@@ -1624,8 +1639,7 @@ static int map_freeze(const union bpf_attr *attr) · 21 unmodified lines
16241639 }
16251640
16261641 mutex_lock(&map->freeze_mutex);
1627−
1628− if (map->writecnt) {
1642+ if (bpf_map_write_active(map)) {
16291643 err = -EBUSY;
16301644 goto err_put;
16311645 }
@@ -4171,6 +4185,9 @@ static int bpf_map_do_batch(const union bpf_attr *attr, · 2539 unmodified lines
41714185 union bpf_attr __user *uattr,
41724186 int cmd)
41734187 {
4188+ bool has_read = cmd == BPF_MAP_LOOKUP_BATCH ||
4189+ cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
4190+ bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
41744191 struct bpf_map *map;
41754192 int err, ufd;
41764193 struct fd f;
@@ -4183,16 +4200,13 @@ static int bpf_map_do_batch(const union bpf_attr *attr, · 6 unmodified lines
41834200 map = __bpf_map_get(f);
41844201 if (IS_ERR(map))
41854202 return PTR_ERR(map);
4186−
4187− if ((cmd == BPF_MAP_LOOKUP_BATCH ||
4188− cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) &&
4189− !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
4203+ if (has_write)
4204+ bpf_map_write_active_inc(map);
4205+ if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
41904206 err = -EPERM;
41914207 goto err_put;
41924208 }
4193−
4194− if (cmd != BPF_MAP_LOOKUP_BATCH &&
4195− !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
4209+ if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
41964210 err = -EPERM;
41974211 goto err_put;
41984212 }
@@ -4205,8 +4219,9 @@ static int bpf_map_do_batch(const union bpf_attr *attr, · 6 unmodified lines
42054219 BPF_DO_BATCH(map->ops->map_update_batch);
42064220 else
42074221 BPF_DO_BATCH(map->ops->map_delete_batch);
4208−
42094222 err_put:
4223+ if (has_write)
4224+ bpf_map_write_active_dec(map);
42104225 fdput(f);
42114226 return err;
42124227 }
kernel/bpf/verifier.c+16−1
@@ -4056,7 +4056,22 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) · 4055 unmodified lines
40564056
40574057 static bool bpf_map_is_rdonly(const struct bpf_map *map)
40584058 {
4059− return (map->map_flags & BPF_F_RDONLY_PROG) && map->frozen;
4059+ /* A map is considered read-only if the following condition are true:
4060+ *
4061+ * 1) BPF program side cannot change any of the map content. The
4062+ * BPF_F_RDONLY_PROG flag is throughout the lifetime of a map
4063+ * and was set at map creation time.
4064+ * 2) The map value(s) have been initialized from user space by a
4065+ * loader and then "frozen", such that no new map update/delete
4066+ * operations from syscall side are possible for the rest of
4067+ * the map's lifetime from that point onwards.
4068+ * 3) Any parallel/pending map update/delete operations from syscall
4069+ * side have been completed. Only after that point, it's safe to
4070+ * assume that map value(s) are immutable.
4071+ */
4072+ return (map->map_flags & BPF_F_RDONLY_PROG) &&
4073+ READ_ONCE(map->frozen) &&
4074+ !bpf_map_write_active(map);
40604075 }
40614076
40624077 static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)