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
This commit is contained in:
Michael Tuexen 2019-09-29 10:45:13 +00:00
parent 9a92921469
commit 12a43d0d5d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=352868
3 changed files with 22 additions and 4 deletions

View File

@ -941,6 +941,20 @@ tcp_output(struct tcpcb *tp)
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)

View File

@ -13343,12 +13343,14 @@ bbr_output_wtime(struct tcpcb *tp, const struct timeval *tv)
}
} 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;

View File

@ -9200,12 +9200,14 @@ rack_output(struct tcpcb *tp)
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;