diff --git a/net-misc/frr/files/frr-9.0-bug-913242.patch b/net-misc/frr/files/frr-9.0-bug-913242.patch index 4005d81..409e49f 100644 --- a/net-misc/frr/files/frr-9.0-bug-913242.patch +++ b/net-misc/frr/files/frr-9.0-bug-913242.patch @@ -1,113 +1,173 @@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c -index dcf0f4d47cfb..8c53191d680f 100644 +index 60e41ac1cc83..7badc6a17cbf 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c -@@ -1405,6 +1405,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, - case BGP_ATTR_LARGE_COMMUNITIES: - case BGP_ATTR_ORIGINATOR_ID: - case BGP_ATTR_CLUSTER_LIST: -+ case BGP_ATTR_ENCAP: - case BGP_ATTR_OTC: - return BGP_ATTR_PARSE_WITHDRAW; - case BGP_ATTR_MP_REACH_NLRI: -@@ -2635,26 +2636,21 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) +@@ -2388,7 +2388,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, + + mp_update->afi = afi; + mp_update->safi = safi; +- return BGP_ATTR_PARSE_EOR; ++ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_ATTR, 0); + } + + mp_update->afi = afi; +@@ -3349,13 +3349,15 @@ bgp_attr_unknown(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 */ -- uint8_t flag, /* IN: attr's flags field */ -- uint8_t *startp) -+static int bgp_attr_encap(struct bgp_attr_parser_args *args) + /* Well-known attribute check. */ +-static int bgp_attr_check(struct peer *peer, struct attr *attr) ++static int bgp_attr_check(struct peer *peer, struct attr *attr, ++ bgp_size_t length) { -- bgp_size_t total; - uint16_t tunneltype = 0; + uint8_t type = 0; + + /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an + * empty UPDATE. */ +- if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) ++ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag && ++ !length) + return BGP_ATTR_PARSE_PROCEED; + + /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required +@@ -3407,7 +3409,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, + enum bgp_attr_parse_ret ret; + uint8_t flag = 0; + uint8_t type = 0; +- bgp_size_t length; ++ bgp_size_t length = 0; + uint8_t *startp, *endp; + uint8_t *attr_endp; + uint8_t seen[BGP_ATTR_BITMAP_SIZE]; +@@ -3658,10 +3660,6 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, + goto done; + } + +- if (ret == BGP_ATTR_PARSE_EOR) { +- goto done; +- } - -- 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_info( -- "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; -+ zlog_err("Tunnel Encap attribute flag isn't optional and transitive %d", -+ flag); -+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, -+ args->total); + if (ret == BGP_ATTR_PARSE_ERROR) { + flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR, + "%s: Attribute %s, parse error", peer->host, +@@ -3734,7 +3732,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, } - if (BGP_ATTR_ENCAP == type) { -@@ -2662,12 +2658,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ - uint16_t tlv_length; + /* Check all mandatory well-known attributes are present */ +- ret = bgp_attr_check(peer, attr); ++ ret = bgp_attr_check(peer, attr, length); + if (ret < 0) + goto done; - if (length < 4) { -- zlog_info( -+ zlog_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)); -@@ -2699,13 +2694,11 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ +diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h +index 1c7e88a4f9e2..3db0863d3b5a 100644 +--- a/bgpd/bgp_attr.h ++++ b/bgpd/bgp_attr.h +@@ -364,7 +364,6 @@ enum bgp_attr_parse_ret { + /* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR + */ + BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3, +- BGP_ATTR_PARSE_EOR = -4, + }; + + struct bpacket_attr_vec_arr; +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index ec692277b26b..f88e1e5afcbb 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -2053,8 +2053,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) + * Non-MP IPv4/Unicast EoR is a completely empty UPDATE + * and MP EoR should have only an empty MP_UNREACH + */ +- if ((!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) +- || (attr_parse_ret == BGP_ATTR_PARSE_EOR)) { ++ if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) { + afi_t afi = 0; + safi_t safi; + struct graceful_restart_info *gr_info; +@@ -2075,9 +2074,6 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) + && nlris[NLRI_MP_WITHDRAW].length == 0) { + afi = nlris[NLRI_MP_WITHDRAW].afi; + safi = nlris[NLRI_MP_WITHDRAW].safi; +- } else if (attr_parse_ret == BGP_ATTR_PARSE_EOR) { +- afi = nlris[NLRI_MP_UPDATE].afi; +- safi = nlris[NLRI_MP_UPDATE].safi; } - if (sublength > length) { -- zlog_info( -- "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; -+ zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", -+ sublength, length); -+ return bgp_attr_malformed(args, -+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, -+ args->total); - } - - /* alloc and copy sub-tlv */ -@@ -2753,13 +2746,10 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ - - if (length) { - /* spurious leftover data */ -- zlog_info( -- "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; -+ zlog_err("Tunnel Encap attribute length is bad: %d leftover octets", -+ length); -+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, -+ args->total); + if (afi && peer->afc[afi][safi]) { +diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c +index 0dd5463979ad..e7e3c2191a7a 100644 +--- a/bgpd/bgp_open.c ++++ b/bgpd/bgp_open.c +@@ -940,8 +940,18 @@ static int bgp_capability_software_version(struct peer *peer, + return -1; } - return 0; -@@ -3732,8 +3722,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, - case BGP_ATTR_VNC: - #endif - case BGP_ATTR_ENCAP: -- ret = bgp_attr_encap(type, peer, length, attr, flag, -- startp); -+ ret = bgp_attr_encap(&attr_args); - break; - case BGP_ATTR_PREFIX_SID: - ret = bgp_attr_prefix_sid(&attr_args); +- if (len) { ++ if (len > BGP_MAX_SOFT_VERSION) { ++ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, ++ "%s: Received Software Version, but the length is too big, truncating, from peer %s", ++ __func__, peer->host); ++ stream_get(str, s, BGP_MAX_SOFT_VERSION); ++ stream_forward_getp(s, len - BGP_MAX_SOFT_VERSION); ++ len = BGP_MAX_SOFT_VERSION; ++ } else if (len) { + stream_get(str, s, len); ++ } ++ ++ if (len) { + str[len] = '\0'; + + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); +diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c +index 3ecffb99d171..d3a02a3df641 100644 +--- a/bgpd/bgp_attr.c ++++ b/bgpd/bgp_attr.c +@@ -492,6 +492,7 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) + uint8_t *data = pnt; + uint8_t tlv_type; + uint16_t tlv_length; ++ uint8_t *end = data + length; + + if (length < 3) { + zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u", +@@ -500,7 +501,13 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) + } + + while (length) { ++ size_t data_len = end - data; ++ + tlv_type = *data; ++ ++ if (data_len - 1 < 2) ++ return false; ++ + ptr_get_be16(data + 1, &tlv_length); + (void)data; + +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index c852203e5b66..ec692277b26b 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -1976,7 +1976,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) + /* Network Layer Reachability Information. */ + update_len = end - stream_pnt(s); + +- if (update_len) { ++ if (update_len && attribute_len) { + /* Set NLRI portion to structure. */ + nlris[NLRI_UPDATE].afi = AFI_IP; + nlris[NLRI_UPDATE].safi = SAFI_UNICAST; +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index bd17a2eec84e..c852203e5b66 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -2401,7 +2401,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) + * and 7 bytes of ORF Address-filter entry from + * the stream + */ +- if (*p_pnt & ORF_COMMON_PART_REMOVE_ALL) { ++ if (p_pnt < p_end && ++ *p_pnt & ORF_COMMON_PART_REMOVE_ALL) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%pBP rcvd Remove-All pfxlist ORF request",