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)