From: Hou Tao <houtao1@xxxxxxxxxx> Hi, The patchset aims to fix the release of inner map in map array or map htab. The release of inner map is different with normal map. For normal map, the map is released after the bpf program which uses the map is destroyed, because the bpf program tracks the used maps. However bpf program can not track the used inner map because these inner map may be updated or deleted dynamically, and for now the ref-counter of inner map is decreased after the inner map is remove from outer map, so the inner map may be freed before the bpf program, which is accessing the inner map, exits and there will be use-after-free problem as demonstrated by patch #6. The patchset fixes the problem by deferring the release of inner map. The freeing of inner map is deferred according to the sleepable attributes of the bpf programs which own the outer map. Patch #1 fixes the warning when running the newly-added selftest under interpreter mode. Patch #2 adds more parameters to .map_fd_put_ptr() to prepare for the fix. Patch #3 fixes the incorrect value of need_defer when freeing the fd array. Patch #4 fixes the potential use-after-free problem by using call_rcu_tasks_trace() and call_rcu() to wait for one tasks trace RCU GP and one RCU GP unconditionally. Patch #5 optimizes the free of inner map by removing the unnecessary RCU GP waiting. Patch #6 adds a selftest to demonstrate the potential use-after-free problem. Patch #7 updates a selftest to update outer map in syscall bpf program. Please see individual patches for more details. And comments are always welcome. Change Log: v5: * patch #3: rename fd_array_map_delete_elem_with_deferred_free() to __fd_array_map_delete_elem() (Alexei) * patch #5: use atomic64_t instead of atomic_t to prevent potential overflow (Alexei) * patch #7: use ptr_to_u64() helper instead of force casting to initialize pointers in bpf_attr (Alexei) v4: https://lore.kernel.org/bpf/20231130140120.1736235-1-houtao@xxxxxxxxxxxxxxx * patch #2: don't use "deferred", use "need_defer" uniformly * patch #3: newly-added, fix the incorrect value of need_defer during fd array free. * patch #4: doesn't consider the case in which bpf map is not used by any bpf program and only use sleepable_refcnt to remove unnecessary tasks trace RCU GP (Alexei) * patch #4: remove memory barriers added due to cautiousness (Alexei) v3: https://lore.kernel.org/bpf/20231124113033.503338-1-houtao@xxxxxxxxxxxxxxx * multiple variable renamings (Martin) * define BPF_MAP_RCU_GP/BPF_MAP_RCU_TT_GP as bit (Martin) * use call_rcu() and its variants instead of synchronize_rcu() (Martin) * remove unnecessary mask in bpf_map_free_deferred() (Martin) * place atomic_or() and the related smp_mb() together (Martin) * add patch #6 to demonstrate that updating outer map in syscall program is dead-lock free (Alexei) * update comments about the memory barrier in bpf_map_fd_put_ptr() * update commit message for patch #3 and #4 to describe more details v2: https://lore.kernel.org/bpf/20231113123324.3914612-1-houtao@xxxxxxxxxxxxxxx * defer the invocation of ops->map_free() instead of bpf_map_put() (Martin) * update selftest to make it being reproducible under JIT mode (Martin) * remove unnecessary preparatory patches v1: https://lore.kernel.org/bpf/20231107140702.1891778-1-houtao@xxxxxxxxxxxxxxx Hou Tao (7): bpf: Check rcu_read_lock_trace_held() before calling bpf map helpers bpf: Add map and need_defer parameters to .map_fd_put_ptr() bpf: Set need_defer as false when clearing fd array during map free bpf: Defer the free of inner map when necessary bpf: Optimize the free of inner map selftests/bpf: Add test cases for inner map selftests/bpf: Test outer map update operations in syscall program include/linux/bpf.h | 15 +- kernel/bpf/arraymap.c | 33 ++-- kernel/bpf/core.c | 4 + kernel/bpf/hashtab.c | 6 +- kernel/bpf/helpers.c | 13 +- kernel/bpf/map_in_map.c | 17 ++- kernel/bpf/map_in_map.h | 2 +- kernel/bpf/syscall.c | 40 ++++- kernel/bpf/verifier.c | 4 +- .../selftests/bpf/prog_tests/map_in_map.c | 141 ++++++++++++++++++ .../selftests/bpf/prog_tests/syscall.c | 30 +++- .../selftests/bpf/progs/access_map_in_map.c | 93 ++++++++++++ tools/testing/selftests/bpf/progs/syscall.c | 96 +++++++++++- 13 files changed, 453 insertions(+), 41 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/map_in_map.c create mode 100644 tools/testing/selftests/bpf/progs/access_map_in_map.c -- 2.29.2