diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 54ecde1b3222..0665b183ceba 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4922,10 +4922,10 @@ static void bgp_packet_ls_attribute(struct stream *s, struct bgp *bgp, struct at /* Write BGP-LS attribute header (RFC 9552 Section 4) */ attr_start = stream_get_endp(s); - stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LINK_STATE); len_pos = stream_get_endp(s); - stream_putc(s, 0); /* Placeholder for length */ + stream_putw(s, 0); /* Placeholder for extended length */ ret = bgp_ls_encode_attr(s, ls_attr); @@ -4936,9 +4936,13 @@ static void bgp_packet_ls_attribute(struct stream *s, struct bgp *bgp, struct at } /* Update the length field */ - attr_len = stream_get_endp(s) - len_pos - 1; + attr_len = stream_get_endp(s) - len_pos - 2; + if (attr_len > UINT16_MAX) { + stream_set_endp(s, attr_start); + return; + } - stream_putc_at(s, len_pos, attr_len); + stream_putw_at(s, len_pos, attr_len); } void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, diff --git a/bgpd/bgp_ls.c b/bgpd/bgp_ls.c index 7ff82e935a2c..7a384e7eec66 100644 --- a/bgpd/bgp_ls.c +++ b/bgpd/bgp_ls.c @@ -653,28 +653,36 @@ int bgp_ls_withdraw(struct bgp *bgp, struct bgp_ls_nlri *nlri) int bgp_nlri_parse_ls(struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { struct stream *s; - struct bgp_ls_nlri nlri; + struct bgp_ls_nlri *nlri; struct prefix p; struct bgp_ls_nlri *ls_entry; struct bgp_dest *dest; int ret = BGP_NLRI_PARSE_OK; + if (!peer || !peer->bgp || !peer->bgp->ls_info || !packet) + return BGP_NLRI_PARSE_ERROR; + s = stream_new(packet->length); stream_put(s, packet->nlri, packet->length); stream_set_getp(s, 0); while (STREAM_READABLE(s) > 0) { - memset(&nlri, 0, sizeof(nlri)); - ret = bgp_ls_decode_nlri(s, &nlri); + nlri = bgp_ls_nlri_alloc(); + if (!nlri) { + ret = BGP_NLRI_PARSE_ERROR; + goto done; + } + ret = bgp_ls_decode_nlri(s, nlri); if (ret < 0) { + bgp_ls_nlri_free(nlri); flog_warn(EC_BGP_LS_PACKET, "%s [Error] Failed to decode BGP-LS NLRI", peer->host); ret = BGP_NLRI_PARSE_ERROR; goto done; } - ls_entry = bgp_ls_nlri_get(&peer->bgp->ls_info->nlri_hash, peer->bgp, &nlri); + ls_entry = bgp_ls_nlri_get(&peer->bgp->ls_info->nlri_hash, peer->bgp, nlri); memset(&p, 0, sizeof(p)); p.family = AF_UNSPEC; @@ -696,7 +704,9 @@ int bgp_nlri_parse_ls(struct peer *peer, struct attr *attr, struct bgp_nlri *pac if (BGP_DEBUG(linkstate, LINKSTATE)) zlog_debug("%s processed BGP-LS %s NLRI type=%u", peer->host, - attr ? "UPDATE" : "WITHDRAW", nlri.nlri_type); + attr ? "UPDATE" : "WITHDRAW", nlri->nlri_type); + + bgp_ls_nlri_free(nlri); } done: diff --git a/bgpd/bgp_ls_nlri.c b/bgpd/bgp_ls_nlri.c index f618bbeaee5c..9502e4d4e1b7 100644 --- a/bgpd/bgp_ls_nlri.c +++ b/bgpd/bgp_ls_nlri.c @@ -1454,10 +1454,13 @@ void bgp_ls_attr_unintern(struct bgp_ls_attr **pls_attr) * | Type | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * Returns number of bytes written + * Returns number of bytes written, or -1 on error */ static inline int stream_put_tlv_hdr(struct stream *s, uint16_t type, uint16_t length) { + if (STREAM_WRITEABLE(s) < BGP_LS_TLV_HDR_SIZE) + return -1; + stream_putw(s, type); stream_putw(s, length); return BGP_LS_TLV_HDR_SIZE; @@ -1522,10 +1525,14 @@ int bgp_ls_encode_node_descriptor(struct stream *s, const struct bgp_ls_node_des { size_t len_pos, sub_tlv_start; int written = 0; + int ret; if (!s || !desc) return -1; + if (STREAM_WRITEABLE(s) < BGP_LS_TLV_HDR_SIZE) + return -1; + /* Write TLV type and reserve space for length */ stream_putw(s, tlv_type); len_pos = stream_get_endp(s); @@ -1536,28 +1543,52 @@ int bgp_ls_encode_node_descriptor(struct stream *s, const struct bgp_ls_node_des /* AS Number (TLV 512) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_AS_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_AS_NUMBER, BGP_LS_AS_NUMBER_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_AS_NUMBER, BGP_LS_AS_NUMBER_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_AS_NUMBER_SIZE) + return -1; stream_putl(s, desc->asn); written += BGP_LS_AS_NUMBER_SIZE; } /* BGP-LS Identifier (TLV 513) - deprecated but may be present */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_BGP_LS_ID_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_BGP_LS_ID, BGP_LS_BGP_LS_ID_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_BGP_LS_ID, BGP_LS_BGP_LS_ID_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_BGP_LS_ID_SIZE) + return -1; stream_putl(s, desc->bgp_ls_id); written += BGP_LS_BGP_LS_ID_SIZE; } /* OSPF Area ID (TLV 514) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_OSPF_AREA_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_OSPF_AREA_ID, BGP_LS_OSPF_AREA_ID_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_OSPF_AREA_ID, BGP_LS_OSPF_AREA_ID_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_OSPF_AREA_ID_SIZE) + return -1; stream_putl(s, desc->ospf_area_id); written += BGP_LS_OSPF_AREA_ID_SIZE; } /* IGP Router ID (TLV 515) - MANDATORY */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_IGP_ROUTER_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IGP_ROUTER_ID, desc->igp_router_id_len); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IGP_ROUTER_ID, desc->igp_router_id_len); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < desc->igp_router_id_len) + return -1; stream_put(s, desc->igp_router_id, desc->igp_router_id_len); written += desc->igp_router_id_len; } @@ -1593,6 +1624,7 @@ int bgp_ls_encode_node_descriptor(struct stream *s, const struct bgp_ls_node_des int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_descriptor *desc) { int written = 0; + int ret; uint16_t i; if (!s || !desc) @@ -1600,7 +1632,13 @@ int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_des /* Link Local/Remote Identifiers (TLV 258) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_LINK_ID_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_LINK_ID, BGP_LS_LINK_ID_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_LINK_ID, BGP_LS_LINK_ID_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_LINK_ID_SIZE) + return -1; stream_putl(s, desc->link_local_id); stream_putl(s, desc->link_remote_id); written += BGP_LS_LINK_ID_SIZE; @@ -1608,28 +1646,52 @@ int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_des /* IPv4 Interface Address (TLV 259) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_INTF_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IPV4_INTF_ADDR, BGP_LS_IPV4_ADDR_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IPV4_INTF_ADDR, BGP_LS_IPV4_ADDR_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_IPV4_ADDR_SIZE) + return -1; stream_put_ipv4(s, desc->ipv4_intf_addr.s_addr); written += BGP_LS_IPV4_ADDR_SIZE; } /* IPv4 Neighbor Address (TLV 260) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_NEIGH_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IPV4_NEIGH_ADDR, BGP_LS_IPV4_ADDR_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IPV4_NEIGH_ADDR, BGP_LS_IPV4_ADDR_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_IPV4_ADDR_SIZE) + return -1; stream_put_ipv4(s, desc->ipv4_neigh_addr.s_addr); written += BGP_LS_IPV4_ADDR_SIZE; } /* IPv6 Interface Address (TLV 261) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_INTF_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IPV6_INTF_ADDR, BGP_LS_IPV6_ADDR_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IPV6_INTF_ADDR, BGP_LS_IPV6_ADDR_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_IPV6_ADDR_SIZE) + return -1; stream_put(s, &desc->ipv6_intf_addr, BGP_LS_IPV6_ADDR_SIZE); written += BGP_LS_IPV6_ADDR_SIZE; } /* IPv6 Neighbor Address (TLV 262) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_NEIGH_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IPV6_NEIGH_ADDR, BGP_LS_IPV6_ADDR_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IPV6_NEIGH_ADDR, BGP_LS_IPV6_ADDR_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_IPV6_ADDR_SIZE) + return -1; stream_put(s, &desc->ipv6_neigh_addr, BGP_LS_IPV6_ADDR_SIZE); written += BGP_LS_IPV6_ADDR_SIZE; } @@ -1637,8 +1699,14 @@ int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_des /* Multi-Topology ID (TLV 263) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_MT_ID_BIT) && desc->mt_id_count > 0) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_MT_ID, - desc->mt_id_count * BGP_LS_MT_ID_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_MT_ID, + desc->mt_id_count * BGP_LS_MT_ID_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < (size_t)desc->mt_id_count * BGP_LS_MT_ID_SIZE) + return -1; for (i = 0; i < desc->mt_id_count; i++) stream_putw(s, desc->mt_id[i]); written += desc->mt_id_count * BGP_LS_MT_ID_SIZE; @@ -1646,7 +1714,13 @@ int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_des /* Remote AS Number (TLV 264) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_REMOTE_AS_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_REMOTE_AS_NUMBER, 4); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_REMOTE_AS_NUMBER, 4); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < 4) + return -1; stream_putl(s, desc->remote_asn); written += 4; } @@ -1674,6 +1748,7 @@ int bgp_ls_encode_link_descriptor(struct stream *s, const struct bgp_ls_link_des int bgp_ls_encode_prefix_descriptor(struct stream *s, const struct bgp_ls_prefix_descriptor *desc) { int written = 0; + int ret; uint16_t i; uint8_t prefix_len_bytes; @@ -1683,8 +1758,14 @@ int bgp_ls_encode_prefix_descriptor(struct stream *s, const struct bgp_ls_prefix /* Multi-Topology ID (TLV 263) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_PREFIX_DESC_MT_ID_BIT) && desc->mt_id_count > 0) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_MT_ID, - desc->mt_id_count * BGP_LS_MT_ID_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_MT_ID, + desc->mt_id_count * BGP_LS_MT_ID_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < (size_t)desc->mt_id_count * BGP_LS_MT_ID_SIZE) + return -1; for (i = 0; i < desc->mt_id_count; i++) stream_putw(s, desc->mt_id[i]); written += desc->mt_id_count * BGP_LS_MT_ID_SIZE; @@ -1692,8 +1773,14 @@ int bgp_ls_encode_prefix_descriptor(struct stream *s, const struct bgp_ls_prefix /* OSPF Route Type (TLV 264) */ if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_PREFIX_DESC_OSPF_ROUTE_BIT)) { - written += stream_put_tlv_hdr(s, BGP_LS_TLV_OSPF_ROUTE_TYPE, - BGP_LS_OSPF_ROUTE_TYPE_SIZE); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_OSPF_ROUTE_TYPE, + BGP_LS_OSPF_ROUTE_TYPE_SIZE); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < BGP_LS_OSPF_ROUTE_TYPE_SIZE) + return -1; stream_putc(s, desc->ospf_route_type); written += BGP_LS_OSPF_ROUTE_TYPE_SIZE; } @@ -1701,15 +1788,27 @@ int bgp_ls_encode_prefix_descriptor(struct stream *s, const struct bgp_ls_prefix /* IP Reachability Information (TLV 265) - MANDATORY */ if (desc->prefix.family == AF_INET) { prefix_len_bytes = (desc->prefix.prefixlen + 7) / 8; - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IP_REACH_INFO, - BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IP_REACH_INFO, + BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < (size_t)BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes) + return -1; stream_putc(s, desc->prefix.prefixlen); stream_put(s, &desc->prefix.u.prefix4, prefix_len_bytes); written += BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes; } else if (desc->prefix.family == AF_INET6) { prefix_len_bytes = (desc->prefix.prefixlen + 7) / 8; - written += stream_put_tlv_hdr(s, BGP_LS_TLV_IP_REACH_INFO, - BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes); + ret = stream_put_tlv_hdr(s, BGP_LS_TLV_IP_REACH_INFO, + BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes); + if (ret < 0) + return -1; + written += ret; + + if (STREAM_WRITEABLE(s) < (size_t)BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes) + return -1; stream_putc(s, desc->prefix.prefixlen); stream_put(s, &desc->prefix.u.prefix6, prefix_len_bytes); written += BGP_LS_PREFIX_LEN_SIZE + prefix_len_bytes; @@ -1744,10 +1843,14 @@ int bgp_ls_encode_node_nlri(struct stream *s, const struct bgp_ls_node_nlri *nlr return -1; /* Protocol-ID (1 byte) */ + if (STREAM_WRITEABLE(s) < BGP_LS_PROTOCOL_ID_SIZE) + return -1; stream_putc(s, nlri->protocol_id); written += BGP_LS_PROTOCOL_ID_SIZE; /* Identifier (8 bytes) */ + if (STREAM_WRITEABLE(s) < BGP_LS_IDENTIFIER_SIZE) + return -1; stream_putq(s, nlri->identifier); written += BGP_LS_IDENTIFIER_SIZE; @@ -1790,10 +1893,14 @@ int bgp_ls_encode_link_nlri(struct stream *s, const struct bgp_ls_link_nlri *nlr return -1; /* Protocol-ID (1 byte) */ + if (STREAM_WRITEABLE(s) < BGP_LS_PROTOCOL_ID_SIZE) + return -1; stream_putc(s, nlri->protocol_id); written += BGP_LS_PROTOCOL_ID_SIZE; /* Identifier (8 bytes) */ + if (STREAM_WRITEABLE(s) < BGP_LS_IDENTIFIER_SIZE) + return -1; stream_putq(s, nlri->identifier); written += BGP_LS_IDENTIFIER_SIZE; @@ -1858,10 +1965,14 @@ int bgp_ls_encode_prefix_nlri(struct stream *s, const struct bgp_ls_prefix_nlri return -1; /* Protocol-ID (1 byte) */ + if (STREAM_WRITEABLE(s) < BGP_LS_PROTOCOL_ID_SIZE) + return -1; stream_putc(s, nlri->protocol_id); written += BGP_LS_PROTOCOL_ID_SIZE; /* Identifier (8 bytes) */ + if (STREAM_WRITEABLE(s) < BGP_LS_IDENTIFIER_SIZE) + return -1; stream_putq(s, nlri->identifier); written += BGP_LS_IDENTIFIER_SIZE; @@ -1917,10 +2028,14 @@ int bgp_ls_encode_nlri(struct stream *s, const struct bgp_ls_nlri *nlri) return -1; /* NLRI Type (2 bytes) */ + if (STREAM_WRITEABLE(s) < BGP_LS_NLRI_TYPE_SIZE) + return -1; stream_putw(s, nlri->nlri_type); written += BGP_LS_NLRI_TYPE_SIZE; /* Reserve space for NLRI Length */ + if (STREAM_WRITEABLE(s) < BGP_LS_NLRI_LENGTH_SIZE) + return -1; len_pos = stream_get_endp(s); stream_putw(s, 0); /* Placeholder */ written += BGP_LS_NLRI_LENGTH_SIZE; @@ -2167,6 +2282,9 @@ int bgp_ls_encode_attr(struct stream *s, const struct bgp_ls_attr *attr) if (stream_put_tlv_hdr(s, BGP_LS_ATTR_MIN_MAX_UNIDIRECTIONAL_LINK_DELAY, 8) < 0) return -1; + + if (STREAM_WRITEABLE(s) < 8) + return -1; stream_put(s, &min_delay_be, 4); stream_put(s, &max_delay_be, 4); } @@ -2366,6 +2484,11 @@ int bgp_ls_decode_node_descriptor(struct stream *s, struct bgp_ls_node_descripto switch (sub_type) { case BGP_LS_TLV_AS_NUMBER: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_AS_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate AS Number TLV in node descriptor"); + return -1; + } if (sub_len != BGP_LS_AS_NUMBER_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid AS Number TLV length %u (expected %u)", @@ -2377,6 +2500,11 @@ int bgp_ls_decode_node_descriptor(struct stream *s, struct bgp_ls_node_descripto break; case BGP_LS_TLV_BGP_LS_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_BGP_LS_ID_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate BGP-LS ID TLV in node descriptor"); + return -1; + } if (sub_len != BGP_LS_BGP_LS_ID_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid BGP-LS ID TLV length %u (expected %u)", @@ -2388,6 +2516,11 @@ int bgp_ls_decode_node_descriptor(struct stream *s, struct bgp_ls_node_descripto break; case BGP_LS_TLV_OSPF_AREA_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_OSPF_AREA_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate OSPF Area ID TLV in node descriptor"); + return -1; + } if (sub_len != BGP_LS_OSPF_AREA_ID_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid OSPF Area ID TLV length %u (expected %u)", @@ -2399,6 +2532,11 @@ int bgp_ls_decode_node_descriptor(struct stream *s, struct bgp_ls_node_descripto break; case BGP_LS_TLV_IGP_ROUTER_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_NODE_DESC_IGP_ROUTER_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IGP Router-ID TLV in node descriptor"); + return -1; + } /* Variable length: 4 to 16 bytes */ if (sub_len < BGP_LS_IGP_ROUTER_ID_MIN_SIZE || sub_len > BGP_LS_IGP_ROUTER_ID_MAX_SIZE) { @@ -2478,15 +2616,20 @@ int bgp_ls_decode_link_descriptor(struct stream *s, struct bgp_ls_link_descripto /* Parse TLVs */ while (stream_get_getp(s) < end_pos) { if (stream_get_tlv_hdr(s, &tlv_type, &tlv_len) < 0) - return -1; + goto error; switch (tlv_type) { case BGP_LS_TLV_LINK_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_LINK_ID_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate Link ID TLV in link descriptor"); + goto error; + } if (tlv_len != BGP_LS_LINK_ID_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid Link ID TLV length %u (expected %u)", tlv_len, BGP_LS_LINK_ID_SIZE); - return -1; + goto error; } desc->link_local_id = stream_getl(s); desc->link_remote_id = stream_getl(s); @@ -2494,55 +2637,80 @@ int bgp_ls_decode_link_descriptor(struct stream *s, struct bgp_ls_link_descripto break; case BGP_LS_TLV_IPV4_INTF_ADDR: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_INTF_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IPv4 Interface Address TLV in link descriptor"); + goto error; + } if (tlv_len != BGP_LS_IPV4_ADDR_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv4 Interface Address TLV length %u", tlv_len); - return -1; + goto error; } stream_get(&desc->ipv4_intf_addr.s_addr, s, BGP_LS_IPV4_ADDR_SIZE); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_INTF_BIT); break; case BGP_LS_TLV_IPV4_NEIGH_ADDR: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_NEIGH_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IPv4 Neighbor Address TLV in link descriptor"); + goto error; + } if (tlv_len != BGP_LS_IPV4_ADDR_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv4 Neighbor Address TLV length %u", tlv_len); - return -1; + goto error; } stream_get(&desc->ipv4_neigh_addr.s_addr, s, BGP_LS_IPV4_ADDR_SIZE); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_LINK_DESC_IPV4_NEIGH_BIT); break; case BGP_LS_TLV_IPV6_INTF_ADDR: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_INTF_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IPv6 Interface Address TLV in link descriptor"); + goto error; + } if (tlv_len != BGP_LS_IPV6_ADDR_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv6 Interface Address TLV length %u", tlv_len); - return -1; + goto error; } stream_get(&desc->ipv6_intf_addr.s6_addr, s, BGP_LS_IPV6_ADDR_SIZE); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_INTF_BIT); break; case BGP_LS_TLV_IPV6_NEIGH_ADDR: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_NEIGH_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IPv6 Neighbor Address TLV in link descriptor"); + goto error; + } if (tlv_len != BGP_LS_IPV6_ADDR_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv6 Neighbor Address TLV length %u", tlv_len); - return -1; + goto error; } stream_get(&desc->ipv6_neigh_addr.s6_addr, s, BGP_LS_IPV6_ADDR_SIZE); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_LINK_DESC_IPV6_NEIGH_BIT); break; case BGP_LS_TLV_MT_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_MT_ID_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate MT-ID TLV in link descriptor"); + goto error; + } /* Variable length: 2*n bytes where n is number of MT-IDs */ if (tlv_len % 2 != 0 || tlv_len > BGP_LS_MAX_MT_ID * 2) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid MT-ID TLV length %u", tlv_len); - return -1; + goto error; } desc->mt_id_count = tlv_len / 2; desc->mt_id = XCALLOC(MTYPE_BGP_LS_NLRI, tlv_len); @@ -2552,11 +2720,16 @@ int bgp_ls_decode_link_descriptor(struct stream *s, struct bgp_ls_link_descripto break; case BGP_LS_TLV_REMOTE_AS_NUMBER: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_LINK_DESC_REMOTE_AS_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate Remote AS Number TLV in link descriptor"); + goto error; + } if (tlv_len != 4) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid Remote AS Number TLV length %u (expected 4)", tlv_len); - return -1; + goto error; } desc->remote_asn = stream_getl(s); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_LINK_DESC_REMOTE_AS_BIT); @@ -2575,10 +2748,16 @@ int bgp_ls_decode_link_descriptor(struct stream *s, struct bgp_ls_link_descripto /* Check we consumed exactly total_length bytes */ if (stream_get_getp(s) != end_pos) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Link Descriptor length mismatch"); - return -1; + goto error; } return 0; + +error: + XFREE(MTYPE_BGP_LS_NLRI, desc->mt_id); + desc->mt_id = NULL; + desc->mt_id_count = 0; + return -1; } /* @@ -2617,15 +2796,20 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr /* Parse TLVs */ while (stream_get_getp(s) < end_pos) { if (stream_get_tlv_hdr(s, &tlv_type, &tlv_len) < 0) - return -1; + goto error; switch (tlv_type) { case BGP_LS_TLV_MT_ID: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_PREFIX_DESC_MT_ID_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate MT-ID TLV in prefix descriptor"); + goto error; + } /* Variable length: 2*n bytes where n is number of MT-IDs */ if (tlv_len % 2 != 0 || tlv_len > BGP_LS_MAX_MT_ID * 2) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid MT-ID TLV length %u", tlv_len); - return -1; + goto error; } desc->mt_id_count = tlv_len / 2; desc->mt_id = XCALLOC(MTYPE_BGP_LS_NLRI, tlv_len); @@ -2635,21 +2819,32 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr break; case BGP_LS_TLV_OSPF_ROUTE_TYPE: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, + BGP_LS_PREFIX_DESC_OSPF_ROUTE_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate OSPF Route Type TLV in prefix descriptor"); + goto error; + } if (tlv_len != BGP_LS_OSPF_ROUTE_TYPE_SIZE) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid OSPF Route Type TLV length %u", tlv_len); - return -1; + goto error; } desc->ospf_route_type = stream_getc(s); BGP_LS_TLV_SET(desc->present_tlvs, BGP_LS_PREFIX_DESC_OSPF_ROUTE_BIT); break; case BGP_LS_TLV_IP_REACH_INFO: + if (BGP_LS_TLV_CHECK(desc->present_tlvs, BGP_LS_PREFIX_DESC_IP_REACH_BIT)) { + flog_warn(EC_BGP_LS_PACKET, + "BGP-LS: duplicate IP Reachability Info TLV in prefix descriptor"); + goto error; + } /* Variable length: prefix_len + ceil(prefix_len/8) */ if (tlv_len < 1) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IP Reach Info TLV length %u", tlv_len); - return -1; + goto error; } /* First byte is prefix length */ desc->prefix.prefixlen = stream_getc(s); @@ -2661,7 +2856,7 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr flog_warn(EC_BGP_LS_PACKET, "BGP-LS: IP Reach Info TLV length %u mismatch (prefix len %u requires %u bytes)", tlv_len, desc->prefix.prefixlen, 1 + expected_bytes); - return -1; + goto error; } /* @@ -2674,7 +2869,7 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv6 prefix length %u (max 128)", desc->prefix.prefixlen); - return -1; + goto error; } if (expected_bytes > 0) stream_get(&desc->prefix.u.prefix6.s6_addr, s, @@ -2686,7 +2881,7 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Invalid IPv4 prefix length %u (max 32)", desc->prefix.prefixlen); - return -1; + goto error; } if (expected_bytes > 0) stream_get(&desc->prefix.u.prefix4.s_addr, s, @@ -2711,16 +2906,22 @@ int bgp_ls_decode_prefix_descriptor(struct stream *s, struct bgp_ls_prefix_descr if (!has_ip_reach) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Mandatory IP Reachability Info TLV missing from Prefix Descriptor"); - return -1; + goto error; } /* Check we consumed exactly total_length bytes */ if (stream_get_getp(s) != end_pos) { flog_warn(EC_BGP_LS_PACKET, "BGP-LS: Prefix Descriptor length mismatch"); - return -1; + goto error; } return 0; + +error: + XFREE(MTYPE_BGP_LS_NLRI, desc->mt_id); + desc->mt_id = NULL; + desc->mt_id_count = 0; + return -1; } /* @@ -3092,6 +3293,11 @@ static int parse_node_flags(struct stream *s, uint16_t length, struct bgp_ls_att return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_NODE_FLAGS_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Node Flags TLV"); + return -1; + } + attr->node_flags = stream_getc(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_NODE_FLAGS_BIT); @@ -3111,6 +3317,11 @@ static int parse_node_name(struct stream *s, uint16_t length, struct bgp_ls_attr if (length == 0) return 0; + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_NODE_NAME_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Node Name TLV"); + return -1; + } + /* Allocate space for node name (null-terminated) */ attr->node_name = XCALLOC(MTYPE_BGP_LS_ATTR, length + 1); stream_get(attr->node_name, s, length); @@ -3132,6 +3343,19 @@ static int parse_isis_area_id(struct stream *s, uint16_t length, struct bgp_ls_a return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_ISIS_AREA_BIT)) { + /* + * RFC 9552 Section 5.3.1.4 allows multiple IS-IS Area-ID TLVs + * to encode synonymous area addresses. We currently support + * only one IS-IS Area-ID TLV; skip any additional ones. + */ + if (BGP_DEBUG(linkstate, LINKSTATE)) + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: multiple IS-IS Area-ID TLVs not supported, skipping duplicate"); + stream_forward_getp(s, length); + return 0; + } + attr->isis_area_id = XCALLOC(MTYPE_BGP_LS_ATTR, length); stream_get(attr->isis_area_id, s, length); attr->isis_area_id_len = length; @@ -3152,6 +3376,11 @@ static int parse_admin_group(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_ADMIN_GROUP_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Admin Group TLV"); + return -1; + } + attr->admin_group = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_ADMIN_GROUP_BIT); @@ -3172,6 +3401,11 @@ static int parse_max_link_bw(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_MAX_LINK_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Maximum Link Bandwidth TLV"); + return -1; + } + /* Read as 32-bit IEEE floating point */ bw_bits = stream_getl(s); memcpy(&attr->max_link_bw, &bw_bits, 4); @@ -3194,6 +3428,11 @@ static int parse_max_resv_bw(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_MAX_RESV_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Maximum Reservable Bandwidth TLV"); + return -1; + } + bw_bits = stream_getl(s); memcpy(&attr->max_resv_bw, &bw_bits, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_MAX_RESV_BW_BIT); @@ -3216,6 +3455,11 @@ static int parse_unresv_bw(struct stream *s, uint16_t length, struct bgp_ls_attr return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_UNRESV_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Unreserved Bandwidth TLV"); + return -1; + } + for (i = 0; i < BGP_LS_MAX_UNRESV_BW; i++) { bw_bits = stream_getl(s); memcpy(&attr->unreserved_bw[i], &bw_bits, 4); @@ -3236,6 +3480,11 @@ static int parse_te_metric(struct stream *s, uint16_t length, struct bgp_ls_attr return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_TE_METRIC_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate TE Default Metric TLV"); + return -1; + } + attr->te_metric = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_TE_METRIC_BIT); @@ -3254,6 +3503,11 @@ static int parse_igp_metric(struct stream *s, uint16_t length, struct bgp_ls_att return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IGP_METRIC_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate IGP Metric TLV"); + return -1; + } + attr->igp_metric = 0; for (int i = 0; i < length; i++) attr->igp_metric = (attr->igp_metric << 8) | stream_getc(s); @@ -3284,6 +3538,11 @@ static int parse_srlg(struct stream *s, uint16_t length, struct bgp_ls_attr *att return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_SRLG_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate SRLG TLV"); + return -1; + } + attr->srlg_values = XMALLOC(MTYPE_BGP_LS_ATTR, count * sizeof(uint32_t)); for (i = 0; i < count; i++) attr->srlg_values[i] = stream_getl(s); @@ -3302,6 +3561,11 @@ static int parse_link_name(struct stream *s, uint16_t length, struct bgp_ls_attr if (length == 0) return 0; + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_LINK_NAME_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Link Name TLV"); + return -1; + } + attr->link_name = XCALLOC(MTYPE_BGP_LS_ATTR, length + 1); stream_get(attr->link_name, s, length); attr->link_name[length] = '\0'; @@ -3315,6 +3579,8 @@ static int parse_link_name(struct stream *s, uint16_t length, struct bgp_ls_attr */ static int parse_ext_admin_group(struct stream *s, uint16_t length, struct bgp_ls_attr *attr) { + size_t nb_words; + /* Length must be multiple of 4 (each word is 32 bits) */ if (length % 4 != 0) { flog_warn(EC_BGP_UPDATE_RCV, @@ -3323,15 +3589,23 @@ static int parse_ext_admin_group(struct stream *s, uint16_t length, struct bgp_l return -1; } - size_t nb_words = length / 4; - - /* Decode each 32-bit word */ - for (size_t i = 0; i < nb_words; i++) { - uint32_t word = ntohl(stream_getl(s)); + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_EXT_ADMIN_GROUP_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Extended Admin Group TLV"); + return -1; + } - admin_group_bulk_set(&attr->ext_admin_group, word, i); + nb_words = length / 4; + if (nb_words > BGP_LS_MAX_EXT_ADMIN_GROUPS) { + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: Extended Admin Group TLV too large (%zu words, max %zu)", + nb_words, (size_t)BGP_LS_MAX_EXT_ADMIN_GROUPS); + return -1; } + /* Decode each 32-bit word */ + for (size_t i = 0; i < nb_words; i++) + admin_group_bulk_set(&attr->ext_admin_group, stream_getl(s), i); + BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_EXT_ADMIN_GROUP_BIT); return 0; @@ -3348,6 +3622,11 @@ static int parse_link_delay(struct stream *s, uint16_t length, struct bgp_ls_att return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_DELAY_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Unidirectional Link Delay TLV"); + return -1; + } + attr->delay = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_DELAY_BIT); @@ -3365,6 +3644,12 @@ static int parse_min_max_delay(struct stream *s, uint16_t length, struct bgp_ls_ return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_MIN_MAX_DELAY_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: duplicate Min/Max Unidirectional Link Delay TLV"); + return -1; + } + attr->min_delay = stream_getl(s); attr->max_delay = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_MIN_MAX_DELAY_BIT); @@ -3383,6 +3668,12 @@ static int parse_link_jitter(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_JITTER_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: duplicate Unidirectional Delay Variation TLV"); + return -1; + } + attr->jitter = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_JITTER_BIT); @@ -3400,6 +3691,11 @@ static int parse_packet_loss(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_PKT_LOSS_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Unidirectional Link Loss TLV"); + return -1; + } + attr->pkt_loss = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_PKT_LOSS_BIT); @@ -3417,6 +3713,11 @@ static int parse_residual_bw(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_RESIDUAL_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Residual Bandwidth TLV"); + return -1; + } + stream_get(&attr->residual_bw, s, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_RESIDUAL_BW_BIT); @@ -3434,6 +3735,11 @@ static int parse_available_bw(struct stream *s, uint16_t length, struct bgp_ls_a return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_AVAILABLE_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Available Bandwidth TLV"); + return -1; + } + stream_get(&attr->available_bw, s, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_AVAILABLE_BW_BIT); @@ -3451,6 +3757,11 @@ static int parse_utilized_bw(struct stream *s, uint16_t length, struct bgp_ls_at return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_UTILIZED_BW_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Utilized Bandwidth TLV"); + return -1; + } + stream_get(&attr->utilized_bw, s, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_UTILIZED_BW_BIT); @@ -3468,6 +3779,11 @@ static int parse_igp_flags(struct stream *s, uint16_t length, struct bgp_ls_attr return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IGP_FLAGS_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate IGP Flags TLV"); + return -1; + } + attr->igp_flags = stream_getc(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_IGP_FLAGS_BIT); @@ -3498,6 +3814,11 @@ static int parse_route_tag(struct stream *s, uint16_t length, struct bgp_ls_attr return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_ROUTE_TAG_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Route Tag TLV"); + return -1; + } + attr->route_tags = XMALLOC(MTYPE_BGP_LS_ATTR, count * sizeof(uint32_t)); for (i = 0; i < count; i++) attr->route_tags[i] = stream_getl(s); @@ -3519,6 +3840,11 @@ static int parse_prefix_metric(struct stream *s, uint16_t length, struct bgp_ls_ return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_PREFIX_METRIC_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Prefix Metric TLV"); + return -1; + } + attr->prefix_metric = stream_getl(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_PREFIX_METRIC_BIT); @@ -3531,16 +3857,22 @@ static int parse_prefix_metric(struct stream *s, uint16_t length, struct bgp_ls_ */ static int parse_ospf_fwd_addr(struct stream *s, uint16_t length, struct bgp_ls_attr *attr) { + if (length != 4 && length != 16) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: Invalid OSPF Fwd Addr length (%u bytes)", + length); + return -1; + } + + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_OSPF_FWD_ADDR_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate OSPF Forwarding Address TLV"); + return -1; + } if (length == 4) { /* IPv4 */ stream_get(&attr->ospf_fwd_addr, s, 4); - } else if (length == 16) { + } else { /* IPv6 */ stream_get(&attr->ospf_fwd_addr6, s, 16); - } else { - flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: Invalid OSPF Fwd Addr length (%u bytes)", - length); - return -1; } BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_OSPF_FWD_ADDR_BIT); @@ -3556,6 +3888,19 @@ static int parse_ipv4_router_id_local(struct stream *s, uint16_t length, struct return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IPV4_ROUTER_ID_LOCAL_BIT)) { + /* + * RFC 9552 Section 5.3.1.4 allows multiple IPv4 Local Router-ID TLVs + * when a node has more than one auxiliary Router-ID. We currently + * support only one; skip any additional ones. + */ + if (BGP_DEBUG(linkstate, LINKSTATE)) + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: multiple IPv4 Local Router-ID TLVs not supported, skipping duplicate"); + stream_forward_getp(s, length); + return 0; + } + stream_get(&attr->ipv4_router_id_local, s, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_IPV4_ROUTER_ID_LOCAL_BIT); return 0; @@ -3570,6 +3915,19 @@ static int parse_ipv6_router_id_local(struct stream *s, uint16_t length, struct return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IPV6_ROUTER_ID_LOCAL_BIT)) { + /* + * RFC 9552 Section 5.3.1.4 allows multiple IPv6 Local Router-ID TLVs + * when a node has more than one auxiliary Router-ID. We currently + * support only one; skip any additional ones. + */ + if (BGP_DEBUG(linkstate, LINKSTATE)) + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: multiple IPv6 Local Router-ID TLVs not supported, skipping duplicate"); + stream_forward_getp(s, length); + return 0; + } + stream_get(&attr->ipv6_router_id_local, s, 16); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_IPV6_ROUTER_ID_LOCAL_BIT); return 0; @@ -3584,6 +3942,19 @@ static int parse_ipv4_router_id_remote(struct stream *s, uint16_t length, struct return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IPV4_ROUTER_ID_REMOTE_BIT)) { + /* + * RFC 9552 Section 5.3.2.1 allows multiple IPv4 Remote Router-ID TLVs + * when a node has more than one auxiliary Router-ID. We currently + * support only one; skip any additional ones. + */ + if (BGP_DEBUG(linkstate, LINKSTATE)) + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: multiple IPv4 Remote Router-ID TLVs not supported, skipping duplicate"); + stream_forward_getp(s, length); + return 0; + } + stream_get(&attr->ipv4_router_id_remote, s, 4); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_IPV4_ROUTER_ID_REMOTE_BIT); return 0; @@ -3598,6 +3969,19 @@ static int parse_ipv6_router_id_remote(struct stream *s, uint16_t length, struct return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_IPV6_ROUTER_ID_REMOTE_BIT)) { + /* + * RFC 9552 Section 5.3.2.1 allows multiple IPv6 Remote Router-ID TLVs + * when a node has more than one auxiliary Router-ID. We currently + * support only one; skip any additional ones. + */ + if (BGP_DEBUG(linkstate, LINKSTATE)) + flog_warn(EC_BGP_UPDATE_RCV, + "BGP-LS: multiple IPv6 Remote Router-ID TLVs not supported, skipping duplicate"); + stream_forward_getp(s, length); + return 0; + } + stream_get(&attr->ipv6_router_id_remote, s, 16); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_IPV6_ROUTER_ID_REMOTE_BIT); return 0; @@ -3612,6 +3996,11 @@ static int parse_link_protection(struct stream *s, uint16_t length, struct bgp_l return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_LINK_PROTECTION_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Link Protection Type TLV"); + return -1; + } + attr->link_protection = stream_getw(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_LINK_PROTECTION_BIT); return 0; @@ -3626,6 +4015,11 @@ static int parse_mpls_protocol_mask(struct stream *s, uint16_t length, struct bg return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_MPLS_PROTOCOL_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate MPLS Protocol Mask TLV"); + return -1; + } + attr->mpls_protocol_mask = stream_getc(s); BGP_LS_TLV_SET(attr->present_tlvs, BGP_LS_ATTR_MPLS_PROTOCOL_BIT); return 0; @@ -3650,6 +4044,11 @@ static int parse_extended_tag(struct stream *s, uint16_t length, struct bgp_ls_a return -1; } + if (BGP_LS_TLV_CHECK(attr->present_tlvs, BGP_LS_ATTR_EXTENDED_TAG_BIT)) { + flog_warn(EC_BGP_UPDATE_RCV, "BGP-LS: duplicate Extended Route Tag TLV"); + return -1; + } + attr->extended_tags = XCALLOC(MTYPE_BGP_LS_ATTR, count * sizeof(uint64_t)); attr->extended_tag_count = count; diff --git a/bgpd/bgp_ls_nlri.h b/bgpd/bgp_ls_nlri.h index 2643a755595b..a2d8a5891b73 100644 --- a/bgpd/bgp_ls_nlri.h +++ b/bgpd/bgp_ls_nlri.h @@ -251,6 +251,7 @@ enum bgp_ls_attr_tlv { #define BGP_LS_MAX_SRLG 64 /* Maximum SRLGs per link */ #define BGP_LS_MAX_UNRESV_BW 8 /* 8 priority classes */ #define BGP_LS_MAX_ROUTE_TAGS 16 /* Maximum route tags */ +#define BGP_LS_MAX_EXT_ADMIN_GROUPS 256 /* Maximum number of admin groups in Extended Admin Group TLV */ /* * Bit positions for attribute presence bitmasks