← WebKit — 2026-W37
a371ed314175328578fc843fa4914cb114715964 Make WTF::UUID unable to hold an invalid value, so one cannot be sent over IPC
severity low
class InputValidation
confidence 0.45
signal score 9.09
Source/JavaScriptCore/jit
Primitive: IPC-decoded UUID could be constructed with the reserved empty/deleted sentinel values, previously only caught by a RELEASE_ASSERT (process abort).
Triage note: WTF::UUID makes the raw-bytes/UInt128 constructors private and routes decoding through fallible tryCreate() factories that reject emptyValue/deletedValue, with consteval createConstant() for hardcoded UUIDs. Hardens IPC deserialization against sentinel-value UUIDs; prior behavior was a controlled abort, so low severity and not memory corruption.
Triage note: WTF::UUID makes the raw-bytes/UInt128 constructors private and routes decoding through fallible tryCreate() factories that reject emptyValue/deletedValue, with consteval createConstant() for hardcoded UUIDs. Hardens IPC deserialization against sentinel-value UUIDs; prior behavior was a controlled abort, so low severity and not memory corruption.
Structural signals: security_assert (+3.0), null_guard (+2.59), msg_soft (+1.0), area:Source/JavaScriptCore/jit (+2.5)
Commit message
Make WTF::UUID unable to hold an invalid value, so one cannot be sent over IPC
https://bugs.webkit.org/show_bug.cgi?id=324032
Reviewed by Darin Adler.
320928@main privatised UUID's reserved empty and deleted values and made the UInt128
and (uint64_t, uint64_t) constructors assert, but the two std::span constructors
still took arbitrary bytes, so an invalid UUID stayed constructible and could reach
an encoder.
Every constructor that takes raw bits becomes private, behind a fallible
UUID::tryCreate() returning std::nullopt for a wrong size or for either reserved
value, alongside the existing parse() and fromNSUUID(). An asserting constructor
does keep an invalid UUID from existing, but only by killing the process, and
nothing stops a future caller from handing it bytes off the wire. With no producer
of an invalid value left, a bare WTF::UUID on the wire is valid by construction, and
"no UUID" has to be spelled Markable<WTF::UUID> or std::optional<WTF::UUID>. No
encode-time check is added, as with ObjectIdentifier; the decode-time one stays,
since it guards against a compromised or fuzzed peer.
The decoder reaches the (uint64_t, uint64_t) overload with [CreateUsing=tryCreate]
in place of the [Validator], which also retires isValid(uint64_t, uint64_t). Its one
other caller, WebAutomationSession::navigationIDToProtocolString(), returns a null
string instead of crashing, which it could already return. JSC's jscJITNamespace,
the only user of the UInt128 constructor, uses a consteval createConstant(), so a
reserved value there is a build error and there is no runtime path in.
Eight call sites move to tryCreate(). Three read bytes they do not control and
already coped with failure: CloneDeserializer::readFileSystemHandle() and the SQLite
blob reads in SQLiteIDBBackingStore and PushDatabase. Folding their hand-rolled
checks into the factory is a strict improvement, since a size check plus if (!uuid)
rejects only the empty value and lets the deleted one through; PushDatabase's
uuidFromSpan() is now exactly tryCreate() and is deleted. Three call sites were also
narrowing a dynamically sized container to std::span<const uint8_t, 16> unchecked,
which is a release assert under hardened libc++.
WebExtensionMessageSenderParameters::documentIdentifier becomes Markable<WTF::UUID>.
Its { 0 } default member initializer would RELEASE_ASSERT since 320928@main. Nothing
reaches it today, since both construction sites initialize all seven members, but
its only consumer already spelled "absent" as documentIdentifier.isValid(), and the
sibling fields in WebExtensionMessageTargetParameters and WebExtensionFrameParameters
are already Markable. The other bare WTF::UUID members that cross IPC come from
createVersion4() and genuinely are not optional.
A FIDO AAGUID is 16 arbitrary vendor bytes, commonly all-zero, so it is not a UUID
and stops being put into one: CtapAuthenticator::aaguidForDebugging() formats the
bytes with a local aaguidToString(), and checks their size. That also fixes the
string it logs, since the byte-span path memcpys into a UInt128 and so rendered the
AAGUID reversed on a little-endian host: a YubiKey 5, published as
cb69481e-8ff7-4039-93ec-0a2729a154a8, logged as a854a129-270a-ec93-3940-f78f1e4869cb.
WebKitTestRunner's dataToUUID() keeps returning WTF::UUID and RELEASE_ASSERTs, since
its input always comes from WKNotificationCopyCoreIDForTesting().
Test: Tools/TestWebKitAPI/Tests/WTF/UUID.cpp
* Source/JavaScriptCore/jit/ExecutableAllocator.cpp:
* Source/WTF/wtf/UUID.h:
(WTF::UUID::tryCreate):
(WTF::UUID::createConstant):
(WTF::UUID::UUID):
(WTF::UUID::isValid): Deleted.
* Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::getFileSystemHandleRecordsForObjectStoreRecord):
* Source/WebCore/Modules/push-api/PushDatabase.cpp:
(WebCore::makePushRecordFromRow):
(WebCore::PushDatabase::getPushSubscriptionSetRecords):
(WebCore::uuidFromSpan): Deleted.
* Source/WebCore/bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::readFileSystemHandle):
* Source/WebKit/Shared/Extensions/WebExtensionMessageSenderParameters.h:
* Source/WebKit/Shared/Extensions/WebExtensionMessageSenderParameters.serialization.in:
* Source/WebKit/Shared/WTFArgumentCoders.serialization.in:
* Source/WebKit/UIProcess/API/C/WKNotificationManager.cpp:
(WKNotificationManagerProviderDidClickNotification_b):
* Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
(-[WKWebsiteDataStore setProxyConfigurations:]):
* Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::navigationIDToProtocolString):
* Source/WebKit/UIProcess/Notifications/WebNotificationManagerProxy.cpp:
(WebKit::WebNotificationManagerProxy::providerDidCloseNotifications):
* Source/WebKit/UIProcess/WebAuthentication/fido/CtapAuthenticator.cpp:
(WebKit::aaguidToString):
(WebKit::CtapAuthenticator::aaguidForDebugging const):
* Source/WebKit/WebProcess/Extensions/API/Cocoa/WebExtensionAPIRuntimeCocoa.mm:
(WebKit::toWebAPI):
* Source/WebKit/WebProcess/Extensions/API/Cocoa/WebExtensionAPITabsCocoa.mm:
(WebKit::WebExtensionAPITabs::sendMessage):
(WebKit::WebExtensionAPITabs::connect):
* Tools/TestWebKitAPI/Tests/WTF/UUID.cpp:
(TEST(WTF, UUIDTryCreateFromSpan)):
(TEST(WTF, UUIDTryCreateFromHighAndLow)):
* Tools/WebKitTestRunner/DataFunctions.h:
(WTR::dataToUUID):
Canonical link: https://commits.webkit.org/320991@main
Before / after
Loading diff…
On This Page