InspectorDebuggerAgent: guard m_scripts.find() with isValidKey for protocol-supplied scriptId - #386
InspectorDebuggerAgent: guard m_scripts.find() with isValidKey for protocol-supplied scriptId#386robobun wants to merge 1 commit into
Conversation
…otocol-supplied scriptId
m_scripts is an UncheckedKeyHashMap<SourceID, Script>, 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.
|
Warning Review limit reached
Next review available in: 14 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
Comment |
There was a problem hiding this comment.
LGTM — straightforward input-validation guards that follow the existing InspectorDOMAgent::nodeForId pattern.
What was reviewed:
- Confirmed
m_scriptsisUncheckedKeyHashMap<JSC::SourceID, ...>andnoSourceID == 0, so the sentinel-key hazard is real andisValidKeyis the right guard. - Each new branch mirrors the adjacent
== end()handling exactly (including thecontinueProgram()/resumed()pair incontinueToLocation), so no behavioral divergence on the error path. .value_or(0)→.value_or(JSC::noSourceID)is a semantic no-op;getBreakpointLocationsonly needs to guardstartSourceIDbecauseendSourceIDis already required to equal it.
Extended reasoning...
Overview
This PR adds m_scripts.isValidKey(sourceID) guards in five InspectorDebuggerAgent protocol handlers (setBreakpoint, continueToLocation, searchInContent, getScriptSource, getBreakpointLocations) before calling m_scripts.find(sourceID) with a client-supplied scriptId. It also swaps two .value_or(0) for .value_or(JSC::noSourceID) (identical value, clearer intent). Single file, ~20 added lines, purely additive early-returns.
Security risks
None introduced. The change is a hardening fix: m_scripts is an UncheckedKeyHashMap, so looking up the empty/deleted sentinel keys (0 / max) is UB — assert-abort in debug, empty-bucket match and null-sourceProvider deref in release. The new guards reject those keys with the same "Missing script..." error the handler already returns for unknown IDs. The inspector protocol is a privileged debug channel, so this is robustness rather than a security boundary, but it does close a remotely-triggerable crash for anything speaking the protocol.
Level of scrutiny
Low-to-moderate. The diff is small, mechanical, and copies an established WebKit idiom verbatim (InspectorDOMAgent::nodeForId at InspectorDOMAgent.cpp:636). Each guard sits immediately before an existing find() and duplicates the adjacent == end() branch's side effects and error string, so the valid-key path is unchanged and the invalid-key path is indistinguishable from "script not found".
Other factors
- Verified
JSC::noSourceID == 0inDebuggerPrimitives.h, so the.value_orchange is a no-op. getBreakpointLocationsonly guardsstartSourceID;endSourceIDis already constrained to equal it a few lines earlier, so a second guard would be dead code.continueToLocation's new branch replicates thecontinueProgram()+resumed()calls from the existing not-found branch, preserving the resume semantics.- No prior reviews on the PR; the bug-hunting pass found nothing.
Problem
m_scriptsinInspectorDebuggerAgentis anUncheckedKeyHashMap<JSC::SourceID, JSC::Debugger::Script>. With WTF's default integer hash traits, key0is the empty-bucket sentinel andUINT32_MAXis the deleted-bucket sentinel.Several Debugger protocol handlers parse the client-supplied
scriptIdstring withparseIntegerAllowingTrailingJunk<JSC::SourceID>(...).value_or(0)and pass the result straight tom_scripts.find(). When a client sendsscriptId: "0"(or"-1","not-a-number", or an overflow thatvalue_or(0)collapses to zero):ASSERT_ENABLEDbuilds the lookup hitsASSERTION FAILED: isValidKey(*entry)atwtf/HashTable.h:692and aborts.Script.Debugger.getScriptSourcereplies with{"scriptSource": ""}for a script that does not exist;Debugger.setBreakpointthen dereferences the nullsourceProviderand segfaults.Repro (against a
bun --inspectprocess)Fix
Guard each call site that looks up a protocol-supplied
sourceIDinm_scriptswithm_scripts.isValidKey(sourceID), returning the existing "Missing script ..." error for the reserved keys. This follows the same pattern asInspectorDOMAgent::nodeForId.Affected handlers:
setBreakpoint,continueToLocation,searchInContent,getScriptSource,getBreakpointLocations.Branched from
34c01d13391e(Bun's currentWEBKIT_VERSION) so the preview build can be consumed directly. The same change applies cleanly onmain.