Skip to content

chore: cherry-pick 074d472db745 from chromium#50443

Merged
jkleinsc merged 2 commits into39-x-yfrom
cherry-pick/39-x-y/chromium/074d472db745
Mar 24, 2026
Merged

chore: cherry-pick 074d472db745 from chromium#50443
jkleinsc merged 2 commits into39-x-yfrom
cherry-pick/39-x-y/chromium/074d472db745

Conversation

@VerteDinde
Copy link
Copy Markdown
Member

[M146][base] Fix UAF in base::OnceCallbackList on re-entrant Notify()

Before this patch, base::OnceCallbackList was susceptible to a
heap-use-after-free when Notify() was called re-entrantly.

The UAF occurred because OnceCallbackList::RunCallback() immediately
spliced executed nodes out of callbacks_ and into null_callbacks_.
If a nested Notify() executed a node that an outer Notify() loop was
already holding an iterator to, and that node's subscription was
subsequently destroyed during the re-entrant cycle, the node would be
physically erased from null_callbacks_. When control returned to the
outer loop, it would attempt to evaluate the now-dangling iterator.

This CL fixes the bug by deferring list mutations until the outermost
iteration completes:

  1. RunCallback() no longer splices nodes during iteration.
  2. Cancellation logic is pushed down to the subclasses via a new
    CancelCallback() hook, which is an extension to the pre-existing
    CancelNullCallback() with increased responsibilities and clearer
    semantics.
  3. If a subscription is destroyed while is_iterating is true,
    OnceCallbackList resets the node and stashes its iterator in
    pending_erasures_.
  4. A new CleanUpNullCallbacksPostIteration() phase runs at the end
    of the outermost Notify(), which safely splices executed nodes
    into null_callbacks_ and physically erases the pending dead nodes.

As a side effect, the type-trait hack in Notify() based on
is_instantiation<CallbackType, OnceCallback> can be removed, because
this information is exposed directly by
OnceCallbackList::CleanUpNullCallbacksPostIteration().

The newly-added unit-test
CallbackListTest.OnceCallbackListCancelDuringReentrantNotify reproduces
the scenario and crashed before this patch.

(cherry picked from commit 36acd49636845be2419269acbe9a5137da3d5d96)

Change-Id: I6b1e2bcb97be1bc8d6a15e5ca7511992e00e1772
Fixed: 489381399
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7627506
Commit-Queue: Mikel Astiz mastiz@chromium.org
Reviewed-by: Gabriel Charette gab@chromium.org
Cr-Original-Commit-Position: refs/heads/main@{#1594520}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7653916
Bot-Commit: Rubber Stamper rubber-stamper@appspot.gserviceaccount.com
Cr-Commit-Position: refs/branch-heads/7680@{#2287}
Cr-Branched-From: 76b7d80e5cda23fe6537eed26d68c92e995c7f39-refs/heads/main@{#1582197}

Notes: Backported fix for 489381399.

@VerteDinde VerteDinde requested a review from a team as a code owner March 23, 2026 22:28
@VerteDinde VerteDinde added semver/patch backwards-compatible bug fixes backport-check-skip Skip trop's backport validity checking 39-x-y labels Mar 23, 2026
@jkleinsc jkleinsc merged commit 64373df into 39-x-y Mar 24, 2026
58 checks passed
@jkleinsc jkleinsc deleted the cherry-pick/39-x-y/chromium/074d472db745 branch March 24, 2026 01:40
@release-clerk
Copy link
Copy Markdown

release-clerk bot commented Mar 24, 2026

Release Notes Persisted

Backported fix for 489381399.

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

Labels

39-x-y backport-check-skip Skip trop's backport validity checking semver/patch backwards-compatible bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants