Skip to content

Commit 592226d

Browse files
puranjaymohangregkh
authored andcommitted
bpf: return VMA snapshot from task_vma iterator
[ Upstream commit 4cbee02 ] Holding the per-VMA lock across the BPF program body creates a lock ordering problem when helpers acquire locks that depend on mmap_lock: vm_lock -> i_rwsem -> mmap_lock -> vm_lock Snapshot the VMA under the per-VMA lock in _next() via memcpy(), then drop the lock before returning. The BPF program accesses only the snapshot. The verifier only trusts vm_mm and vm_file pointers (see BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). vm_file is reference- counted with get_file() under the lock and released via fput() on the next iteration or in _destroy(). vm_mm is already correct because lock_vma_under_rcu() verifies vma->vm_mm == mm. All other pointers are left as-is by memcpy() since the verifier treats them as untrusted. Fixes: 4ac4546 ("bpf: Introduce task_vma open-coded iterator kfuncs") Signed-off-by: Puranjay Mohan <puranjay@kernel.org> Acked-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Mykyta Yatsenko <yatsenko@meta.com> Link: https://lore.kernel.org/r/20260408154539.3832150-4-puranjay@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 3745834 commit 592226d

1 file changed

Lines changed: 30 additions & 12 deletions

File tree

kernel/bpf/task_iter.c

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm)
808808
struct bpf_iter_task_vma_kern_data {
809809
struct task_struct *task;
810810
struct mm_struct *mm;
811-
struct vm_area_struct *locked_vma;
811+
struct vm_area_struct snapshot;
812812
u64 next_addr;
813813
};
814814

@@ -842,7 +842,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
842842

843843
/*
844844
* Reject irqs-disabled contexts including NMI. Operations used
845-
* by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async)
845+
* by _next() and _destroy() (vma_end_read, fput, bpf_iter_mmput_async)
846846
* can take spinlocks with IRQs disabled (pi_lock, pool->lock).
847847
* Running from NMI or from a tracepoint that fires with those
848848
* locks held could deadlock.
@@ -885,7 +885,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it,
885885
goto err_cleanup_iter;
886886
}
887887

888-
kit->data->locked_vma = NULL;
888+
kit->data->snapshot.vm_file = NULL;
889889
kit->data->next_addr = addr;
890890
return 0;
891891

@@ -947,35 +947,53 @@ bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data)
947947
return vma;
948948
}
949949

950+
static void bpf_iter_task_vma_snapshot_reset(struct vm_area_struct *snap)
951+
{
952+
if (snap->vm_file) {
953+
fput(snap->vm_file);
954+
snap->vm_file = NULL;
955+
}
956+
}
957+
950958
__bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it)
951959
{
952960
struct bpf_iter_task_vma_kern *kit = (void *)it;
953-
struct vm_area_struct *vma;
961+
struct vm_area_struct *snap, *vma;
954962

955963
if (!kit->data) /* bpf_iter_task_vma_new failed */
956964
return NULL;
957965

958-
if (kit->data->locked_vma) {
959-
vma_end_read(kit->data->locked_vma);
960-
kit->data->locked_vma = NULL;
961-
}
966+
snap = &kit->data->snapshot;
967+
968+
bpf_iter_task_vma_snapshot_reset(snap);
962969

963970
vma = bpf_iter_task_vma_find_next(kit->data);
964971
if (!vma)
965972
return NULL;
966973

967-
kit->data->locked_vma = vma;
974+
memcpy(snap, vma, sizeof(*snap));
975+
976+
/*
977+
* The verifier only trusts vm_mm and vm_file (see
978+
* BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). Take a reference
979+
* on vm_file; vm_mm is already correct because lock_vma_under_rcu()
980+
* verifies vma->vm_mm == mm. All other pointers are untrusted by
981+
* the verifier and left as-is.
982+
*/
983+
if (snap->vm_file)
984+
get_file(snap->vm_file);
985+
968986
kit->data->next_addr = vma->vm_end;
969-
return vma;
987+
vma_end_read(vma);
988+
return snap;
970989
}
971990

972991
__bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it)
973992
{
974993
struct bpf_iter_task_vma_kern *kit = (void *)it;
975994

976995
if (kit->data) {
977-
if (kit->data->locked_vma)
978-
vma_end_read(kit->data->locked_vma);
996+
bpf_iter_task_vma_snapshot_reset(&kit->data->snapshot);
979997
put_task_struct(kit->data->task);
980998
bpf_iter_mmput_async(kit->data->mm);
981999
bpf_mem_free(&bpf_global_ma, kit->data);

0 commit comments

Comments
 (0)