mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-08 14:34:22 +00:00
bgpd: fix bad heap reads in type-2 nlri parsing
Various forms of corrupt packets could trigger reads of garbage heap. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
4adddf0a29
commit
e121d83163
@ -3590,11 +3590,12 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
uint32_t addpath_id)
|
uint32_t addpath_id)
|
||||||
{
|
{
|
||||||
struct prefix_rd prd;
|
struct prefix_rd prd;
|
||||||
struct prefix_evpn p;
|
struct prefix_evpn p = {};
|
||||||
struct bgp_route_evpn evpn;
|
struct bgp_route_evpn evpn = {};
|
||||||
uint8_t ipaddr_len;
|
uint8_t ipaddr_len;
|
||||||
uint8_t macaddr_len;
|
uint8_t macaddr_len;
|
||||||
mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
|
/* holds the VNI(s) as in packet */
|
||||||
|
mpls_label_t label[BGP_MAX_LABELS] = {};
|
||||||
uint32_t num_labels = 0;
|
uint32_t num_labels = 0;
|
||||||
uint32_t eth_tag;
|
uint32_t eth_tag;
|
||||||
int ret;
|
int ret;
|
||||||
@ -3613,60 +3614,61 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&evpn, 0, sizeof(evpn));
|
struct stream *pkt = stream_new(psize);
|
||||||
|
stream_put(pkt, pfx, psize);
|
||||||
|
|
||||||
/* Make prefix_rd */
|
/* Make prefix_rd */
|
||||||
prd.family = AF_UNSPEC;
|
prd.family = AF_UNSPEC;
|
||||||
prd.prefixlen = 64;
|
prd.prefixlen = 64;
|
||||||
memcpy(&prd.val, pfx, 8);
|
|
||||||
pfx += 8;
|
STREAM_GET(&prd.val, pkt, 8);
|
||||||
|
|
||||||
/* Make EVPN prefix. */
|
/* Make EVPN prefix. */
|
||||||
memset(&p, 0, sizeof(struct prefix_evpn));
|
|
||||||
p.family = AF_EVPN;
|
p.family = AF_EVPN;
|
||||||
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
|
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
|
||||||
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
|
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
|
||||||
|
|
||||||
/* Copy Ethernet Seg Identifier */
|
/* Copy Ethernet Seg Identifier */
|
||||||
if (attr) {
|
if (attr) {
|
||||||
memcpy(&attr->esi, pfx, sizeof(esi_t));
|
STREAM_GET(&attr->esi, pkt, sizeof(esi_t));
|
||||||
|
|
||||||
if (bgp_evpn_is_esi_local(&attr->esi))
|
if (bgp_evpn_is_esi_local(&attr->esi))
|
||||||
attr->es_flags |= ATTR_ES_IS_LOCAL;
|
attr->es_flags |= ATTR_ES_IS_LOCAL;
|
||||||
else
|
else
|
||||||
attr->es_flags &= ~ATTR_ES_IS_LOCAL;
|
attr->es_flags &= ~ATTR_ES_IS_LOCAL;
|
||||||
|
} else {
|
||||||
|
STREAM_FORWARD_GETP(pkt, sizeof(esi_t));
|
||||||
}
|
}
|
||||||
pfx += sizeof(esi_t);
|
|
||||||
|
|
||||||
/* Copy Ethernet Tag */
|
/* Copy Ethernet Tag */
|
||||||
memcpy(ð_tag, pfx, 4);
|
STREAM_GET(ð_tag, pkt, 4);
|
||||||
p.prefix.macip_addr.eth_tag = ntohl(eth_tag);
|
p.prefix.macip_addr.eth_tag = ntohl(eth_tag);
|
||||||
pfx += 4;
|
|
||||||
|
|
||||||
/* Get the MAC Addr len */
|
/* Get the MAC Addr len */
|
||||||
macaddr_len = *pfx++;
|
STREAM_GETC(pkt, macaddr_len);
|
||||||
|
|
||||||
/* Get the MAC Addr */
|
/* Get the MAC Addr */
|
||||||
if (macaddr_len == (ETH_ALEN * 8)) {
|
if (macaddr_len == (ETH_ALEN * 8)) {
|
||||||
memcpy(&p.prefix.macip_addr.mac.octet, pfx, ETH_ALEN);
|
STREAM_GET(&p.prefix.macip_addr.mac.octet, pkt, ETH_ALEN);
|
||||||
pfx += ETH_ALEN;
|
|
||||||
} else {
|
} else {
|
||||||
flog_err(
|
flog_err(
|
||||||
EC_BGP_EVPN_ROUTE_INVALID,
|
EC_BGP_EVPN_ROUTE_INVALID,
|
||||||
"%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
|
"%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
|
||||||
peer->bgp->vrf_id, peer->host, macaddr_len);
|
peer->bgp->vrf_id, peer->host, macaddr_len);
|
||||||
return -1;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the IP. */
|
/* Get the IP. */
|
||||||
ipaddr_len = *pfx++;
|
STREAM_GETC(pkt, ipaddr_len);
|
||||||
|
|
||||||
if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN
|
if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN
|
||||||
&& ipaddr_len != IPV6_MAX_BITLEN) {
|
&& ipaddr_len != IPV6_MAX_BITLEN) {
|
||||||
flog_err(
|
flog_err(
|
||||||
EC_BGP_EVPN_ROUTE_INVALID,
|
EC_BGP_EVPN_ROUTE_INVALID,
|
||||||
"%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d",
|
"%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d",
|
||||||
peer->bgp->vrf_id, peer->host, ipaddr_len);
|
peer->bgp->vrf_id, peer->host, ipaddr_len);
|
||||||
return -1;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipaddr_len) {
|
if (ipaddr_len) {
|
||||||
@ -3674,25 +3676,17 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN)
|
p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN)
|
||||||
? IPADDR_V4
|
? IPADDR_V4
|
||||||
: IPADDR_V6;
|
: IPADDR_V6;
|
||||||
memcpy(&p.prefix.macip_addr.ip.ip.addr, pfx, ipaddr_len);
|
STREAM_GET(&p.prefix.macip_addr.ip.ip.addr, pkt, ipaddr_len);
|
||||||
}
|
}
|
||||||
pfx += ipaddr_len;
|
|
||||||
|
|
||||||
/* Get the VNI(s). Stored as bytes here. */
|
/* Get the VNI(s). Stored as bytes here. */
|
||||||
|
STREAM_GET(&label[0], pkt, BGP_LABEL_BYTES);
|
||||||
num_labels++;
|
num_labels++;
|
||||||
memset(label, 0, sizeof(label));
|
|
||||||
memcpy(&label[0], pfx, BGP_LABEL_BYTES);
|
|
||||||
pfx += BGP_LABEL_BYTES;
|
|
||||||
psize -= (33 + ipaddr_len);
|
|
||||||
/* Do we have a second VNI? */
|
/* Do we have a second VNI? */
|
||||||
if (psize) {
|
if (STREAM_READABLE(pkt)) {
|
||||||
num_labels++;
|
num_labels++;
|
||||||
memcpy(&label[1], pfx, BGP_LABEL_BYTES);
|
STREAM_GET(&label[1], pkt, BGP_LABEL_BYTES);
|
||||||
/*
|
|
||||||
* If in future, we are required to access additional fields,
|
|
||||||
* we MUST increment pfx by BGP_LABEL_BYTES in before reading
|
|
||||||
* the next field
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the route. */
|
/* Process the route. */
|
||||||
@ -3704,6 +3698,16 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
|
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
|
||||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||||
&prd, &label[0], num_labels, &evpn);
|
&prd, &label[0], num_labels, &evpn);
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
stream_failure:
|
||||||
|
flog_err(EC_BGP_EVPN_ROUTE_INVALID,
|
||||||
|
"%u:%s - Rx EVPN Type-2 NLRI - corrupt, discarding",
|
||||||
|
peer->bgp->vrf_id, peer->host);
|
||||||
|
ret = -1;
|
||||||
|
done:
|
||||||
|
stream_free(pkt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user