[PATCH v2] tcp: Avoid division by zero with small MSS values
Fuzz testing with AFL++ persistent mode found that
tcp_buf_data_from_sock() terminates the process with SIGFPE
(signal 8) from division by zero at:
fill_bufs = DIV_ROUND_UP(wnd_scaled - already_sent, mss);
when MSS is small enough (less than four) to round down to 0
during the bit-shift in MSS_SET(). The termination itself is
clean (not memory corruption or data leakage), but we can
handle this condition more gracefully.
We considered resetting connections with a zero or very low
MSS, but concluded this is not RFC-compliant: RFC 9293,
section 3.1 (MUST-7), states: "TCP implementations MUST be
prepared to handle an illegal option length (e.g., zero); a
suggested procedure is to reset the connection and log the
error cause." However, this applies only to option *lengths*,
not *values* — no standard RFC defines a minimum MSS value.
Section 3.5.2 further states: "A reset must not be sent if
it is not clear that this is the case." Very low MSS values
also have legitimate uses in microcontroller applications
with limited buffers, and a zero MSS could represent a
unidirectional connection.
Rounding a low MSS upward is also not an option: emitting
segments larger than the peer advertised violates the
effective send MSS requirement in RFC 9293, section 3.7.1.
Instead, preserve the actual MSS:
- Adjust MSS_SET() to clamp non-zero values below 4 to 1,
avoiding the round-to-zero in bit-field storage.
- Adjust MSS_GET() to return 1 when tap_mss is 1, so we
never inflate the MSS beyond what the peer advertised.
- When MSS is zero, don't send data:
tcp_buf_data_from_sock() returns early. The peer will
eventually determine the connection is unusable and
reset it.
Signed-off-by: Anshu Kumari
participants (1)
-
Anshu Kumari