BudgetScan

Positive Backlog can be truncated in listen(2) on 64-bit platforms

low swesweep-fasthttp · tcplisten/tcplisten.go · (*Config).fdSetup · run #4

Description

A positive cfg.Backlog larger than the platform C int range is passed directly to unix.Listen. On 64-bit targets the syscall can truncate the value, allowing an attacker-controlled Backlog (for example 1<<32) to bypass the backlog <= 0 default check and effectively set a zero or invalid backlog, degrading or failing the listener.

Triage

Not triaged.

Raw scan report for this file

I analyzed the file against the public API threat model: `(*Config).NewListener(network, addr)` is the trust boundary, with caller-controlled `network`, `addr`, and `Config` fields such as `ReusePort`, `DeferAccept`, `FastOpen`, and `Backlog`.

Key flows:

- `addr` and `network` go into `net.ResolveTCPAddr`. The error is checked.
- The resolved IP is copied into fixed-size `unix.SockaddrInet4.Addr` or `unix.SockaddrInet6.Addr` via `copy(dst, src)`. `copy` bounds-checks the destination, and `To4()`/`To16()` either return the correct-sized slice or nil. A nil source only leaves the address zero-filled; it does not overflow the fixed buffers.
- Zone handling calls `net.InterfaceByName`, checks the error, and converts the interface index with `safeIntToUint32`, which rejects negative values and values above `MaxUint32`.
- `fdSetup` configures socket options, binds, and listens. Negative or zero `Backlog` falls back to `soMaxConn()`. Positive `Backlog` is passed to `unix.Listen` without clamping to the platform C `int` range.
- `NewListener` creates the fd, calls `fdSetup`, safely converts fd to `uintptr`, wraps it with `os.NewFile`, converts it with `net.FileListener`, and closes the temporary file/listener on error.

Most of the address-parsing and integer-conversion logic is safe. The notable reachable issues are:

1. A nil `*Config` receiver can cause a panic in `fdSetup` after a socket fd has already been allocated.
2. A positive `Backlog` larger than the platform C `int` range can be truncated in the `listen(2)` syscall on 64-bit systems, allowing an attacker-controlled config value to effectively set an invalid or zero backlog.

Other observations, such as ignored best-effort `Close()` errors in error paths, DNS side effects from caller-supplied hostnames, and platform-dependent dual-stack behavior, are lower-signal robustness concerns rather than clear zero-day vulnerabilities.

```json
[
  {
    "severity": "medium",
    "title": "Nil Config receiver can panic in NewListener",
    "function": "(*Config).NewListener",
    "description": "NewListener can be invoked with a nil *Config receiver. It calls cfg.fdSetup without checking cfg, and fdSetup dereferences cfg.ReusePort. This causes a nil pointer dereference after the socket fd has been allocated; an unrecovered panic crashes the host process, and a recovered panic can leak the fd."
  },
  {
    "severity": "low",
    "title": "Positive Backlog can be truncated in listen(2) on 64-bit platforms",
    "function": "(*Config).fdSetup",
    "description": "A positive cfg.Backlog larger than the platform C int range is passed directly to unix.Listen. On 64-bit targets the syscall can truncate the value, allowing an attacker-controlled Backlog (for example 1<<32) to bypass the backlog <= 0 default check and effectively set a zero or invalid backlog, degrading or failing the listener."
  }
]
```