fix(interactsh): serialize InternalEvent access#7322
Conversation
`interactsh.(*Client).processInteractionForRequest` was updating the wrapped event under lock but releasing it before calling `Operators.Execute()`, allowing async interactsh updates to race with matcher expr evaluation on the same `InternalEvent` map, causing fatal concurrent map iteration/write crashes. Hold the event lock while populating interactsh fields and running operators, and use a locked `eventHash()` helper for matched-template cache lookups that access the same event data. Fixes #7319 Signed-off-by: Dwi Siswanto <git@dw1.io>
WalkthroughUpdated interactsh event processing to use a hash wrapper function instead of directly hashing event data, preventing concurrent map iteration issues during template matching. Refactored operator execution error handling to ensure proper unlock sequencing, and added a concurrent event mutation test to validate thread-safety. Changes
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Neo - PR Security ReviewNo security issues found Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/protocols/common/interactsh/interactsh_test.go (1)
55-60: Consider adding a brief comment explaining the synchronization pattern.The
MatchFuncclosure orchestrates the race condition scenario, but the purpose isn't immediately obvious.📝 Suggested documentation improvement
MatchFunc: func(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string) { + // Signal writer goroutine to start mutating while we're in the middle of matching. + // With the fix, the writer will block waiting for the lock that processInteractionForRequest holds. startWriter.Do(func() { close(writerStarted) }) + // Yield to allow writer goroutine to be scheduled (it will block on the lock). runtime.Gosched() return matcher.MatchWords("not-present-in-corpus", data) },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/protocols/common/interactsh/interactsh_test.go` around lines 55 - 60, Add a short comment inside the MatchFunc closure (near startWriter.Do, close(writerStarted), and runtime.Gosched()) that explains the synchronization pattern: that startWriter.Do signals the writer goroutine to begin by closing writerStarted, runtime.Gosched is used to yield the scheduler to increase the likelihood of the race for the test, and matcher.MatchWords("not-present-in-corpus", data) is then evaluated to exercise the race condition; reference the symbols MatchFunc, startWriter, writerStarted, runtime.Gosched, and matcher.MatchWords to make the intent and safety of the ordering explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/protocols/common/interactsh/interactsh_test.go`:
- Around line 55-60: Add a short comment inside the MatchFunc closure (near
startWriter.Do, close(writerStarted), and runtime.Gosched()) that explains the
synchronization pattern: that startWriter.Do signals the writer goroutine to
begin by closing writerStarted, runtime.Gosched is used to yield the scheduler
to increase the likelihood of the race for the test, and
matcher.MatchWords("not-present-in-corpus", data) is then evaluated to exercise
the race condition; reference the symbols MatchFunc, startWriter, writerStarted,
runtime.Gosched, and matcher.MatchWords to make the intent and safety of the
ordering explicit.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: aa46cbb1-277c-46ad-8ac1-18d8f8a3677c
📒 Files selected for processing (2)
pkg/protocols/common/interactsh/interactsh.gopkg/protocols/common/interactsh/interactsh_test.go
Proposed changes
fix(interactsh): serialize
InternalEventaccessinteractsh.(*Client).processInteractionForRequestwas updating the wrapped event under lock but
releasing it before calling
Operators.Execute(),allowing async interactsh updates to race with
matcher expr evaluation on the same
InternalEventmap, causing fatal concurrent map iteration/write
crashes.
Hold the event lock while populating interactsh
fields and running operators, and use a locked
eventHash()helper for matched-template cachelookups that access the same event data.
Fixes #7319
Proof
patch:
dev:
Checklist
Summary by CodeRabbit
Bug Fixes
Tests