← All issues

[5] NetworkProcess null-deref on a BroadcastChannel message with a null name

Severity: Low | Component: WebKit NetworkProcess IPC surface | e85a1ea

Rated Low because the diff fixes a reliably reachable null-StringImpl dereference in the NetworkProcess driven by a forged IPC message; the faulting address carries no attacker-controlled data, so the observable effect is a controlled crash (availability) with no path to memory corruption, and reaching it already requires a compromised WebProcess.

NetworkBroadcastChannelRegistry uses the IPC-supplied channel name as a HashMap<String, ...> key in registerChannel() (via ensure()) and in unregisterChannel() / postMessage() (via find()). A compromised or malformed WebProcess could send a null String for the name; looking up a null String key dereferences a null StringImpl while hashing the key (StringHash::hash() calls key.impl()->hash()), crashing the network process before HashTable::validateKey() ever runs. The fix rejects a null name with a MESSAGE_CHECK in all three endpoints, matching the existing origin validation.

Source/WebKit/NetworkProcess/NetworkBroadcastChannelRegistry.cpp

void NetworkBroadcastChannelRegistry::registerChannel(IPC::Connection& connection, const WebCore::ClientOrigin& origin, const String& name)
{
MESSAGE_CHECK(isValidClientOrigin(origin), connection);
+ MESSAGE_CHECK(!name.isNull(), connection);
 
auto& channelsForOrigin = m_broadcastChannels.ensure(origin, [] { return NameToConnectionIdentifiersMap { }; }).iterator->value;
auto& connectionIdentifiersForName = channelsForOrigin.ensure(name, [] { return Vector<IPC::Connection::UniqueID> { }; }).iterator->value;
...
void NetworkBroadcastChannelRegistry::unregisterChannel(...) {
MESSAGE_CHECK(isValidClientOrigin(origin), connection);
+ MESSAGE_CHECK(!name.isNull(), connection);
...
void NetworkBroadcastChannelRegistry::postMessage(...) {
MESSAGE_CHECK_COMPLETION(isValidClientOrigin(origin), connection, completionHandler());
+ MESSAGE_CHECK_COMPLETION(!name.isNull(), connection, completionHandler());

LayoutTests/ipc/coreipc.js

case 'String':
+ if (argument === null)
+ return {value: null, type: 'String'};

registerChannel() and unregisterChannel() gain MESSAGE_CHECK(!name.isNull(), connection), and postMessage() gains MESSAGE_CHECK_COMPLETION(!name.isNull(), connection, completionHandler()), each placed immediately after the existing isValidClientOrigin(origin) check and before the String name is used as a HashMap key. The remaining diff is collateral: a new layout test driving the bug through the IPC testing API, and a one-line change to coreipc.js's ArgumentSerializer to allow serializing a null value for a String argument.

Missing null-validation of attacker-controlled IPC input before it is used as a hash-map key that dereferences its backing StringImpl during hashing.

BroadcastChannel is a Web API letting same-origin browsing contexts message each other; the NetworkProcess maintains the central registry so messages route across WebProcesses. MESSAGE_CHECK is a WebKit IPC macro that validates an assertion on an incoming message and, on failure, terminates the offending connection rather than continuing. A WTF String wraps a refcounted StringImpl; a null String has a null impl(), and StringHash::hash() computes a key's hash by calling key.impl()->hash(). HashMap insertion/lookup hashes the key, and only later runs HashTable::validateKey(). The IPCTestingAPI is a test-only facility that lets a layout test synthesize raw IPC messages to a target process, used here to reproduce a message a compromised WebProcess could send.

This is a null pointer dereference from unvalidated IPC input. Before the fix, NetworkBroadcastChannelRegistry trusted the IPC-supplied channel name and used it directly as a HashMap<String, ...> key without validating it was non-null. The endpoints validated the ClientOrigin via isValidClientOrigin but applied no equivalent check to name. When a null String is used as a key, the hash table must compute the key's hash before it can reach HashTable::validateKey(): StringHash::hash() calls key.impl()->hash(), and for a null String impl() returns nullptr, dereferencing a null StringImpl.

🔒

Where exactly does the null-name crash occur, and why does the hash table's own validation never get a chance to catch it? The cross-process impact is assessed in depth.

Subscribe to read more

🔒

Several reusable audit directions for IPC-keyed map handlers across the NetworkProcess, with concrete grep targets for finding sibling-field validation gaps.

Subscribe to read more