From 71c8e36d612c008685088941515f2487932197e4 Mon Sep 17 00:00:00 2001 From: robobun Date: Mon, 3 Aug 2026 18:51:56 +0000 Subject: [PATCH] InspectorDebuggerAgent: guard m_scripts.find() with isValidKey for protocol-supplied scriptId m_scripts is an UncheckedKeyHashMap, which under WTF's default integer traits reserves 0 as the empty-bucket key and UINT32_MAX as the deleted-bucket key. The Debugger agent parses the protocol scriptId string with parseIntegerAllowingTrailingJunk and passes the result (or value_or(0) on parse failure) straight to m_scripts.find(). When a client supplies scriptId "0" (or "-1", an unparseable string, or anything else that collapses to 0), the lookup walks the table with the empty key: * ASSERT_ENABLED builds hit ASSERTION FAILED: isValidKey(*entry) at wtf/HashTable.h:692 and SIGABRT. * Release builds match the first empty bucket and return a phantom default-constructed Script. getScriptSource replies with an empty scriptSource for a script that does not exist; setBreakpoint then dereferences a null sourceProvider and SIGSEGVs. Guard each user-controlled m_scripts.find() with m_scripts.isValidKey() so the reserved keys take the same "Missing script" error path as any other unknown id. This mirrors the existing pattern in InspectorDOMAgent::nodeForId. --- .../agents/InspectorDebuggerAgent.cpp | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp index de316c795ab5c..212a81c2b6cc6 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp @@ -617,6 +617,9 @@ Protocol::ErrorStringOr InspectorDebuggerAgent::continueToLocation(Refresumed(); + return makeUnexpected("Missing script for scriptId in given location"_s); + } + auto scriptIterator = m_scripts.find(sourceID); if (scriptIterator == m_scripts.end()) { m_debugger.continueProgram(); @@ -1110,7 +1119,11 @@ Protocol::ErrorStringOr InspectorDebuggerAgent::continueToLocation(Ref>> InspectorDebuggerAgent::searchInContent(const Protocol::Debugger::ScriptId& scriptId, const String& query, std::optional&& caseSensitive, std::optional&& isRegex) { - auto it = m_scripts.find(parseIntegerAllowingTrailingJunk(scriptId).value_or(0)); + auto sourceID = parseIntegerAllowingTrailingJunk(scriptId).value_or(JSC::noSourceID); + if (!m_scripts.isValidKey(sourceID)) + return makeUnexpected("Missing script for given scriptId"_s); + + auto it = m_scripts.find(sourceID); if (it == m_scripts.end()) return makeUnexpected("Missing script for given scriptId"_s); @@ -1119,7 +1132,11 @@ Protocol::ErrorStringOr>> Protocol::ErrorStringOr InspectorDebuggerAgent::getScriptSource(const Protocol::Debugger::ScriptId& scriptId) { - auto it = m_scripts.find(parseIntegerAllowingTrailingJunk(scriptId).value_or(0)); + auto sourceID = parseIntegerAllowingTrailingJunk(scriptId).value_or(JSC::noSourceID); + if (!m_scripts.isValidKey(sourceID)) + return makeUnexpected("Missing script for given scriptId"_s); + + auto it = m_scripts.find(sourceID); if (it == m_scripts.end()) return makeUnexpected("Missing script for given scriptId"_s); @@ -1167,6 +1184,9 @@ Protocol::ErrorStringOr>> Inspec if (startLineNumber == endLineNumber && endColumnNumber < startColumnNumber) return makeUnexpected("Cannot have columnNumber of given end be before columnNumber of given start"_s); + if (!m_scripts.isValidKey(startSourceID)) + return makeUnexpected("Missing script for scriptId in given start"_s); + auto scriptIterator = m_scripts.find(startSourceID); if (scriptIterator == m_scripts.end()) return makeUnexpected("Missing script for scriptId in given start"_s);