Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec839218 authored by Eric Dumazet's avatar Eric Dumazet Committed by Greg Kroah-Hartman
Browse files

tcp: tcp_fragment() should apply sane memory limits



commit f070ef2ac66716357066b683fb0baf55f8191a2e upstream.

Jonathan Looney reported that a malicious peer can force a sender
to fragment its retransmit queue into tiny skbs, inflating memory
usage and/or overflow 32bit counters.

TCP allows an application to queue up to sk_sndbuf bytes,
so we need to give some allowance for non malicious splitting
of retransmit queue.

A new SNMP counter is added to monitor how many times TCP
did not allow to split an skb if the allowance was exceeded.

Note that this counter might increase in the case applications
use SO_SNDBUF socket option to lower sk_sndbuf.

CVE-2019-11478 : tcp_fragment, prevent fragmenting a packet when the
	socket is already using more than half the allowed space

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarJonathan Looney <jtl@netflix.com>
Acked-by: default avatarNeal Cardwell <ncardwell@google.com>
Acked-by: default avatarYuchung Cheng <ycheng@google.com>
Reviewed-by: default avatarTyler Hicks <tyhicks@canonical.com>
Cc: Bruce Curtis <brucec@netflix.com>
Cc: Jonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c09be314
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -282,6 +282,7 @@ enum
	LINUX_MIB_TCPACKCOMPRESSED,		/* TCPAckCompressed */
	LINUX_MIB_TCPACKCOMPRESSED,		/* TCPAckCompressed */
	LINUX_MIB_TCPZEROWINDOWDROP,		/* TCPZeroWindowDrop */
	LINUX_MIB_TCPZEROWINDOWDROP,		/* TCPZeroWindowDrop */
	LINUX_MIB_TCPRCVQDROP,			/* TCPRcvQDrop */
	LINUX_MIB_TCPRCVQDROP,			/* TCPRcvQDrop */
	LINUX_MIB_TCPWQUEUETOOBIG,		/* TCPWqueueTooBig */
	__LINUX_MIB_MAX
	__LINUX_MIB_MAX
};
};


+1 −0
Original line number Original line Diff line number Diff line
@@ -290,6 +290,7 @@ static const struct snmp_mib snmp4_net_list[] = {
	SNMP_MIB_ITEM("TCPAckCompressed", LINUX_MIB_TCPACKCOMPRESSED),
	SNMP_MIB_ITEM("TCPAckCompressed", LINUX_MIB_TCPACKCOMPRESSED),
	SNMP_MIB_ITEM("TCPZeroWindowDrop", LINUX_MIB_TCPZEROWINDOWDROP),
	SNMP_MIB_ITEM("TCPZeroWindowDrop", LINUX_MIB_TCPZEROWINDOWDROP),
	SNMP_MIB_ITEM("TCPRcvQDrop", LINUX_MIB_TCPRCVQDROP),
	SNMP_MIB_ITEM("TCPRcvQDrop", LINUX_MIB_TCPRCVQDROP),
	SNMP_MIB_ITEM("TCPWqueueTooBig", LINUX_MIB_TCPWQUEUETOOBIG),
	SNMP_MIB_SENTINEL
	SNMP_MIB_SENTINEL
};
};


+5 −0
Original line number Original line Diff line number Diff line
@@ -1299,6 +1299,11 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
	if (nsize < 0)
	if (nsize < 0)
		nsize = 0;
		nsize = 0;


	if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf)) {
		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPWQUEUETOOBIG);
		return -ENOMEM;
	}

	if (skb_unclone(skb, gfp))
	if (skb_unclone(skb, gfp))
		return -ENOMEM;
		return -ENOMEM;