File Quagga-CVE-2023-38802-bgpd-withdraw.bsc1213284.patch of Package quagga.36746
From ab91e2aa78ce8464d01a57aebbc2dc5afc8cf119 Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.com>
Date: Wed, 13 Sep 2023 12:30:52 +0200
Subject: [PATCH 1/4] bgpd: treat-as-withdraw for malformed attributes
Upsteam: no
References: CVE-2023-38802,bsc#1213284
Backported frr commit 4ba5a9c55f761e0c32d45050014b68e431d8b254
from https://github.com/FRRouting/frr/pull/5744:
```
Author: Donatas Abraitis <donatas.abraitis@gmail.com>
Date: Wed Jan 29 15:09:37 2020 +0200
bgpd: Update some attributes how they are handled if malformed
According to https://tools.ietf.org/html/rfc7606 some of the attributes
MUST be handled as "treat-as-withdraw" approach.
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
```
Signed-off-by: Marius Tomaschewski <mt@suse.com>
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 43955125..1eb5bc5d 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -918,7 +918,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
return BGP_ATTR_PARSE_PROCEED;
/* Core attributes, particularly ones which may influence route
- * selection, should always cause session resets
+ * selection, should be treat-as-withdraw.
*/
case BGP_ATTR_ORIGIN:
case BGP_ATTR_AS_PATH:
@@ -926,11 +926,12 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
case BGP_ATTR_MULTI_EXIT_DISC:
case BGP_ATTR_LOCAL_PREF:
case BGP_ATTR_COMMUNITIES:
+ case BGP_ATTR_EXT_COMMUNITIES:
case BGP_ATTR_ORIGINATOR_ID:
case BGP_ATTR_CLUSTER_LIST:
+ return BGP_ATTR_PARSE_WITHDRAW;
case BGP_ATTR_MP_REACH_NLRI:
case BGP_ATTR_MP_UNREACH_NLRI:
- case BGP_ATTR_EXT_COMMUNITIES:
bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
notify_datap, length);
return BGP_ATTR_PARSE_ERROR;
@@ -1169,23 +1170,19 @@ bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
(peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
{
zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return BGP_ATTR_PARSE_ERROR;
+ return BGP_ATTR_PARSE_WITHDRAW;
}
/* First AS check for EBGP. */
if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
{
if (peer->sort == BGP_PEER_EBGP
- && ! aspath_firstas_check (attr->aspath, peer->as))
- {
- zlog (peer->log, LOG_ERR,
- "%s incorrect first AS (must be %u)", peer->host, peer->as);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return BGP_ATTR_PARSE_ERROR;
- }
+ && ! aspath_firstas_check (attr->aspath, peer->as))
+ {
+ zlog (peer->log, LOG_ERR,
+ "%s incorrect first AS (must be %u)", peer->host, peer->as);
+ return BGP_ATTR_PARSE_WITHDRAW;
+ }
}
/* local-as prepend */
@@ -1309,8 +1306,12 @@ bgp_attr_local_pref (struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- /* Length check. */
- if (length != 4)
+ /* if received from an internal neighbor, it SHALL be considered
+ * malformed if its length is not equal to 4. If malformed, the
+ * UPDATE message SHALL be handled using the approach of "treat-as-
+ * withdraw".
+ */
+ if (peer->sort == BGP_PEER_IBGP && length != 4)
{
zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
length);
@@ -1372,7 +1373,8 @@ bgp_attr_aggregator (struct bgp_attr_parser_args *args)
struct attr_extra *attre = bgp_attr_extra_get (attr);
/* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
- if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
+ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)
+ && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV))
wantedlen = 8;
if (length != wantedlen)
@@ -1551,6 +1553,9 @@ bgp_attr_community (struct bgp_attr_parser_args *args)
/* XXX: fix community_parse to use stream API and remove this */
stream_forward_getp (peer->ibuf, length);
+ /* The Community attribute SHALL be considered malformed if its
+ * length is not a non-zero multiple of 4.
+ */
if (!attr->community)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
@@ -1569,7 +1574,11 @@ bgp_attr_originator_id (struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- /* Length check. */
+ /* if received from an internal neighbor, it SHALL be considered
+ * malformed if its length is not equal to 4. If malformed, the
+ * UPDATE message SHALL be handled using the approach of "treat-as-
+ * withdraw".
+ */
if (length != 4)
{
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
@@ -1595,7 +1604,11 @@ bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
- /* Check length. */
+ /* if received from an internal neighbor, it SHALL be considered
+ * malformed if its length is not a non-zero multiple of 4. If
+ * malformed, the UPDATE message SHALL be handled using the approach
+ * of "treat-as-withdraw".
+ */
if (length % 4)
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
@@ -1816,7 +1829,10 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp (peer->ibuf, length);
-
+
+ /* The Extended Community attribute SHALL be considered malformed if
+ * its length is not a non-zero multiple of 8.
+ */
if (!attr->extra->ecommunity)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
@@ -2047,16 +2063,16 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
&& ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
type = BGP_ATTR_LOCAL_PREF;
+ /* If any of the well-known mandatory attributes are not present
+ * in an UPDATE message, then "treat-as-withdraw" MUST be used.
+ */
if (type)
{
zlog (peer->log, LOG_WARNING,
"%s Missing well-known attribute %d / %s",
peer->host, type, LOOKUP (attr_str, type));
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MISS_ATTR,
- &type, 1);
- return BGP_ATTR_PARSE_ERROR;
+
+ return BGP_ATTR_PARSE_WITHDRAW;
}
return BGP_ATTR_PARSE_PROCEED;
}
diff --git a/tests/aspath_test.c b/tests/aspath_test.c
index 5a0899ec..4f752af1 100644
--- a/tests/aspath_test.c
+++ b/tests/aspath_test.c
@@ -637,7 +637,7 @@ static struct aspath_tests {
"4b AS4_PATH w/o AS_PATH",
&test_segments[6],
NULL,
- AS4_DATA, -1,
+ AS4_DATA, -2,
PEER_CAP_AS4_ADV,
{ COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
--
2.35.3
From d286bd5bef266b0b1cde75359d96a447eab1cf0f Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.com>
Date: Wed, 13 Sep 2023 12:30:52 +0200
Subject: [PATCH 2/4] bgpd: treat 0-length cluster_list as withdraw
Upsteam: no
References: CVE-2023-38802,bsc#1213284
Backported frr commit 33ba22c24874b12916c4ea0fc57e9e188ce7c18d
from https://github.com/FRRouting/frr/pull/6167:
```
Author: Quentin Young <qlyoung@cumulusnetworks.com>
Date: Mon Apr 6 12:30:35 2020 -0400
bgpd: treat 0-length cluster_list as withdraw
See source comment...
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
```
Signed-off-by: Marius Tomaschewski <mt@suse.com>
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 1eb5bc5d..e3a7546a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1609,7 +1609,7 @@ bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
* malformed, the UPDATE message SHALL be handled using the approach
* of "treat-as-withdraw".
*/
- if (length % 4)
+ if (length == 0 || length % 4)
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
--
2.35.3
From 8a6dc173b2afa1b8904787b02635a724f098da6b Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.com>
Date: Wed, 13 Sep 2023 12:30:52 +0200
Subject: [PATCH 3/4] bgpd: Treat-as-withdraw if [e]community length is zero
Upsteam: no
References: CVE-2023-38802,bsc#1213284
Backported frr commit 6680b5508c8d37b61910ee141d9696bd3d10315e
from https://github.com/FRRouting/frr/pull/6173:
```
Author: Donatas Abraitis <donatas.abraitis@gmail.com>
Date: Tue Apr 7 10:08:16 2020 +0300
bgpd: Treat-as-withdraw if [el]community length is zero
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
```
Signed-off-by: Marius Tomaschewski <mt@suse.com>
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index e3a7546a..017ac2b6 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1544,7 +1544,8 @@ bgp_attr_community (struct bgp_attr_parser_args *args)
if (length == 0)
{
attr->community = NULL;
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
attr->community =
@@ -1822,7 +1823,8 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
if (attr->extra)
attr->extra->ecommunity = NULL;
/* Empty extcomm doesn't seem to be invalid per se */
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
(bgp_attr_extra_get (attr))->ecommunity =
--
2.35.3
From e35b24f747ffb3491041e31c5a06c14fe21b751e Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.com>
Date: Fri, 15 Sep 2023 10:34:20 +0200
Subject: [PATCH 4/4] bgpd: treat-as-withdraw for tunnel encapsulation
Upsteam: no
References: CVE-2023-38802,bsc#1213284
Backported frr commit bcb6b58d9530173df41d3a3cbc4c600ee0b4b186
from https://github.com/FRRouting/frr/pull/14295 (CVE-2023-38802):
```
bgpd: Use treat-as-withdraw for tunnel encapsulation attribute
Before this path we used session reset method, which is discouraged by rfc7606.
Handle this as rfc requires.
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
```
Signed-off-by: Marius Tomaschewski <mt@suse.com>
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 017ac2b6..fce4b542 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -929,6 +929,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
case BGP_ATTR_EXT_COMMUNITIES:
case BGP_ATTR_ORIGINATOR_ID:
case BGP_ATTR_CLUSTER_LIST:
+ case BGP_ATTR_ENCAP:
return BGP_ATTR_PARSE_WITHDRAW;
case BGP_ATTR_MP_REACH_NLRI:
case BGP_ATTR_MP_UNREACH_NLRI:
@@ -1847,31 +1848,24 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
/* Parse Tunnel Encap attribute in an UPDATE */
static int
-bgp_attr_encap(
- uint8_t type,
- struct peer *peer, /* IN */
- bgp_size_t length, /* IN: attr's length field */
- struct attr *attr, /* IN: caller already allocated */
- u_char flag, /* IN: attr's flags field */
- u_char *startp)
-{
- bgp_size_t total;
+bgp_attr_encap(struct bgp_attr_parser_args *args)
+{
struct attr_extra *attre = NULL;
struct bgp_attr_encap_subtlv *stlv_last = NULL;
uint16_t tunneltype;
-
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ bgp_size_t length = args->length;
+ uint8_t type = args->type;
+ uint8_t flag = args->flags;
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
{
zlog (peer->log, LOG_ERR,
"Tunnel Encap attribute flag isn't optional and transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
if (BGP_ATTR_ENCAP == type) {
@@ -1881,11 +1875,8 @@ bgp_attr_encap(
if (length < 4) {
zlog (peer->log, LOG_ERR,
"Tunnel Encap attribute not long enough to contain outer T,L");
- bgp_notify_send_with_data(peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
tunneltype = stream_getw (BGP_INPUT (peer));
tlv_length = stream_getw (BGP_INPUT (peer));
@@ -1912,11 +1903,8 @@ bgp_attr_encap(
zlog (peer->log, LOG_ERR,
"Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
sublength, length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
/* alloc and copy sub-tlv */
@@ -1953,11 +1941,8 @@ bgp_attr_encap(
/* spurious leftover data */
zlog (peer->log, LOG_ERR,
"Tunnel Encap attribute length is bad: %d leftover octets", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
}
return 0;
@@ -2266,7 +2251,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
ret = bgp_attr_ext_communities (&attr_args);
break;
case BGP_ATTR_ENCAP:
- ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
+ ret = bgp_attr_encap (&attr_args);
break;
default:
ret = bgp_attr_unknown (&attr_args);
--
2.35.3