CVE-2026-28532
Description
FRRouting before 10.5.3 contains an integer overflow vulnerability in seven OSPF Traffic Engineering and Segment Routing TLV parser functions where a uint16_t accumulator variable truncates uint32_t values returned by the TLV_SIZE() macro, causing the loop termination condition to fail while pointer advancement continues unchecked. Attackers with an established OSPF adjacency can send a crafted LS Update packet with a malicious Type 10 or Type 11 Opaque LSA to trigger out-of-bounds memory reads and crash all affected routers in the OSPF area or autonomous system.
Affected products
1Patches
1f098decf0298Merge pull request #21002 from Jafaral/ospf-fix
2 files changed · +91 −23
ospfd/ospf_sr.c+40 −10 modified@@ -989,7 +989,8 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) struct ext_subtlv_rmt_itf_addr *rmt_itf; struct tlv_header *sub_tlvh; - uint16_t length = 0, sum = 0, i = 0; + uint32_t length = 0, sum = 0; + uint16_t i = 0; /* Check TLV size */ if ((ntohs(tlvh->length) > size) @@ -1004,7 +1005,15 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE; sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE); - for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { + for (; sum < length && sub_tlvh;) { + uint32_t tlv_size = TLV_SIZE(sub_tlvh); + + if (tlv_size > length - sum) { + zlog_warn("Malformed Extended Link sub-TLV size %u (remaining %u)", + tlv_size, length - sum); + break; + } + switch (ntohs(sub_tlvh->type)) { case EXT_SUBTLV_ADJ_SID: adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh; @@ -1045,7 +1054,9 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) default: break; } - sum += TLV_SIZE(sub_tlvh); + sum += tlv_size; + if (sum < length) + sub_tlvh = TLV_HDR_NEXT(sub_tlvh); } IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data); @@ -1066,7 +1077,7 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, struct ext_subtlv_prefix_sid *psid; struct tlv_header *sub_tlvh; - uint16_t length = 0, sum = 0; + uint32_t length = 0, sum = 0; /* Check TLV size */ if ((ntohs(tlvh->length) > size) @@ -1081,7 +1092,15 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE; sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE + EXT_TLV_PREFIX_SIZE); - for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { + for (; sum < length && sub_tlvh;) { + uint32_t tlv_size = TLV_SIZE(sub_tlvh); + + if (tlv_size > length - sum) { + zlog_warn("Malformed Extended Prefix sub-TLV size %u (remaining %u)", + tlv_size, length - sum); + break; + } + switch (ntohs(sub_tlvh->type)) { case EXT_SUBTLV_PREFIX_SID: psid = (struct ext_subtlv_prefix_sid *)sub_tlvh; @@ -1106,7 +1125,9 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, default: break; } - sum += TLV_SIZE(sub_tlvh); + sum += tlv_size; + if (sum < length) + sub_tlvh = TLV_HDR_NEXT(sub_tlvh); } osr_debug(" |- Found SID %u for prefix %pFX", srp->sid, @@ -1374,7 +1395,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) struct ri_sr_tlv_sid_label_range *ri_srlb = NULL; struct ri_sr_tlv_sr_algorithm *algo = NULL; struct sr_block srgb; - uint16_t length = 0, sum = 0; + uint32_t length = 0, sum = 0; uint8_t msd = 0; osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4", @@ -1402,8 +1423,15 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) srgb.range_size = 0; srgb.lower_bound = 0; - for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL); - tlvh = TLV_HDR_NEXT(tlvh)) { + for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);) { + uint32_t tlv_size = TLV_SIZE(tlvh); + + if (tlv_size > length - sum) { + zlog_warn("Malformed RI TLV size %u (remaining %u)", tlv_size, + length - sum); + break; + } + switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; @@ -1420,7 +1448,9 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) default: break; } - sum += TLV_SIZE(tlvh); + sum += tlv_size; + if (sum < length) + tlvh = TLV_HDR_NEXT(tlvh); } /* Check if Segment Routing Capabilities has been found */
ospfd/ospf_te.c+51 −13 modified@@ -2119,7 +2119,7 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) struct ls_attributes *old, attr = {}; struct tlv_header *tlvh; void *value; - uint16_t len, sum; + uint32_t len, sum; uint8_t lsa_id; /* Initialize Attribute */ @@ -2149,11 +2149,19 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) sum = sizeof(struct tlv_header); /* Browse sub-TLV and fulfill Link State Attributes */ - for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + tlvh = TLV_DATA(tlvh); + while (sum < len) { + uint32_t tlv_size = TLV_SIZE(tlvh); uint32_t val32, tab32[2]; float valf, tabf[8]; struct in_addr addr; + if (tlv_size > len - sum) { + zlog_warn("Malformed TE sub-TLV size %u (remaining %u)", tlv_size, + len - sum); + break; + } + value = TLV_DATA(tlvh); switch (ntohs(tlvh->type)) { case TE_LINK_SUBTLV_LCLIF_IPADDR: @@ -2248,7 +2256,9 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) default: break; } - sum += TLV_SIZE(tlvh); + sum += tlv_size; + if (sum < len) + tlvh = TLV_HDR_NEXT(tlvh); } /* Get corresponding Edge from Link State Data Base */ @@ -2348,7 +2358,7 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) struct tlv_header *tlvh; struct in_addr addr; struct ls_edge_key key = {.family = AF_UNSPEC}; - uint16_t len, sum; + uint32_t len, sum; uint8_t lsa_id; /* Initialize TLV browsing */ @@ -2360,14 +2370,25 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) sum = sizeof(struct tlv_header); /* Browse sub-TLV to find Link ID */ - for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + tlvh = TLV_DATA(tlvh); + while (sum < len) { + uint32_t tlv_size = TLV_SIZE(tlvh); + + if (tlv_size > len - sum) { + zlog_warn("Malformed TE sub-TLV size %u (remaining %u)", tlv_size, + len - sum); + break; + } + if (ntohs(tlvh->type) == TE_LINK_SUBTLV_LCLIF_IPADDR) { memcpy(&addr, TLV_DATA(tlvh), TE_LINK_SUBTLV_DEF_SIZE); key.family = AF_INET; IPV4_ADDR_COPY(&key.k.addr, &addr); break; } - sum += TLV_SIZE(tlvh); + sum += tlv_size; + if (sum < len) + tlvh = TLV_HDR_NEXT(tlvh); } if (key.family == AF_UNSPEC) return 0; @@ -2442,7 +2463,7 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) struct ls_node *node; struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; - uint16_t len = 0, sum = 0; + uint32_t len = 0, sum = 0; /* Get vertex / Node from LSA Advertised Router ID */ vertex = get_vertex(ted, lsa); @@ -2453,13 +2474,18 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) /* Initialize TLV browsing */ len = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh; - tlvh = TLV_HDR_NEXT(tlvh)) { + for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh;) { + uint32_t tlv_size = TLV_SIZE(tlvh); struct ri_sr_tlv_sr_algorithm *algo; struct ri_sr_tlv_sid_label_range *range; struct ri_sr_tlv_node_msd *msd; uint32_t size, lower; + if (tlv_size > len - sum) { + zlog_warn("Malformed RI TLV size %u (remaining %u)", tlv_size, len - sum); + break; + } + switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: if (TLV_BODY_SIZE(tlvh) < 1 || @@ -2544,7 +2570,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) default: break; } - sum += TLV_SIZE(tlvh); + sum += tlv_size; + if (sum < len) + tlvh = TLV_HDR_NEXT(tlvh); } /* Vertex has been created or updated: export it */ @@ -2756,7 +2784,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) struct ext_tlv_link *ext; struct ls_edge *edge; struct ls_attributes *atr; - uint16_t len = 0, sum = 0, i; + uint32_t len = 0, sum = 0; + uint16_t i; uint32_t label; /* Get corresponding Edge from Link State Data Base */ @@ -2790,11 +2819,18 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) len -= EXT_TLV_LINK_SIZE; tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE); - for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + for (; sum < len;) { + uint32_t tlv_size = TLV_SIZE(tlvh); struct ext_subtlv_adj_sid *adj; struct ext_subtlv_lan_adj_sid *ladj; struct ext_subtlv_rmt_itf_addr *rmt; + if (tlv_size > len - sum) { + zlog_warn("Malformed Extended Link sub-TLV size %u (remaining %u)", + tlv_size, len - sum); + break; + } + switch (ntohs(tlvh->type)) { case EXT_SUBTLV_ADJ_SID: if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_ADJ_SID_SIZE) @@ -2873,7 +2909,9 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) default: break; } - sum += TLV_SIZE(tlvh); + sum += tlv_size; + if (sum < len) + tlvh = TLV_HDR_NEXT(tlvh); } /* Export Link State Edge if needed */
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/FRRouting/frr/commit/f098decf02987fbf1c891766c1516ac832adadfdnvdPatch
- github.com/FRRouting/frr/pull/21002nvdIssue TrackingPatch
- www.vulncheck.com/advisories/frrouting-integer-overflow-in-ospf-tlv-parser-functionsnvdThird Party Advisory
- github.com/FRRouting/frr/releases/tag/frr-10.5.3nvdRelease Notes
News mentions
0No linked articles in our index yet.