Author: tuexen
Date: Sun Sep 29 10:45:13 2019
New Revision: 352868
URL: https://svnweb.freebsd.org/changeset/base/352868

Log:
  RFC 7112 requires a host to put the complete IP header chain
  including the TCP header in the first IP packet.
  Enforce this in tcp_output(). In addition make sure that at least
  one byte payload fits in the TCP segement to allow making progress.
  Without this check, a kernel with INVARIANTS will panic.
  This issue was found by running an instance of syzkaller.
  
  Reviewed by:          jtl@
  MFC after:            3 days
  Sponsored by:         Netflix, Inc.
  Differential Revision:        https://reviews.freebsd.org/D21665

Modified:
  head/sys/netinet/tcp_output.c
  head/sys/netinet/tcp_stacks/bbr.c
  head/sys/netinet/tcp_stacks/rack.c

Modified: head/sys/netinet/tcp_output.c
==============================================================================
--- head/sys/netinet/tcp_output.c       Sun Sep 29 06:12:51 2019        
(r352867)
+++ head/sys/netinet/tcp_output.c       Sun Sep 29 10:45:13 2019        
(r352868)
@@ -941,6 +941,20 @@ send:
                        if (tp->t_flags & TF_NEEDFIN)
                                sendalot = 1;
                } else {
+                       if (optlen + ipoptlen >= tp->t_maxseg) {
+                               /*
+                                * Since we don't have enough space to put
+                                * the IP header chain and the TCP header in
+                                * one packet as required by RFC 7112, don't
+                                * send it. Also ensure that at least one
+                                * byte of the payload can be put into the
+                                * TCP segment.
+                                */
+                               SOCKBUF_UNLOCK(&so->so_snd);
+                               error = EMSGSIZE;
+                               sack_rxmit = 0;
+                               goto out;
+                       }
                        len = tp->t_maxseg - optlen - ipoptlen;
                        sendalot = 1;
                        if (dont_sendalot)

Modified: head/sys/netinet/tcp_stacks/bbr.c
==============================================================================
--- head/sys/netinet/tcp_stacks/bbr.c   Sun Sep 29 06:12:51 2019        
(r352867)
+++ head/sys/netinet/tcp_stacks/bbr.c   Sun Sep 29 10:45:13 2019        
(r352868)
@@ -13343,12 +13343,14 @@ send:
                        }
                } else {
                        /* Not doing TSO */
-                       if (optlen + ipoptlen > tp->t_maxseg) {
+                       if (optlen + ipoptlen >= tp->t_maxseg) {
                                /*
                                 * Since we don't have enough space to put
                                 * the IP header chain and the TCP header in
                                 * one packet as required by RFC 7112, don't
-                                * send it.
+                                * send it. Also ensure that at least one
+                                * byte of the payload can be put into the
+                                * TCP segment.
                                 */
                                SOCKBUF_UNLOCK(&so->so_snd);
                                error = EMSGSIZE;

Modified: head/sys/netinet/tcp_stacks/rack.c
==============================================================================
--- head/sys/netinet/tcp_stacks/rack.c  Sun Sep 29 06:12:51 2019        
(r352867)
+++ head/sys/netinet/tcp_stacks/rack.c  Sun Sep 29 10:45:13 2019        
(r352868)
@@ -9200,12 +9200,14 @@ send:
                                sendalot = 1;
 
                } else {
-                       if (optlen + ipoptlen > tp->t_maxseg) {
+                       if (optlen + ipoptlen >= tp->t_maxseg) {
                                /*
                                 * Since we don't have enough space to put
                                 * the IP header chain and the TCP header in
                                 * one packet as required by RFC 7112, don't
-                                * send it.
+                                * send it. Also ensure that at least one
+                                * byte of the payload can be put into the
+                                * TCP segment.
                                 */
                                SOCKBUF_UNLOCK(&so->so_snd);
                                error = EMSGSIZE;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to