Skip to content

net_io: pass the fd count, not the array size, to anetTcpServer - #199

Merged
wiedehopf merged 1 commit into
wiedehopf:devfrom
enricolorenzoni59:fix/netfds-capacity
Nov 2, 2026
Merged

wiedehopf merged 1 commit into
wiedehopf:devfrom
enricolorenzoni59:fix/netfds-capacity

Conversation

@enricolorenzoni59

Copy link
Copy Markdown
Contributor

Summary
serviceListen() declares int newfds[16] and passes sizeof (newfds) to anetTcpServer() as the maximum number of descriptors it may store. That argument is a count, not a size: it is 64. If getaddrinfo() returns more than 16 addresses for which bind() succeeds, the loop in anetTcpServer() writes up to 64 ints into the 16-int stack array.

Impact
--net-bind-address is passed to getaddrinfo() as the node name, so any hostname is accepted (the help text says <ipaddr>, nothing validates it). A name with more than 16 addresses overflows newfds by up to 192 bytes on the stack while the network services are initialized. The overflow stops when bind() fails, so it needs a hostname with many bindable addresses; with one it is a remote-ish configuration crash/corruption, not a theoretical one.

Repro
With an interposer that returns 20 addresses for many.example (DYLD_INTERPOSE on macOS, LD_PRELOAD on Linux; each entry on its own port so every bind() succeeds):

$ DYLD_INSERT_LIBRARIES=manyaddrs.dylib ./readsb --net-only --net --quiet \
    --net-bind-address many.example --net-bi-port 39123
==43596==ERROR: AddressSanitizer: stack-buffer-overflow
WRITE of size 4 at 0x00016f27dd20 thread T2
    #0 anetListen anet.c:385
    #1 anetTcpServer anet.c:381
    #2 serviceListen net_io.c:836
    #3 modesInitNet net_io.c:1095
SUMMARY: AddressSanitizer: stack-buffer-overflow anet.c:385 in anetListen

Fix
Pass the array capacity, sizeof (newfds) / sizeof (newfds[0]), instead of the array size in bytes. The listener then uses at most the first 16 addresses, as intended.

Verification

  • Before: ASan aborts with a stack-buffer-overflow in anetTcpServer() called from serviceListen().
  • After: no sanitizer report, 39123: Beast TCP input port is printed and readsb runs normally (exits cleanly with --auto-exit).
  • Normal builds and plain IP addresses are unaffected: the count only bounds the loop, the first 16 entries are used as before.

serviceListen() declares int newfds[16] and passes sizeof (newfds) as the
maximum number of descriptors anetTcpServer() may store. That is 64, so a
--net-bind-address hostname that resolves to more than 16 addresses makes
the bind loop write up to 64 ints into a 16-int stack array: 192 bytes of
stack corruption.

Pass the array capacity instead. Verified with a getaddrinfo interposer
that returns 20 addresses: ASan reports a stack-buffer-overflow in
anetTcpServer() before the change and nothing after it, the listener still
starts on the first 16 addresses.
@wiedehopf
wiedehopf merged commit 021f186 into wiedehopf:dev Nov 2, 2026
6 checks passed
@wiedehopf

Copy link
Copy Markdown
Owner

And it only allows 16 addresses?!
Let's do 64 it I don't see any drawback haha :)

@enricolorenzoni59

enricolorenzoni59 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor Author

Probably 16 are enough, if not: #200

@wiedehopf

Copy link
Copy Markdown
Owner

already changed a bit of code around, that really doesn't need a PR ;p

@enricolorenzoni59
enricolorenzoni59 deleted the fix/netfds-capacity branch November 2, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants