Skip to content

Enqueue wait handle free to epoch work item during set_wait_handle#5307

Draft
mikeagun wants to merge 5 commits into
microsoft:mainfrom
mikeagun:fix/ring-buffer-wait-event
Draft

Enqueue wait handle free to epoch work item during set_wait_handle#5307
mikeagun wants to merge 5 commits into
microsoft:mainfrom
mikeagun:fix/ring-buffer-wait-event

Conversation

@mikeagun

Copy link
Copy Markdown
Contributor

Description

Describe the purpose of and changes within this Pull Request.
Please reference an issue with a keyword such as Fixes #abc, Closes #xyz, etc., so the work can be tracked.

Testing

Do any existing tests cover this change? Are new tests needed?

If new tests were added:

  • Unit tests are added.
  • Driver tests are added.

Documentation

Is there any documentation impact for this change?

Installation

Is there any installer impact for this change?

Michael Agun and others added 5 commits May 20, 2026 13:13
F-001 (Critical): _ring_buffer_notify_consumer reads kernel_page->wait_event
without synchronization while set_wait_handle/destroy can concurrently
replace and dereference the old event object, causing a use-after-free.

Fix: Reader reads the pointer exactly once via ReadPointerNoFence (zero
overhead, matching ebpf_program.c:1576 pattern). Writer atomically swaps
via InterlockedExchangePointer, then defers ObDereferenceObject of the
old event to an epoch work item so in-flight readers (BPF programs within
an epoch) can safely call KeSetEvent before the event is freed.

F-007 (Medium): Callers pass ebpf_handle_invalid to clear the wait handle,
but ObReferenceObjectByHandle fails on the invalid handle and the function
returns early without clearing or dereferencing the old event — leaking
the kernel event object reference.

Fix: Check for ebpf_handle_invalid before ObReferenceObjectByHandle. When
clearing, swap in NULL and let the deferred-deref logic release the old
event.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verify that ebpf_map_set_wait_handle_internal with ebpf_handle_invalid
properly clears the old event reference (returns EBPF_SUCCESS instead of
EBPF_INVALID_ARGUMENT), and that a new handle can be set afterward.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stress test: producer thread writes ring buffer records while another
thread rapidly sets and clears the wait handle. Exercises the
ReadPointerNoFence + epoch-deferred ObDereferenceObject synchronization.
Run for 1-2 seconds to maximize race window coverage.

Added to both api_test.exe (kernel test) and unit_tests.exe (usersim).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ebpf_ring_buffer_set_wait_handle runs inside an epoch via the protocol
handler. The previous OOM fallback called ebpf_epoch_synchronize, which
waits for the current epoch to retire — but the caller is an active
reader in that epoch, causing self-deadlock.

Fix: probe-allocate an epoch work item before the swap. If allocation
fails, fail the operation before modifying state. After the swap,
allocate with the real old_wait_event context. If the post-swap
allocation fails (extremely unlikely after probe success), log and
leak the event reference rather than risk deadlock.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

This pull request isn't linked to any GitHub issue. Please reference an issue with a keyword such as Fixes #123, Closes #456, etc., so the work can be tracked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant