Module Name:    src
Committed By:   martin
Date:           Sun Oct 26 09:48:18 UTC 2014

Modified Files:
        src/sys/netinet [netbsd-7]: tcp_output.c

Log Message:
Pull up following revision(s) (requested by christos in ticket #157):
        sys/netinet/tcp_output.c: revision 1.178
Avoid stack overflow when SACK and TCP_SIGNATURE are both present. Thanks
to Jonathan Looney for pointing this out.


To generate a diff of this commit:
cvs rdiff -u -r1.176.2.1 -r1.176.2.2 src/sys/netinet/tcp_output.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/tcp_output.c
diff -u src/sys/netinet/tcp_output.c:1.176.2.1 src/sys/netinet/tcp_output.c:1.176.2.2
--- src/sys/netinet/tcp_output.c:1.176.2.1	Fri Oct 24 07:28:14 2014
+++ src/sys/netinet/tcp_output.c	Sun Oct 26 09:48:18 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_output.c,v 1.176.2.1 2014/10/24 07:28:14 martin Exp $	*/
+/*	$NetBSD: tcp_output.c,v 1.176.2.2 2014/10/26 09:48:18 martin Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -135,7 +135,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.176.2.1 2014/10/24 07:28:14 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_output.c,v 1.176.2.2 2014/10/26 09:48:18 martin Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -557,6 +557,7 @@ tcp_output(struct tcpcb *tp)
 #endif
 	struct tcphdr *th;
 	u_char opt[MAX_TCPOPTLEN];
+#define OPT_FITS(more)	((optlen + (more)) < sizeof(opt))
 	unsigned optlen, hdrlen, packetlen;
 	unsigned int sack_numblks;
 	int idle, sendalot, txsegsize, rxsegsize;
@@ -1123,7 +1124,7 @@ send:
 		tp->snd_nxt = tp->iss;
 		tp->t_ourmss = tcp_mss_to_advertise(synrt != NULL ?
 						    synrt->rt_ifp : NULL, af);
-		if ((tp->t_flags & TF_NOOPT) == 0) {
+		if ((tp->t_flags & TF_NOOPT) == 0 && OPT_FITS(4)) {
 			opt[0] = TCPOPT_MAXSEG;
 			opt[1] = 4;
 			opt[2] = (tp->t_ourmss >> 8) & 0xff;
@@ -1132,7 +1133,8 @@ send:
 
 			if ((tp->t_flags & TF_REQ_SCALE) &&
 			    ((flags & TH_ACK) == 0 ||
-			    (tp->t_flags & TF_RCVD_SCALE))) {
+			    (tp->t_flags & TF_RCVD_SCALE)) &&
+			    OPT_FITS(4)) {
 				*((u_int32_t *) (opt + optlen)) = htonl(
 					TCPOPT_NOP << 24 |
 					TCPOPT_WINDOW << 16 |
@@ -1140,7 +1142,7 @@ send:
 					tp->request_r_scale);
 				optlen += 4;
 			}
-			if (tcp_do_sack) {
+			if (tcp_do_sack && OPT_FITS(4)) {
 				u_int8_t *cp = (u_int8_t *)(opt + optlen);
 
 				cp[0] = TCPOPT_SACK_PERMITTED;
@@ -1160,7 +1162,7 @@ send:
 	if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
 	     (flags & TH_RST) == 0 &&
 	    ((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
-	     (tp->t_flags & TF_RCVD_TSTMP))) {
+	     (tp->t_flags & TF_RCVD_TSTMP)) && OPT_FITS(TCPOLEN_TSTAMP_APPA)) {
 		u_int32_t *lp = (u_int32_t *)(opt + optlen);
 
 		/* Form timestamp option as shown in appendix A of RFC 1323. */
@@ -1184,30 +1186,33 @@ send:
 		struct ipqent *tiqe;
 
 		sack_len = sack_numblks * 8 + 2;
-		bp[0] = TCPOPT_NOP;
-		bp[1] = TCPOPT_NOP;
-		bp[2] = TCPOPT_SACK;
-		bp[3] = sack_len;
-		if ((tp->rcv_sack_flags & TCPSACK_HAVED) != 0) {
-			sack_numblks--;
-			*lp++ = htonl(tp->rcv_dsack_block.left);
-			*lp++ = htonl(tp->rcv_dsack_block.right);
-			tp->rcv_sack_flags &= ~TCPSACK_HAVED;
-		}
-		for (tiqe = TAILQ_FIRST(&tp->timeq);
-		    sack_numblks > 0; tiqe = TAILQ_NEXT(tiqe, ipqe_timeq)) {
-			KASSERT(tiqe != NULL);
-			sack_numblks--;
-			*lp++ = htonl(tiqe->ipqe_seq);
-			*lp++ = htonl(tiqe->ipqe_seq + tiqe->ipqe_len +
-			    ((tiqe->ipqe_flags & TH_FIN) != 0 ? 1 : 0));
+		if (OPT_FITS(sack_len + 2)) {
+			bp[0] = TCPOPT_NOP;
+			bp[1] = TCPOPT_NOP;
+			bp[2] = TCPOPT_SACK;
+			bp[3] = sack_len;
+			if ((tp->rcv_sack_flags & TCPSACK_HAVED) != 0) {
+				sack_numblks--;
+				*lp++ = htonl(tp->rcv_dsack_block.left);
+				*lp++ = htonl(tp->rcv_dsack_block.right);
+				tp->rcv_sack_flags &= ~TCPSACK_HAVED;
+			}
+			for (tiqe = TAILQ_FIRST(&tp->timeq);
+			    sack_numblks > 0;
+			    tiqe = TAILQ_NEXT(tiqe, ipqe_timeq)) {
+				KASSERT(tiqe != NULL);
+				sack_numblks--;
+				*lp++ = htonl(tiqe->ipqe_seq);
+				*lp++ = htonl(tiqe->ipqe_seq + tiqe->ipqe_len +
+				    ((tiqe->ipqe_flags & TH_FIN) != 0 ? 1 : 0));
+			}
+			optlen += sack_len + 2;
 		}
-		optlen += sack_len + 2;
 	}
 	TCP_REASS_UNLOCK(tp);
 
 #ifdef TCP_SIGNATURE
-	if (tp->t_flags & TF_SIGNATURE) {
+	if ((tp->t_flags & TF_SIGNATURE) && OPT_FITS(TCPOLEN_SIGNATURE + 2)) {
 		u_char *bp;
 		/*
 		 * Initialize TCP-MD5 option (RFC2385)

Reply via email to