From 72088b05d469a6b6a8b9a2b250885246ea0c2acb Mon Sep 17 00:00:00 2001
From: Donald Sharp <sharpd@nvidia.com>
Date: Fri, 30 Sep 2022 08:57:43 -0400
Subject: [PATCH] bgpd: Ensure FRR has enough data to read 2 bytes in
 bgp_open_option_parse

In bgp_open_option_parse the code is checking that the
stream has at least 2 bytes to read ( the opt_type and
the opt_length).  However if BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
is configured then FRR is reading 3 bytes.  Which is not good
since the packet could be badly formateed.  Ensure that
FRR has the appropriate data length to read the data.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
(cherry picked from commit 1117baca3c592877a4d8a13ed6a1d9bd83977487)

CVE: CVE-2022-40318

Upstream-Status: Backport
[https://github.com/FRRouting/frr/commit/72088b05d469a6b6a8b9a2b250885246ea0c2acb]

Signed-off-by: Jonas Gorski <jonas.gorski@bisdn.de>
---
 bgpd/bgp_open.c | 35 ++++++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index fe4c24a8c979..de550d2ac607 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1209,19 +1209,40 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
 		uint8_t opt_type;
 		uint16_t opt_length;
 
-		/* Must have at least an OPEN option header */
-		if (STREAM_READABLE(s) < 2) {
+		/*
+		 * Check that we can read the opt_type and fetch it
+		 */
+		if (STREAM_READABLE(s) < 1) {
 			zlog_info("%s Option length error", peer->host);
 			bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
 					BGP_NOTIFY_OPEN_MALFORMED_ATTR);
 			return -1;
 		}
-
-		/* Fetch option type and length. */
 		opt_type = stream_getc(s);
-		opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
-				     ? stream_getw(s)
-				     : stream_getc(s);
+
+		/*
+		 * Check the length of the stream to ensure that
+		 * FRR can properly read the opt_length. Then read it
+		 */
+		if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) {
+			if (STREAM_READABLE(s) < 2) {
+				zlog_info("%s Option length error", peer->host);
+				bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+						BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+				return -1;
+			}
+
+			opt_length = stream_getw(s);
+		} else {
+			if (STREAM_READABLE(s) < 1) {
+				zlog_info("%s Option length error", peer->host);
+				bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+						BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+				return -1;
+			}
+
+			opt_length = stream_getc(s);
+		}
 
 		/* Option length check. */
 		if (STREAM_READABLE(s) < opt_length) {
-- 
2.40.1

