DF-2597 / fix.diff
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -777,11 +777,20 @@ tcp_sack_fill_report(tp, opt, &optlen); #ifdef TCP_SIGNATURE - if (tp->t_flags & TF_SIGNATURE) { + if ((tp->t_flags & TF_SIGNATURE) && + optlen + TCPOLEN_SIGNATURE + 2 <= TCP_MAXOLEN) { int i; u_char *bp; /* - * Initialize TCP-MD5 option (RFC2385) + * Initialize TCP-MD5 option (RFC 2385). + * + * Bound-check the 40-byte opt[] stack buffer before the + * 18-byte signature option + 2-byte NOP/EOL terminator, + * which would otherwise overrun opt[] when combined with + * MSS/window-scale/SACK-permitted/timestamp/SACK options. + * If there is no room, the segment is sent without the + * signature and will be rejected by an MD5 peer (graceful + * degradation) instead of smashing the kernel stack. */ bp = (u_char *)opt + optlen; *bp++ = TCPOPT_SIGNATURE; @@ -796,6 +805,13 @@ *bp++ = TCPOPT_NOP; *bp++ = TCPOPT_EOL; optlen += 2; + } else if (tp->t_flags & TF_SIGNATURE) { + /* + * No room for the signature in opt[]: leave TF_SIGNATURE + * set but do not append the option (sigoff stays 0); the + * segment will fail MD5 verification on the peer rather + * than overrun the kernel stack. + */ } #endif /* TCP_SIGNATURE */ KASSERT(optlen <= TCP_MAXOLEN, ("too many TCP options")); |