Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 16b1bde3c1918236d0eefee504bcf4180566087f
      
https://github.com/WebKit/WebKit/commit/16b1bde3c1918236d0eefee504bcf4180566087f
  Author: Zak Ridouh <[email protected]>
  Date:   2026-06-30 (Tue, 30 Jun 2026)

  Changed paths:
    A 
LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private-expected.txt
    A 
LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private.html
    M Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp

  Log Message:
  -----------
  [CoreIPC] [NP] Heap UAF in WebCore::IDBServer::MemoryIndexCursor reverse 
iterator when a Prev/Prevunique cursor's next-higher index entry is deleted
<https://bugs.webkit.org/show_bug.cgi?id=313818>
<rdar://174678764>

Reviewed by Sihui Liu.

MemoryIndexCursor caches an IndexValueStore::Iterator across IPC messages.
For Prev/Prevunique cursors this wraps std::set<IDBKeyData>::reverse_iterator
objects (one for the outer IndexValueStore::m_orderedKeys set, one nested in
IndexValueEntry::Iterator for the inner per-index-key set). A
std::reverse_iterator stores a forward base() iterator pointing one element
past the logical position; for libc++ std::set that is a raw __tree_node*.

MemoryIndexCursor::indexValueChanged() only invalidates m_currentIterator
when the changed (key, primaryKey) equals the cursor's current logical
position. Deleting the next-higher index key (Variant A, outer set) or the
next-higher primary key under a shared index key (Variant B, inner set)
therefore frees exactly the __tree_node base() references while the guard
early-returns. The next IterateCursor IPC executes ++m_reverseIterator =>
--base() => __tree_prev_iter(freed_node), a heap-use-after-free in
com.apple.WebKit.Networking reachable from a compromised WebContent process
via NetworkStorageManager IPC with WCP-controlled
IDBDatabaseIdentifier.m_isTransient = true forcing MemoryIDBBackingStore.

Fix by gating the equality early-return on info().isDirectionForward(). For
reverse cursors we now invalidate m_currentIterator on any index mutation;
iterate() already re-seeks via reverseFind(m_currentKey, m_currentPrimaryKey)
when the iterator is invalid. Both removeEntriesWithValueKey() erase paths
(outer m_orderedKeys.erase() and inner IndexValueEntry::removeKey()) reach
indexValueChanged() through MemoryIndex::notifyCursorsOfValueChange(), so
both variants are closed.

* 
LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private-expected.txt:
 Added.
* 
LayoutTests/storage/indexeddb/index-cursor-reverse-delete-next-higher-key-private.html:
 Added.
* Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp:
(WebCore::IDBServer::MemoryIndexCursor::indexValueChanged):

Originally-landed-as: 305413.842@safari-7624-branch (d14d12e915f3). 
rdar://180436983
Canonical link: https://commits.webkit.org/316129@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to