BPF List
 help / color / mirror / Atom feed
* [PATCH bpf-next v6 0/4] bpf: Fix task work scheduling races
@ 2026-10-10  4:21 Yun Lu
  2026-10-10  4:21 ` [PATCH bpf-next v6 1/4] bpf: Fix NULL task dereference in task work cancellation Yun Lu
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Yun Lu @ 2026-10-10  4:21 UTC (permalink / raw)
  To: ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, ihor.solodrai
  Cc: yatsenko, bpf

From: Yun Lu <luyun@kylinos.cn>

This series fixes two races in the bpf_task_work scheduling kfuncs and
adds a regression test for each.  Each fix is followed by its test.

Patch 1 captures the task pointer before publishing the callback, which
can clear ctx->task before the scheduling handler attempts cancellation.
The existing RCU read-side section keeps the captured task alive because
bpf_task_release() is put_task_struct_rcu_user().

Patch 2 adds a 1500-round cross-CPU stress test for the cancellation
races: context reuse and map-value deletion racing with scheduling or
callback completion.  It does not force the exact faulting interleavings.

Patch 3 rejects context reuse while the previous scheduling irq_work is
still BUSY.  Otherwise a delayed handler can consume the next round's
SCHEDULING state and leave a false SCHEDULED state with a NULL task.

Patch 4 adds a separate test for that BUSY gate.  A bounded fexit wait on
task_work_add() holds the real scheduling handler after publication.
The target's next syscall attempts context reuse after its callback
wrapper has returned.  Observing its acknowledgment inside the fexit
wait proves the attempt occurred while the old irq_work was still BUSY.
Check rejection with -EBUSY, bounded recovery and exactly-once delivery.
Missed windows are retried within a bounded attempt budget.

Changes since v5:

- Narrow the race test to the cancellation races it covers and add the
  task_work_busy test: a bounded fexit wait on task_work_add() holds
  the real window while the target thread attempts reuse after its
  callback wrapper returned, asserting -EBUSY, bounded recovery and
  exactly-once delivery.
- Give each attempt dedicated workers and a fresh map value; reset the
  shared state before the workers are enabled and reuse it only after
  their TIDs have left PID lookup.
- Skip on fewer than two CPUs or confirmed PREEMPT_RT.  Reorder the
  series so each fix is followed by its test.  Kernel patches
  unchanged.

v5: https://lore.kernel.org/all/20260930085417.186729-1-luyun_611@163.com/

Changes since v4 (selftest only; patches 1 and 2 are unchanged):

- Rework the commit message to map each variant to the races fixed by
  this series, and note that the stress test does not force the exact
  faulting interleavings.
- Merge the trigger and target threads into one worker function, name
  the polling bounds, and accept only -ENOENT in the deletion-race
  variant (-EBUSY is retried inside the BPF program and never
  published to userspace).

v4: https://lore.kernel.org/all/20260929072800.113129-1-luyun_611@163.com/

Changes since v3:

- Drop the get_task_struct()/put_task_struct() pair: capturing the
  pointer before task_work_add() is sufficient, since
  bpf_task_release() is put_task_struct_rcu_user() and the handler's
  RCU read-side section keeps the captured task alive.  Reword the
  RCU explanation.
- Split the BUSY check and the one-time irq_work initialization into
  a separate patch 2, with the full interleaving and the failure it
  prevents.
- Selftest code unchanged; commit message wording only.

v3: https://lore.kernel.org/all/20260922100042.136818-1-luyun_611@163.com/

Changes since v2:

- Kernel: drop irq_work_sync() from the callback and both
  WARN_ON_ONCE() checks, as requested in review.  Following the
  suggested direction, the scheduling handler now takes its own task
  reference around task_work_add() and the post-add cancellation; the
  temporary ctx refcount from v2 is gone as well.  The callback ends
  up unchanged from upstream.
- The BUSY check in acquire is kept: without it a handler delayed
  between task_work_add() and its state cmpxchg can flip the next
  round into a bogus SCHEDULED, which later routes map-value deletion
  into task_work_cancel() with an already-reset ctx->task.
- Selftest is unchanged apart from the rebase.

v2: https://lore.kernel.org/all/20260921101453.69273-1-luyun_611@163.com/

Changes since v1:

- Kernel: rework the fix per review feedback.  Replace the round_refs
  ownership counter and the extra irq_work objects with a completion
  edge: the callback claims RUNNING and waits for the scheduling
  irq_work via irq_work_sync(), plus one temporary reference from the
  existing ctx refcount and a BUSY check covering the add-failure
  path.  No context fields or states are added.
- Selftest: address review feedback (single packed result store,
  bounded thread-start wait, tolerate the expected deletion-race
  outcomes).

v1: https://lore.kernel.org/bpf/20260918080014.54012-1-luyun_611@163.com/

Testing:

- Built with KASAN, lockdep, PROVE_RCU and DEBUG_ATOMIC_SLEEP in
  QEMU/KVM.  task_work_busy, the cancellation race test and the
  task_work family passed; under target-CPU contention the BUSY test
  retried missed windows and still completed its coverage.
- Without patch 3, task_work_busy failed the in-window -EBUSY
  assertion as expected.  On PREEMPT_RT it skipped after observing
  the irq_work handler thread.  Worker-creation and exit-probe
  failures produced the intended errors without secondary failures.

Yun Lu (4):
  bpf: Fix NULL task dereference in task work cancellation
  selftests/bpf: Add task work cancellation race test
  bpf: Prevent task work context reuse while irq_work is busy
  selftests/bpf: Add task work BUSY window test

 kernel/bpf/helpers.c                               |  54 +-
 .../selftests/bpf/prog_tests/test_task_work.c      | 843 +++++++++++++++++++++
 tools/testing/selftests/bpf/progs/task_work_busy.c | 380 ++++++++++
 tools/testing/selftests/bpf/progs/task_work_race.c | 126 +++
 4 files changed, 1393 insertions(+), 10 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/task_work_busy.c
 create mode 100644 tools/testing/selftests/bpf/progs/task_work_race.c

base-commit: 5dd1818b15d98d4a20806cd00b1b40320b06004f
-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-12  3:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-10  4:21 [PATCH bpf-next v6 0/4] bpf: Fix task work scheduling races Yun Lu
2026-10-10  4:21 ` [PATCH bpf-next v6 1/4] bpf: Fix NULL task dereference in task work cancellation Yun Lu
2026-10-10  4:21 ` [PATCH bpf-next v6 2/4] selftests/bpf: Add task work cancellation race test Yun Lu
2026-10-10  4:21 ` [PATCH bpf-next v6 3/4] bpf: Prevent task work context reuse while irq_work is busy Yun Lu
2026-10-10  4:21 ` [PATCH bpf-next v6 4/4] selftests/bpf: Add task work BUSY window test Yun Lu
2026-10-10  5:20   ` bot+bpf-ci
2026-10-12  3:23     ` luyun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox