fix: address 10 security and correctness issues from code audit#1
Merged
Jayian1890 merged 1 commit intomainfrom Mar 2, 2026
Merged
fix: address 10 security and correctness issues from code audit#1Jayian1890 merged 1 commit intomainfrom
Jayian1890 merged 1 commit intomainfrom
Conversation
- Fix critical bug: USER_PASS auth always disconnected before request phase; authenticated sessions now correctly proceed to CONNECT/BIND/UDP - Fix max_connections TOCTOU race: use atomic_fetch_add+check returned value instead of separate load/add to prevent exceeding the limit - Fix pthread_create failure path: decrement active_connections when the thread cannot be spawned, preventing the counter drifting permanently - Fix server->running: change from volatile bool to _Atomic bool for correct C11 memory-ordering guarantees across worker threads - Fix realloc safety in socks5_add_allow_ip: save result to temp pointer before assigning to avoid losing the original pointer on failure - Fix localtime thread safety: replace localtime() with localtime_r() on POSIX and localtime_s() on Windows to eliminate data races under concurrent sessions - Fix GSSAPI token length parsing: replace type-punned pointer cast (strict-aliasing UB) with memcpy into a uint16_t before ntohs() - Fix nmethods bounds check: clamp to 255 (max SOCKS5 methods per spec) instead of sizeof(buf) which is an unrelated implementation detail - Remove dead plen > 255 check: plen is uint8_t so the comparison is always false; remove to eliminate compiler noise and confusion - Fix UDP relay domain-name path: add else-continue when getaddrinfo result is too large, preventing a sendto() to 0.0.0.0:0 Fixes found via full manual code audit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR addresses 10 bugs and safety issues found during a full manual code audit of
socks5.c. All changes are in a single commit, and the build produces zero warnings (clang -Wall -Wextra). The complete test suite passes (the pre-existingGSSAPI Advertisedfailure withoutHAVE_GSSAPIis unchanged).Fixes
🔴 Critical
1. USER_PASS authentication always disconnected before relay (
goto cleanupbug)The
if (selected_method == SOCKS5_AUTH_USER_PASS)block unconditionally executedgoto cleanup, meaning the proxy was completely non-functional when authentication was enabled — the client never got to send a CONNECT/BIND/UDP request. Fixed so that only a failed authentication jumps to cleanup; successful auth falls through to step 3 (Request).🟠 High
2.
pthread_createfailure did not decrementactive_connectionsactive_connectionswas incremented beforepthread_create. On failure the socket and session were freed, but the counter was never decremented. Over time this would cause the counter to permanently drift upward, eventually blocking all new connections. Addedatomic_fetch_subin the failure path.3.
max_connectionsTOCTOU raceThe previous pattern (
atomic_load→ check →atomic_fetch_add) allowed multiple threads accepting simultaneously to each read a value just below the limit and all proceed, collectively exceedingmax_connections. Fixed by doing theatomic_fetch_addfirst and checking the returned (pre-increment) value, decrementing back if over the limit.4.
server->running—volatile boolinstead of_Atomic boolvolatiledoes not provide any memory-ordering guarantees in C11. Worker threads spinning onwhile (server->running)could observe a staletrueafter another thread calledsocks5_server_stop. Changed to_Atomic bool; existing= true/falseassignments and direct reads are valid atomic operations in C11.5.
localtime()is not thread-safelocaltime()uses an internal static buffer and is not reentrant. Under concurrent connections this is a data race. Replaced withlocaltime_r()on POSIX andlocaltime_s()on Windows using an#ifdef _WIN32guard.🟡 Medium
6.
reallocresult stored directly — pointer lost on failureFixed by storing the result in a temporary pointer and only assigning on success.
7. UDP relay: silent
sendto()to0.0.0.0:0ongetaddrinfooverflowWhen the resolved address was larger than
target_addr, thememcpywas silently skipped butsendto()was still called with an uninitialized/zeroedtarget_addr. Addedelse { freeaddrinfo(res); continue; }to skip the packet cleanly.8. GSSAPI token length — strict-aliasing UB
Fixed with
memcpyinto a properly-typed variable beforentohs().🔵 Low
9.
nmethodsbounds check usedsizeof(buf)instead of 255The SOCKS5 spec limits
nmethodsto 255 (1-byte field). The checknmethods > (int)sizeof(buf)was checking against the unrelated buffer size (512). Fixed to> 255.10. Dead code:
plen > 255always false foruint8_tplenis declareduint8_t, soplen > 255can never be true. Removed the dead check.Remaining issues
Remaining audit findings (timing-safe auth,
system()→execvp(),handle_signalasync-safety,ssize_tportability on Windows, credential logging, etc.) are tracked in #2.