Skip to content

Fix potential exit node crash and unbounded LZ4 decompression - #39

Open
RinZ27 wants to merge 1 commit into
p1neappleXpress:mainfrom
RinZ27:fix/rawsocket-bounds-decompress-limit
Open

RinZ27 wants to merge 1 commit into
p1neappleXpress:mainfrom
RinZ27:fix/rawsocket-bounds-decompress-limit

Conversation

@RinZ27

@RinZ27 RinZ27 commented Sep 12, 2026

Copy link
Copy Markdown

While testing the tunnel stability under heavy load, I noticed a scenario where the exit node process crashed unexpectedly due to a slice bounds panic in the raw socket readLoop. The code was calculating ipHeaderLen from the first byte of the IP packet, but if a truncated or malformed packet arrives where this length exceeds the actual bytes received, slicing pktCopy[ipHeaderLen:] panics instantly. Because this loop isn't wrapped in SafeGo, the panic takes down the entire tunnel.

Added a quick bounds check before the slice operation in both Linux and Darwin raw socket endpoints to fix that. If ipHeaderLen + 20 is larger than the packet size, the code just skips it now.

Another issue caught my attention in compressor.go regarding how LZ4 decompression is handled. The current implementation uses an unbounded io.ReadAll on the LZ4 reader, which means a tiny crafted compressed payload could decompress into gigabytes of zeros. That would easily cause an OOM crash on either the client or the exit node, so capping it with io.LimitReader limits the output to a safe 10MB to prevent any decompression bomb issues.

@damnurmum

Copy link
Copy Markdown
Contributor

Can confirm both issues are real - checked against our fork (damnurmum/OpenFlux-Android), which carries compressor.go and the raw-socket endpoints byte-identical to main.

The unbounded LZ4 io.ReadAll in particular is a genuine decompression-bomb vector on both sides of the tunnel (client and exit node both run untrusted-input decompression on whatever the transport hands them), not just an exit-node concern, so the io.LimitReader fix is worth having regardless of the raw-socket panic fix. We'll be applying the same bound on our end either way - happy to see this land here too so it doesn't have to live as an undocumented fork-only patch.

- Add bounds check in rawsocket readLoop/WritePackets to prevent slice bounds panic when IHL field exceeds actual packet length.

- Add io.LimitReader to LZ4 decompression to prevent OOM crash from malicious decompression bomb payload.
@RinZ27
RinZ27 force-pushed the fix/rawsocket-bounds-decompress-limit branch from bd20c0a to a10ef51 Compare September 14, 2026 06:20
@RinZ27

RinZ27 commented Sep 14, 2026

Copy link
Copy Markdown
Author

The Darwin raw socket code got removed upstream anyway, so the fix there is no longer needed. @damnurmum glad to hear the LZ4 limit is useful for your fork as well

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