summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2026-10-17 16:37:07 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-10-17 21:58:22 +0000
commitdfcd1765911223df60845e288ad392d5237f47a3 (patch)
tree54a55bb6a02814bda011b97caae2d77e113a82d2 /include/linux
parentccb88db8dac8fabde58656d5d4a33711e89c480a (diff)
downloadlinux-dfcd1765911223df60845e288ad392d5237f47a3.tar.gz
linux-dfcd1765911223df60845e288ad392d5237f47a3.zip
bpf: Reject sleepable programs for task_vma iterator
A sleepable "iter.s/task_vma" program can be attached, but its ->show() callback runs with the mmap_lock of the iterated mm held for read. As soon as the program runs, bpf_iter_run_prog() calls might_fault(), and any bpf_copy_from_user() or bpf_copy_from_user_task() it does may really fault or take mmap_lock again. With lockdep this is reported as recursive locking of mmap_lock. Without lockdep, a fault on the reader's own mm, or access_process_vm() on the iterated mm, has to take mmap_lock for read again. If a writer queued up in the meantime that blocks behind the writer, which in turn waits for the read lock the iterator already holds, and the read() hangs: reader (iter.s/task_vma) other thread of the same mm task_vma_seq_get_next() mmap_read_lock(mm) mmap_write_lock(mm) <- waits bpf prog: copy_from_user() page fault mmap_read_lock(mm) <- queued behind the writer The reader waits killable, so the hang lasts until it gets a fatal signal. bpf_iter_link_attach() allows sleepable programs for the targets that set BPF_ITER_RESCHED, and task_vma sets it because cond_resched() between VMAs is fine with mmap_lock held. Rescheduling between objects and running a sleepable program inside ->show() are different properties, though, and task_vma only has the first one. The open-coded task_vma iterator does not have this problem since it hands out a snapshot of the VMA and holds no lock when it returns to the program. The vma handed to the program is only stable under mmap_lock, so the lock can't be dropped around ->show(). Add a feature flag BPF_ITER_NOSLEEP for targets which can't run sleepable programs although they can reschedule, and set it for task_vma. The check at attach time is not enough. BPF_LINK_UPDATE replaces the program of a link, and bpf_iter_link_replace() only compares the type, the attach type and the BTF id of the two programs, which are the same for a sleepable and a non-sleepable one. Do the check there as well. That also closes this way around the existing rule: so far a sleepable program could be put on a link of a target that doesn't set BPF_ITER_RESCHED, like the hash map element iterator, which runs it under rcu_read_lock(). BPF_LINK_CREATE of a sleepable program for the task_vma target, and BPF_LINK_UPDATE to one, now fail with -EINVAL, also for programs that don't touch user memory and have been working since sleepable iterator programs exist. The programs can still be loaded. They have to be loaded as non-sleepable programs, or use the open-coded iterator. Fixes: b77fb25dcb34 ("bpf: Add support for bpf iterator programs to use sleepable helpers") Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261017163745.3341787-6-alexei.starovoitov@gmail.com
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/bpf.h3
1 files changed, 2 insertions, 1 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 54144372281c..46d325aa178e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3137,7 +3137,8 @@ typedef const struct bpf_func_proto *
const struct bpf_prog *prog);
enum bpf_iter_feature {
- BPF_ITER_RESCHED = BIT(0),
+ BPF_ITER_RESCHED = BIT(0), /* may cond_resched() between objects */
+ BPF_ITER_NOSLEEP = BIT(1), /* ->show() can't run sleepable progs */
};
#define BPF_ITER_CTX_ARG_MAX 2