diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 60e41ac1cc83..7badc6a17cbf 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -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) } /* 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) { 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; - } - 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, } /* 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; 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 (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; } - 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",