CVE-2019-8460 (published 2019-08-26T20:15Z)

OpenBSD kernel version <= 6.5 can be forced to create long chains of TCP SACK holes that causes very expensive calls to tcp_sack_option() for every incoming SACK packet which can lead to a denial of service.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/openbsd/src
commit_details: repo_url: https://github.com/openbsd/src
author: bluhm
author_date: 2019-07-10 18:45:31+00:00
msg: Received SACK options are managed by a linked list at the TCP socket.
There is a global tunable limit net.inet.tcp.sackholelimit, default
is 32768.  If an attacker manages to attach all these sack holes
to a few TCP connections, the lists may grow long.  Traversing them
might cause higher CPU consumption on the victim machine.  In
practice such a situation is hard to create as the TCP retransmit
and 2*msl timer flush the list periodically.  For additional
protection, enforce a per connection limit of 128 SACK holes in the
list.
reported by Reuven Plevinsky and Tal Vainshtein
discussed with claudio@ and procter@; OK deraadt@
repository: repo_url: https://github.com/openbsd/src
repo_name: openbsd/src
description: Read-only git conversion of OpenBSD's official CVS src repository. Pull requests not accepted - send diffs to the tech@ mailing list.
repo_language: C
owner: openbsd
file_changes: filename: tcp.h
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/*	$OpenBSD: tcp.h,v 1.20 2013/08/12 21:57:16 bluhm Exp $	*/
+/*	$OpenBSD: tcp.h,v 1.21 2019/07/10 18:45:31 bluhm Exp $	*/
 /*	$NetBSD: tcp.h,v 1.8 1995/04/17 05:32:58 cgd Exp $	*/
 
 /*
@@ -102,7 +102,8 @@ struct tcphdr {
 #define	TCPOPT_SACK_HDR   (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_SACK<<8)
 /* Miscellaneous constants */
 #define	MAX_SACK_BLKS	6	/* Max # SACK blocks stored at sender side */
-#define	TCP_MAX_SACK	3	/* MAX # SACKs sent in any segment */
+#define	TCP_MAX_SACK	3	/* Max # SACKs sent in any segment */
+#define	TCP_SACKHOLE_LIMIT 128	/* Max # SACK holes per connection */
 
 #define	TCP_MAXBURST	4	/* Max # packets after leaving Fast Rxmit */
 

programming_language: C
filename: tcp_input.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/*	$OpenBSD: tcp_input.c,v 1.359 2018/09/17 14:07:48 friehm Exp $	*/
+/*	$OpenBSD: tcp_input.c,v 1.360 2019/07/10 18:45:31 bluhm Exp $	*/
 /*	$NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $	*/
 
 /*
@@ -2492,6 +2492,8 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
 				 * ACKs some data in middle of a hole; need to
 				 * split current hole
 				 */
+				if (tp->snd_numholes >= TCP_SACKHOLE_LIMIT)
+					goto done;
 				temp = (struct sackhole *)
 				    pool_get(&sackhl_pool, PR_NOWAIT);
 				if (temp == NULL)
@@ -2519,6 +2521,8 @@ tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
 			 * Need to append new hole at end.
 			 * Last hole is p (and it's not NULL).
 			 */
+			if (tp->snd_numholes >= TCP_SACKHOLE_LIMIT)
+				goto done;
 			temp = (struct sackhole *)
 			    pool_get(&sackhl_pool, PR_NOWAIT);
 			if (temp == NULL)

programming_language: C