fix: prevent indefinite hangs during TLS operations (#819)#958
fix: prevent indefinite hangs during TLS operations (#819)#958Gengyscan wants to merge 1 commit intoprojectdiscovery:mainfrom
Conversation
…#819) Root cause: two concurrency bugs in ztls client caused indefinite hangs when scanning large target lists. 1. tlsHandshakeWithTimeout evaluated Handshake() synchronously as a send-expression in the select statement. Go evaluates the send value before entering select, so the timeout branch could never fire. Fix: run Handshake() in a goroutine, use a buffered errChan, and close the TLS connection on timeout to unblock any pending I/O. 2. EnumerateCiphers used context.TODO() which provides no deadline. Fix: create a context.WithTimeout derived from the configured Timeout value (guarded for Timeout==0 to avoid instant expiry). Fixes projectdiscovery#819
Neo - PR Security ReviewNo security issues found Highlights
Hardening Notes
Comment |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThe changes modify TLS handshake timeout handling in ztls.go. Changes
Sequence Diagram(s)sequenceDiagram
participant Caller as EnumerateCiphers
participant TimeoutCtx as Context Manager
participant Goroutine as Handshake Goroutine
participant Channel as Result Channel
participant Conn as TLS Connection
Caller->>TimeoutCtx: Create context with timeout
Caller->>Goroutine: Spawn goroutine
Goroutine->>Conn: Perform TLS handshake
par Handshake Path
Conn-->>Goroutine: Success or Error
Goroutine->>Channel: Send result
and Timeout Path
TimeoutCtx->>TimeoutCtx: Deadline reached
TimeoutCtx->>Conn: Cancel/Close connection
end
Caller->>Channel: Receive result
alt Result received
Caller->>Caller: Process handshake result
else Timeout triggered
Caller->>Caller: Handle timeout error
end
Caller->>TimeoutCtx: Cancel context cleanup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 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 unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Fixes #819 — tlsx hangs indefinitely when scanning large target lists (30k+ hosts).
Root Cause
Two concurrency bugs in the ztls client:
Bug 1:
tlsHandshakeWithTimeoutnever times outGo evaluates the send-expression (
tlsConn.Handshake()) before entering theselectstatement. This means the function blocks on the handshake synchronously, and thectx.Done()branch can never fire. If a remote host is slow or unresponsive, the goroutine hangs forever.Bug 2:
EnumerateCiphersusescontext.TODO()context.TODO()has no deadline, so even iftlsHandshakeWithTimeoutworked correctly, cipher enumeration would never time out.Fix
Fix 1: Run handshake in a goroutine
selectcan race it against the context deadlineerrChanis buffered (capacity 1) so the goroutine won't leak if the timeout fires firsttlsConn.Close()is called to unblock any pendingRead/Writein the handshake goroutineFix 2: Replace
context.TODO()with proper timeoutUses the same
Timeout != 0guard pattern already present inConnectWithOptions(line 118) to avoid creating a context that expires instantly when no timeout is configured.Testing
pkg/tlsx/ztls/ztls.goConnectWithOptionsalready uses the same timeout guard)Summary by CodeRabbit