← WebKit — 2026-W37
0ccf17b18a16f173f05d78da36e3bb5c1cc5531b [iOS] Heap UAF in WebPageProxy::attachmentForIdentifier from NSItemProvider loadHandler
severity medium
class Race
confidence 0.6
signal score 13.5
Source/WebKit/UIProcess
patch-now
Primitive: off-main-thread access to WebPageProxy::attachmentForIdentifier / m_attachments from the item-provider file callback
Triage note: Adds RELEASE_ASSERT(RunLoop::isMain()) to attachmentForIdentifier and captures the RefPtr attachment and attachmentIdentifier up front on the main thread instead of calling attachmentForIdentifier inside the background WebItemProviderFileCallback. The old code read the main-thread-only attachment map off-thread, a data race / potential UAF during promised-attachment drags.
Triage note: Adds RELEASE_ASSERT(RunLoop::isMain()) to attachmentForIdentifier and captures the RefPtr attachment and attachmentIdentifier up front on the main thread instead of calling attachmentForIdentifier inside the background WebItemProviderFileCallback. The old code read the main-thread-only attachment map off-thread, a data race / potential UAF during promised-attachment drags.
Structural signals: smartptr_member_added (+3.0), security_assert (+3.0), null_guard (+1.2), msg_strong (+3.0), msg_medium (+2.0), surgical (+1.3)
Commit message
[iOS] Heap UAF in WebPageProxy::attachmentForIdentifier from NSItemProvider loadHandler
rdar://178069797
Reviewed by Wenson Hsieh.
A compromised WebContent process can trigger a heap-use-after-free in the UI
process for iOS WKWebView embedders that set _attachmentElementEnabled=YES.
WebPageProxy's attachment map, m_attachmentIdentifierToAttachmentMap, is a
plain HashMap with no lock, and the main thread and a background thread can
both reach it at once when a user drags an attachment onto a drag and drop
target. NSItemProvider runs the fileCallback installed by
-[WKContentView _prepareToDragPromisedAttachment:] on a background queue,
which calls WebPageProxy::attachmentForIdentifier(), which then reads the map
from the background queue. From the main thread, the WebContent process sends
`Messages::WebPageProxy::RegisterAttachmentIdentifier`, and its handler calls
`set` on the same map, modifying it.
When map grows due to attachment registration from the main thread,
HashTable::rehash() calls fastFree() on the old table while the background thread
still probes it. Since the attacker controls the timing and number of the
`RegisterAttachmentIdentifier` messages, they control when the free happens.
Fix this in `_prepareToDragPromisedAttachment` by capturing the attachment from
`attachmentForIdentifier` a single time on the main thread at the beginning
rather than re-reading a second time from a background thread, and by
ensuring ensureLocalDragSessionContext/addTemporaryDirectory is dispatched to
the main thread from the callback.
Test: Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::attachmentForIdentifier const):
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _prepareToDragPromisedAttachment:]):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKAttachmentTests.mm:
(TestWebKitAPI::TEST(WKAttachmentTestsIOS, LoadPromisedAttachmentFileRepresentationOffMainThread)):
Identifier: 316606.671@safari-7625-branch
Before / after
Loading diff…
On This Page