d5b71798805e687cd0e2f68a76c366f6c8f7ff3b [M153] Prevent UAF in TargetHandler::SetAttachedTargetsOfType
The bug at a glance
Browser-process use-after-free in the DevTools TargetHandler auto-attach logic: iterating a copied map and calling AutoDetach could synchronously destroy sibling DevToolsAgentHost objects still referenced by bare pointer keys, causing a UAF. Exploitation requires a DevTools/CDP client with Target.autoAttachRelated access and OOPIF/hidden-target setup, which raises the bar; the privileged attack surface and need for an attached debugger cap this at medium rather than high. It is reachable by any code able to speak CDP to the browser (e.g. automation, some extensions).
In SetAttachedTargetsOfType, detaching one target can synchronously dispose child sessions and tear down owned resources (hidden targets), destroying sibling DevToolsAgentHost instances and mutating auto_attached_sessions_ while the detach loop still holds bare DevToolsAgentHost* keys from a stale copy.
Root cause
The original code copied auto_attached_sessions_ into old_sessions and iterated it, calling AutoDetach(source, host.get()) inline. AutoDetach on a subframe target can synchronously dispose child sessions and destroy sibling agent hosts, invalidating the bare-pointer keys (and session objects) referenced by the still-running loop and by the subsequent new_hosts loop that consulted old_sessions.contains(host.get()). The fix splits the work: first collect strong scoped_refptr references for every host that needs detaching while all entries are alive, then run AutoDetach over that owned vector (AutoDetach re-validates each host against the live auto_attached_sessions_ map and skips any already detached by cascades), and finally check containment against the live auto_attached_sessions_ instead of the stale copy.
Key code
Collect strong refs before detaching so synchronous cascade destruction of sibling agent hosts cannot free the pointers mid-iteration.
std::vector<scoped_refptr<DevToolsAgentHost>> hosts_to_detach;
for (const auto& entry : auto_attached_sessions_) {
scoped_refptr<DevToolsAgentHost> host(entry.first);
if (host->GetType() == type && entry.second->auto_attacher_id_ ==
reinterpret_cast<uintptr_t>(source) && !new_hosts.contains(host))
hosts_to_detach.push_back(std::move(host));
}
for (const auto& host : hosts_to_detach)
AutoDetach(source, host.get()); // re-validates against live map
Patch walkthrough
content/browser/devtools/protocol/target_handler.cc— SetAttachedTargetsOfType is restructured. Previously it iterated a stale copy old_sessions and called AutoDetach inline, then iterated new_hosts checking old_sessions.contains. Now it (1) iterates the live auto_attached_sessions_ taking strong scoped_refptr keys into hosts_to_detach for matching hosts, (2) runs AutoDetach over hosts_to_detach so the targets stay alive during detachment and AutoDetach can safely re-validate/skip ones already detached by cascades, and (3) attaches new hosts by checking the live auto_attached_sessions_.contains instead of the stale copy. This eliminates dereferencing freed sibling DevToolsAgentHost pointers when in-loop detachment synchronously destroys siblings.third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-related-hidden-targets-detach.js— New regression test: auto-attaches related targets for a page, creates an OOPIF, then creates 20 hidden targets under the iframe session and auto-attaches each, then performs a cross-site navigation that detaches the iframe and disposes its hidden targets. It verifies the iframe session is cleanly detached and the browser does not crash, exercising the sibling-destruction cascade.third_party/blink/web_tests/http/tests/inspector-protocol/target/auto-attach-related-hidden-targets-detach-expected.txt— Expected output confirming clean detach (‘iframe session detached’) and ‘SUCCESS: Navigated and detached without crash’.
Background
TargetHandler / auto-attach — DevTools (CDP) component that automatically attaches debugging sessions to related targets (e.g. OOPIFs, workers, hidden targets). auto_attached_sessions_ maps DevToolsAgentHost* to session state.
DevToolsAgentHost — Refcounted browser-process object representing a debuggable target. Bare pointers used as map keys can dangle if the object is destroyed while an iteration holds the key.
Hidden targets / detach cascade — Hidden targets created under a frame are owned by that frame’s session; detaching the frame synchronously disposes child sessions and destroys their agent hosts, mutating auto_attached_sessions_ during the loop.
Fixed/Bug references — Bug: 553119925; cherry-picked to M153 (branch 8010). Security-relevant UAF fix merged to a release branch.
Vulnerability window
- Introduction — SetAttachedTargetsOfType iterated a stale map copy and detached inline, assuming siblings remained valid across AutoDetach. (inferred)
- Discovery — Bug 553119925: cross-site navigation of a page with auto-attached iframe plus hidden targets triggered sibling destruction during the detach loop.
- Fix — Collect strong refs first, then detach using the owned vector and re-validate against the live map (commit 76d750b581).
- Merge — Cherry-picked to M153 branch 8010 as d5b7179880 with a web test.
Proof of concept
Conceptual only, and requires DevTools/CDP access. Via the DevTools protocol: Target.autoAttachRelated for a page, create an OOPIF, create multiple hidden targets under the iframe session and auto-attach them, then navigate the page cross-site. The iframe detach disposes the hidden targets, destroying sibling DevToolsAgentHosts while SetAttachedTargetsOfType iterates, triggering the UAF pre-patch. Exact heap state and crash reproduction cannot be derived from the diff.
Exploitation
- Access — Requires a client that can speak CDP to the browser with Target auto-attach capability (automation harness, DevTools, or a sufficiently privileged extension). (inferred)
- Setup — Auto-attach related targets, create an OOPIF, and create many hidden child targets to populate auto_attached_sessions_ with sibling agent hosts. (inferred)
- Trigger — Cross-site navigate the page so the iframe detaches and synchronously disposes its hidden targets during the detach loop. (inferred)
- Use — Freed sibling DevToolsAgentHost bare-pointer keys / session objects are dereferenced by the loop, yielding a browser-process UAF; weaponization would need heap grooming across refcounted hosts. (inferred)
Detection & hunting
For defenders and detection engineers:
- ASan heap-use-after-free in TargetHandler::SetAttachedTargetsOfType / AutoDetach —
- CDP Target.autoAttachRelated + hidden targets + navigation —
Audit directions
- content/browser/devtools/protocol/target_handler.cc — Audit every loop that iterates auto_attached_sessions_ (or copies thereof) and calls detach/dispose methods that can re-enter and mutate the map; ensure strong refs are held and containment checks use the live map. Review AutoDetach/AutoAttach for other callers assuming siblings survive.
- DevTools session/host lifetime — Look for other places that key containers on bare DevToolsAgentHost* and iterate while invoking methods that can synchronously destroy sibling hosts (hidden-target disposal, child-session teardown).