DragonFlyBSD Kernel Audit
DF-2597 / fix.diff
← back to finding ↓ download raw
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"));