Version in base suite: 8.4.4-1.1~deb12u1 Base version: frr_8.4.4-1.1~deb12u1 Target version: frr_8.4.4-1.1~deb12u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/frr/frr_8.4.4-1.1~deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/frr/frr_8.4.4-1.1~deb12u2.dsc changelog | 22 ++ patches/CVE-2023-3748.patch | 39 ++++ patches/CVE-2024-27913.patch | 21 ++ patches/CVE-2024-31950.patch | 48 ++++++ patches/CVE-2024-31951.patch | 88 +++++++++++ patches/CVE-2024-34088.patch | 61 +++++++ patches/CVE-2025-61099_61107.patch | 268 +++++++++++++++++++++++++++++++++ patches/CVE-2025-61104.patch | 29 +++ patches/CVE-2026-28532.patch | 292 +++++++++++++++++++++++++++++++++++++ patches/CVE-2026-37457.patch | 36 ++++ patches/CVE-2026-37458.patch | 30 +++ patches/CVE-2026-5107.patch | 85 ++++++++++ patches/series | 11 + 13 files changed, 1030 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpdau5_qrt/frr_8.4.4-1.1~deb12u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpdau5_qrt/frr_8.4.4-1.1~deb12u2.dsc: no acceptable signature found diff -Nru frr-8.4.4/debian/changelog frr-8.4.4/debian/changelog --- frr-8.4.4/debian/changelog 2023-09-05 08:04:06.000000000 +0000 +++ frr-8.4.4/debian/changelog 2026-06-02 07:30:27.000000000 +0000 @@ -1,3 +1,25 @@ +frr (8.4.4-1.1~deb12u2) bookworm-security; urgency=high + + * Non-maintainer upload by the Security Team. + * Backport upstream fixes for several BGP/OSPF/babeld vulnerabilities: + - CVE-2026-37457: off-by-one out-of-bounds write in the BGP FlowSpec + operator decoder. + - CVE-2026-28532: out-of-bounds read in OSPF TE/SR Opaque LSA TLV parsing + caused by a truncated length accumulator (ospf_te_delete_te hunk adapted + to the 8.4.4 edge-key code). + - CVE-2026-5107: missing length validation when parsing EVPN Type-2/3/4 and + ENCAP/VNC NLRIs (hand-ported to the 8.4.4 EVPN code). + - CVE-2026-37458: missing martian next-hop validation in MP_REACH_NLRI. + - CVE-2025-61099, CVE-2025-61100, CVE-2025-61101, CVE-2025-61102, + CVE-2025-61103, CVE-2025-61104, CVE-2025-61105, CVE-2025-61106, + CVE-2025-61107: NULL pointer dereference in ospfd when dumping Opaque + LSAs while OSPF packet debugging is enabled. + - CVE-2023-3748: infinite loop (DoS) in babeld packet parsing. + - CVE-2024-27913, CVE-2024-31950, CVE-2024-31951, CVE-2024-34088: crashes + and buffer overflows in OSPF Traffic Engineering / Opaque LSA parsing. + + -- Aron Xu Tue, 02 Jun 2026 15:30:27 +0800 + frr (8.4.4-1.1~deb12u1) bookworm-security; urgency=high * Non-maintainer upload by the Security Team. diff -Nru frr-8.4.4/debian/patches/CVE-2023-3748.patch frr-8.4.4/debian/patches/CVE-2023-3748.patch --- frr-8.4.4/debian/patches/CVE-2023-3748.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2023-3748.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,39 @@ +Description: babeld: avoid infinite loops in parse_packet + A crafted babel packet (unicast Hello, interval==0, or a mandatory unknown + sub-TLV) could make parse_packet() in babeld/message.c loop forever because a + "continue" failed to advance the buffer index, causing a denial of service + (CVE-2023-3748). +Origin: backport, https://github.com/FRRouting/frr/commit/ae1e0e1fed77716bc06f181ad68c4433fb5523d0 +Bug: https://github.com/FRRouting/frr/issues/11808 +Forwarded: not-needed +diff --git a/babeld/message.c b/babeld/message.c +index 687f768446..b5c2a58984 100644 +--- a/babeld/message.c ++++ b/babeld/message.c +@@ -422,7 +422,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, + debugf(BABEL_DEBUG_COMMON, + "Received Hello from %s on %s that does not have all 0's in the unused section of flags, ignoring", + format_address(from), ifp->name); +- continue; ++ goto done; + } + + /* +@@ -434,7 +434,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, + debugf(BABEL_DEBUG_COMMON, + "Received Unicast Hello from %s on %s that FRR is not prepared to understand yet", + format_address(from), ifp->name); +- continue; ++ goto done; + } + + DO_NTOHS(seqno, message + 4); +@@ -452,7 +452,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, + debugf(BABEL_DEBUG_COMMON, + "Received hello from %s on %s should be ignored as that this version of FRR does not know how to properly handle interval == 0", + format_address(from), ifp->name); +- continue; ++ goto done; + } + + changed = update_neighbour(neigh, seqno, interval); diff -Nru frr-8.4.4/debian/patches/CVE-2024-27913.patch frr-8.4.4/debian/patches/CVE-2024-27913.patch --- frr-8.4.4/debian/patches/CVE-2024-27913.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2024-27913.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,21 @@ +Description: ospfd: fix crash in OSPF TE parsing of malformed LSA + A malformed OSPF Traffic Engineering LSA could make ospf_te_parse_te() access a + missing attribute field and crash ospfd (CVE-2024-27913). +Origin: backport, https://github.com/FRRouting/frr/commit/a73e66d07329d721f26f3f336f7735de420b0183 +Bug: https://github.com/FRRouting/frr/pull/15431 +Forwarded: not-needed +diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c +index a55a37a907..359dc1f5d4 100644 +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -2246,6 +2246,10 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) + } + + /* Get corresponding Edge from Link State Data Base */ ++ if (IPV4_NET0(attr.standard.local.s_addr) && !attr.standard.local_id) { ++ ote_debug(" |- Found no TE Link local address/ID. Abort!"); ++ return -1; ++ } + edge = get_edge(ted, attr.adv, attr.standard.local); + old = edge->attributes; + diff -Nru frr-8.4.4/debian/patches/CVE-2024-31950.patch frr-8.4.4/debian/patches/CVE-2024-31950.patch --- frr-8.4.4/debian/patches/CVE-2024-31950.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2024-31950.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,48 @@ +Description: ospfd: fix buffer overflow in Router Information parsing + ospf_te_parse_ri() in ospfd/ospf_te.c did not validate Segment Routing sub-TLV + lengths, allowing a crafted Router Information LSA to overflow a buffer and + crash ospfd (CVE-2024-31950). +Origin: backport, https://github.com/FRRouting/frr/commit/f69d1313b19047d3d83fc2b36a518355b861dfc4 +Bug: https://github.com/FRRouting/frr/pull/15674 +Forwarded: not-needed +diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c +index 359dc1f5d4..091669d8ed 100644 +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -2456,6 +2456,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) + + switch (ntohs(tlvh->type)) { + case RI_SR_TLV_SR_ALGORITHM: ++ if (TLV_BODY_SIZE(tlvh) < 1 || ++ TLV_BODY_SIZE(tlvh) > ALGORITHM_COUNT) ++ break; + algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; + + for (int i = 0; i < ntohs(algo->header.length); i++) { +@@ -2480,6 +2483,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) + break; + + case RI_SR_TLV_SRGB_LABEL_RANGE: ++ if (TLV_BODY_SIZE(tlvh) != RI_SR_TLV_LABEL_RANGE_SIZE) ++ break; + range = (struct ri_sr_tlv_sid_label_range *)tlvh; + size = GET_RANGE_SIZE(ntohl(range->size)); + lower = GET_LABEL(ntohl(range->lower.value)); +@@ -2497,6 +2502,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) + break; + + case RI_SR_TLV_SRLB_LABEL_RANGE: ++ if (TLV_BODY_SIZE(tlvh) != RI_SR_TLV_LABEL_RANGE_SIZE) ++ break; + range = (struct ri_sr_tlv_sid_label_range *)tlvh; + size = GET_RANGE_SIZE(ntohl(range->size)); + lower = GET_LABEL(ntohl(range->lower.value)); +@@ -2514,6 +2521,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) + break; + + case RI_SR_TLV_NODE_MSD: ++ if (TLV_BODY_SIZE(tlvh) < RI_SR_TLV_NODE_MSD_SIZE) ++ break; + msd = (struct ri_sr_tlv_node_msd *)tlvh; + if ((CHECK_FLAG(node->flags, LS_NODE_MSD)) + && (node->msd == msd->value)) diff -Nru frr-8.4.4/debian/patches/CVE-2024-31951.patch frr-8.4.4/debian/patches/CVE-2024-31951.patch --- frr-8.4.4/debian/patches/CVE-2024-31951.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2024-31951.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,88 @@ +Description: ospfd: validate Extended Link sub-TLV lengths + ospf_te_parse_ext_link() in ospfd/ospf_te.c did not validate Adjacency-SID + sub-TLV lengths, allowing a crafted Extended Link Opaque LSA to overflow a + buffer and crash ospfd (CVE-2024-31951). +Origin: backport, https://github.com/FRRouting/frr/commit/5557a289acdaeec8cc63ffc97b5c2abf6dee7b3a +Bug: https://github.com/FRRouting/frr/pull/15674 +Forwarded: not-needed +diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c +index 091669d8ed..e68f9444f5 100644 +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -2620,6 +2620,7 @@ static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) + struct ext_tlv_prefix *ext; + struct ext_subtlv_prefix_sid *pref_sid; + uint32_t label; ++ uint16_t len, size; + + /* Get corresponding Subnet from Link State Data Base */ + ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); +@@ -2641,6 +2642,18 @@ static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) + ote_debug(" |- Process Extended Prefix LSA %pI4 for subnet %pFX", + &lsa->data->id, &pref); + ++ /* ++ * Check Extended Prefix TLV size against LSA size ++ * as only one TLV is allowed per LSA ++ */ ++ len = TLV_BODY_SIZE(&ext->header); ++ size = lsa->size - (OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE); ++ if (len != size || len <= 0) { ++ ote_debug(" |- Wrong TLV size: %u instead of %u", ++ (uint32_t)len, (uint32_t)size); ++ return -1; ++ } ++ + /* Initialize TLV browsing */ + ls_pref = subnet->ls_pref; + pref_sid = (struct ext_subtlv_prefix_sid *)((char *)(ext) + TLV_HDR_SIZE +@@ -2751,8 +2764,20 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) + ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4", + &lsa->data->id, &edge->attributes->standard.local); + +- /* Initialize TLV browsing */ +- len = TLV_BODY_SIZE(&ext->header) - EXT_TLV_LINK_SIZE; ++ /* ++ * Check Extended Link TLV size against LSA size ++ * as only one TLV is allowed per LSA ++ */ ++ len = TLV_BODY_SIZE(&ext->header); ++ i = lsa->size - (OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE); ++ if (len != i || len <= 0) { ++ ote_debug(" |- Wrong TLV size: %u instead of %u", ++ (uint32_t)len, (uint32_t)i); ++ return -1; ++ } ++ ++ /* Initialize subTLVs browsing */ ++ 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)) { +@@ -2762,6 +2787,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) + + switch (ntohs(tlvh->type)) { + case EXT_SUBTLV_ADJ_SID: ++ if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_ADJ_SID_SIZE) ++ break; + adj = (struct ext_subtlv_adj_sid *)tlvh; + label = CHECK_FLAG(adj->flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG) +@@ -2788,6 +2815,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) + + break; + case EXT_SUBTLV_LAN_ADJ_SID: ++ if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_LAN_ADJ_SID_SIZE) ++ break; + ladj = (struct ext_subtlv_lan_adj_sid *)tlvh; + label = CHECK_FLAG(ladj->flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG) +@@ -2817,6 +2846,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) + + break; + case EXT_SUBTLV_RMT_ITF_ADDR: ++ if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_RMT_ITF_ADDR_SIZE) ++ break; + rmt = (struct ext_subtlv_rmt_itf_addr *)tlvh; + if (CHECK_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR) + && IPV4_ADDR_SAME(&atr->standard.remote, diff -Nru frr-8.4.4/debian/patches/CVE-2024-34088.patch frr-8.4.4/debian/patches/CVE-2024-34088.patch --- frr-8.4.4/debian/patches/CVE-2024-34088.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2024-34088.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,61 @@ +Description: ospfd: protect calls to get_edge() against NULL + get_edge() in ospfd/ospf_te.c may return NULL, but several callers + (ospf_te_update_link, ospf_te_parse_te, ospf_te_parse_ext_link) dereferenced + the result without checking, so a crafted OSPF TE LSA could crash ospfd + (CVE-2024-34088). Also reject invalid Link/Node IDs inside get_edge(). +Origin: backport, https://github.com/FRRouting/frr/commit/cef38442420aeac8e163f8aa55f1b985908f993c +Bug: https://github.com/FRRouting/frr/pull/15674 +Forwarded: not-needed +diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c +index 23a1b181ec..d1f114e30a 100644 +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -1686,6 +1686,11 @@ static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_node_id adv, + struct ls_edge *edge; + struct ls_attributes *attr; + ++ /* Check that Link ID and Node ID are valid */ ++ if (IPV4_NET0(link_id.s_addr) || IPV4_NET0(adv.id.ip.addr.s_addr) || ++ adv.origin != OSPFv2) ++ return NULL; ++ + /* Search Edge that corresponds to the Link ID */ + key = ((uint64_t)ntohl(link_id.s_addr)) & 0xffffffff; + edge = ls_find_edge_by_key(ted, key); +@@ -1758,6 +1763,10 @@ static void ospf_te_update_link(struct ls_ted *ted, struct ls_vertex *vertex, + + /* Get Corresponding Edge from Link State Data Base */ + edge = get_edge(ted, vertex->node->adv, link_data); ++ if (!edge) { ++ ote_debug(" |- Found no edge from Link Data. Abort!"); ++ return; ++ } + attr = edge->attributes; + + /* re-attached edge to vertex if needed */ +@@ -2276,11 +2285,11 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) + } + + /* Get corresponding Edge from Link State Data Base */ +- if (IPV4_NET0(attr.standard.local.s_addr) && !attr.standard.local_id) { +- ote_debug(" |- Found no TE Link local address/ID. Abort!"); ++ edge = get_edge(ted, attr.adv, attr.standard.local); ++ if (!edge) { ++ ote_debug(" |- Found no edge from Link local add./ID. Abort!"); + return -1; + } +- edge = get_edge(ted, attr.adv, attr.standard.local); + old = edge->attributes; + + ote_debug(" |- Process Traffic Engineering LSA %pI4 for Edge %pI4", +@@ -2786,6 +2795,10 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) + lnid.id.ip.area_id = lsa->area->area_id; + ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); + edge = get_edge(ted, lnid, ext->link_data); ++ if (!edge) { ++ ote_debug(" |- Found no edge from Extended Link Data. Abort!"); ++ return -1; ++ } + atr = edge->attributes; + + ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4", diff -Nru frr-8.4.4/debian/patches/CVE-2025-61099_61107.patch frr-8.4.4/debian/patches/CVE-2025-61099_61107.patch --- frr-8.4.4/debian/patches/CVE-2025-61099_61107.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2025-61099_61107.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,268 @@ +Description: ospfd: guard vty_out against NULL vty when dumping link/prefix info + When "debug ospf packet ... detail" is enabled, ospfd dumps Opaque LSAs by + calling the per-type show helpers with a NULL vty (intending zlog output). + The TE/SR Extended-Link/Prefix dump helpers in ospf_ext.c dereferenced vty + (via vty_out) without a NULL check, so a crafted OSPF LS-Update could crash + ospfd (remote, unauthenticated DoS). This covers CVE-2025-61099, CVE-2025-61100, + CVE-2025-61101, CVE-2025-61102, CVE-2025-61103, CVE-2025-61105, CVE-2025-61106 + and CVE-2025-61107; CVE-2025-61104 (check_tlv_size) is handled by the companion + patch CVE-2025-61104.patch. + . + The upstream fix (commit 034e6fe67078) rewrites the JSON-aware show functions of + a much newer ospf_ext.c. 8.4.4 predates the JSON support in these helpers, so + the same NULL-vty guard is applied directly to the 8.4.4 plain-vty_out code. +Origin: backport, https://github.com/FRRouting/frr/commit/034e6fe67078810b952630055614ee5710d1196e +Bug: https://github.com/FRRouting/frr/issues/19471 +Forwarded: not-needed +Index: b/ospfd/ospf_ext.c +=================================================================== +--- a/ospfd/ospf_ext.c ++++ b/ospfd/ospf_ext.c +@@ -1739,9 +1739,16 @@ static uint16_t show_vty_ext_link_rmt_it + + check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address"); + +- vty_out(vty, +- " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n", +- ntohs(top->header.length), &top->value); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n", ++ ntohs(top->header.length), &top->value); ++ } else { ++ zlog_debug(" Remote Interface Address Sub-TLV: Length %u", ++ ntohs(top->header.length)); ++ zlog_debug(" Address: %pI4", &top->value); ++ } + + return TLV_SIZE(tlvh); + } +@@ -1754,14 +1761,28 @@ static uint16_t show_vty_ext_link_adj_si + + check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID"); + +- vty_out(vty, +- " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n", +- ntohs(top->header.length), top->flags, top->mtid, top->weight, +- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" +- : "Index", +- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) +- ? GET_LABEL(ntohl(top->value)) +- : ntohl(top->value)); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n", ++ ntohs(top->header.length), top->flags, top->mtid, top->weight, ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } else { ++ zlog_debug(" Adj-SID Sub-TLV: Length %u", ntohs(top->header.length)); ++ zlog_debug(" Flags: 0x%x", top->flags); ++ zlog_debug(" MT-ID:0x%x", top->mtid); ++ zlog_debug(" Weight: 0x%x", top->weight); ++ zlog_debug(" %s: %u", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } +@@ -1775,15 +1796,30 @@ static uint16_t show_vty_ext_link_lan_ad + + check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID"); + +- vty_out(vty, +- " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n", +- ntohs(top->header.length), top->flags, top->mtid, top->weight, +- &top->neighbor_id, +- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" +- : "Index", +- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) +- ? GET_LABEL(ntohl(top->value)) +- : ntohl(top->value)); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n", ++ ntohs(top->header.length), top->flags, top->mtid, top->weight, ++ &top->neighbor_id, ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } else { ++ zlog_debug(" LAN-Adj-SID Sub-TLV: Length %u", ntohs(top->header.length)); ++ zlog_debug(" Flags: 0x%x", top->flags); ++ zlog_debug(" MT-ID:0x%x", top->mtid); ++ zlog_debug(" Weight: 0x%x", top->weight); ++ zlog_debug(" Neighbor ID: %pI4", &top->neighbor_id); ++ zlog_debug(" %s: %u", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } +@@ -1791,14 +1827,24 @@ static uint16_t show_vty_ext_link_lan_ad + static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, + size_t buf_size) + { ++ /* If vty is not available, dump info via zlog. */ + if (TLV_SIZE(tlvh) > buf_size) { +- vty_out(vty, " TLV size %d exceeds buffer size. Abort!", +- TLV_SIZE(tlvh)); ++ if (vty != NULL) ++ vty_out(vty, " TLV size %d exceeds buffer size. Abort!", ++ TLV_SIZE(tlvh)); ++ else ++ zlog_debug(" TLV size %d exceeds buffer size. Abort!", ++ TLV_SIZE(tlvh)); + return buf_size; + } + +- vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", +- ntohs(tlvh->type), ntohs(tlvh->length)); ++ if (vty != NULL) { ++ vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", ++ ntohs(tlvh->type), ntohs(tlvh->length)); ++ } else { ++ zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", ++ ntohs(tlvh->type), ntohs(tlvh->length)); ++ } + + return TLV_SIZE(tlvh); + } +@@ -1814,18 +1860,32 @@ static uint16_t show_vty_link_info(struc + + /* Verify that TLV length is valid against remaining buffer size */ + if (length > buf_size) { +- vty_out(vty, +- " Extended Link TLV size %d exceeds buffer size. Abort!\n", +- length); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Extended Link TLV size %d exceeds buffer size. Abort!\n", ++ length); ++ } else { ++ zlog_debug(" Extended Link TLV size %d exceeds buffer size. Abort!", ++ length); ++ } + return buf_size; + } + +- vty_out(vty, +- " Extended Link TLV: Length %u\n Link Type: 0x%x\n" +- " Link ID: %pI4\n", +- ntohs(top->header.length), top->link_type, +- &top->link_id); +- vty_out(vty, " Link data: %pI4\n", &top->link_data); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Extended Link TLV: Length %u\n Link Type: 0x%x\n" ++ " Link ID: %pI4\n", ++ ntohs(top->header.length), top->link_type, ++ &top->link_id); ++ vty_out(vty, " Link data: %pI4\n", &top->link_data); ++ } else { ++ zlog_debug(" Extended Link TLV: Length %u", ntohs(top->header.length)); ++ zlog_debug(" Link Type: 0x%x", top->link_type); ++ zlog_debug(" Link ID: %pI4", &top->link_id); ++ zlog_debug(" Link data: %pI4", &top->link_data); ++ } + + /* Skip Extended TLV and parse sub-TLVs */ + length -= EXT_TLV_LINK_SIZE; +@@ -1887,15 +1947,29 @@ static uint16_t show_vty_ext_pref_pref_s + + check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID"); + +- vty_out(vty, +- " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n", +- ntohs(top->header.length), top->algorithm, top->flags, +- top->mtid, +- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label" +- : "Index", +- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) +- ? GET_LABEL(ntohl(top->value)) +- : ntohl(top->value)); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n", ++ ntohs(top->header.length), top->algorithm, top->flags, ++ top->mtid, ++ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } else { ++ zlog_debug(" Prefix SID Sub-TLV: Length %u", ntohs(top->header.length)); ++ zlog_debug(" Algorithm: %u", top->algorithm); ++ zlog_debug(" Flags: 0x%x", top->flags); ++ zlog_debug(" MT-ID:0x%x", top->mtid); ++ zlog_debug(" %s: %u", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label" ++ : "Index", ++ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ++ ? GET_LABEL(ntohl(top->value)) ++ : ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } +@@ -1911,17 +1985,32 @@ static uint16_t show_vty_pref_info(struc + + /* Verify that TLV length is valid against remaining buffer size */ + if (length > buf_size) { +- vty_out(vty, +- " Extended Link TLV size %d exceeds buffer size. Abort!\n", +- length); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Extended Link TLV size %d exceeds buffer size. Abort!\n", ++ length); ++ } else { ++ zlog_debug(" Extended Link TLV size %d exceeds buffer size. Abort!", ++ length); ++ } + return buf_size; + } + +- vty_out(vty, +- " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n" +- "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n", +- ntohs(top->header.length), top->route_type, top->af, top->flags, +- &top->address, top->pref_length); ++ /* If vty is not available, dump info via zlog. */ ++ if (vty != NULL) { ++ vty_out(vty, ++ " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n" ++ "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n", ++ ntohs(top->header.length), top->route_type, top->af, top->flags, ++ &top->address, top->pref_length); ++ } else { ++ zlog_debug(" Extended Prefix TLV: Length %u", ntohs(top->header.length)); ++ zlog_debug(" Route Type: %u", top->route_type); ++ zlog_debug(" Address Family: 0x%x", top->af); ++ zlog_debug(" Flags: 0x%x", top->flags); ++ zlog_debug(" Address: %pI4/%u", &top->address, top->pref_length); ++ } + + /* Skip Extended Prefix TLV and parse sub-TLVs */ + length -= EXT_TLV_PREFIX_SIZE; diff -Nru frr-8.4.4/debian/patches/CVE-2025-61104.patch frr-8.4.4/debian/patches/CVE-2025-61104.patch --- frr-8.4.4/debian/patches/CVE-2025-61104.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2025-61104.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,29 @@ +Description: ospfd: add NULL check for vty_out in check_tlv_size + Companion to CVE-2025-61099.patch: guard the vty_out() call in check_tlv_size() + in ospf_ext.c so the OSPF Opaque LSA detail dump path does not dereference a + NULL vty (CVE-2025-61104). +Origin: backport, https://github.com/FRRouting/frr/commit/b7d9b7aa47627b31e4b50795284408ab6de98660 +Bug: https://github.com/FRRouting/frr/issues/19471 +Forwarded: not-needed +Index: b/ospfd/ospf_ext.c +=================================================================== +--- a/ospfd/ospf_ext.c ++++ b/ospfd/ospf_ext.c +@@ -1717,11 +1717,15 @@ static void ospf_ext_lsa_schedule(struct + * ------------------------------------ + */ + ++/* Check NULL for vty. If vty is not available, dump info via zlog */ + #define check_tlv_size(size, msg) \ + do { \ + if (ntohs(tlvh->length) != size) { \ +- vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \ +- msg, ntohs(tlvh->length), size); \ ++ if (vty != NULL) \ ++ vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \ ++ msg, ntohs(tlvh->length), size); \ ++ else \ ++ zlog_debug(" Wrong %s TLV size: %d(%d). Abort!", msg, ntohs(tlvh->length), size); \ + return size + TLV_HDR_SIZE; \ + } \ + } while (0) diff -Nru frr-8.4.4/debian/patches/CVE-2026-28532.patch frr-8.4.4/debian/patches/CVE-2026-28532.patch --- frr-8.4.4/debian/patches/CVE-2026-28532.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2026-28532.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,292 @@ +Description: harden OSPF TE/SR TLV iteration against malformed lengths + A uint16_t accumulator truncated uint32_t TLV_SIZE() values in the OSPF TE/SR + TLV parsers (ospf_te.c, ospf_sr.c), so a crafted Opaque LSA with malformed TLV + lengths could make the loop terminator fail while the read pointer advanced, + causing an out-of-bounds read / ospfd crash (CVE-2026-28532). + . + Backported from upstream master commit d3e8aedb87; the ospf_te_delete_te() hunk + was adapted by hand because 8.4.4 still uses a uint64_t edge key instead of the + newer struct ls_edge_key. +Origin: backport, https://github.com/FRRouting/frr/commit/d3e8aedb87671f38db59b0df908e25e1d4af027d +Bug: https://github.com/FRRouting/frr/pull/21002 +Forwarded: not-needed +Index: b/ospfd/ospf_sr.c +=================================================================== +--- a/ospfd/ospf_sr.c ++++ b/ospfd/ospf_sr.c +@@ -1000,7 +1000,8 @@ static struct sr_link *get_ext_link_sid( + 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) +@@ -1015,7 +1016,15 @@ static struct sr_link *get_ext_link_sid( + 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; +@@ -1056,7 +1065,9 @@ static struct sr_link *get_ext_link_sid( + 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); +@@ -1077,7 +1088,7 @@ static struct sr_prefix *get_ext_prefix_ + 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) +@@ -1092,7 +1103,15 @@ static struct sr_prefix *get_ext_prefix_ + 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; +@@ -1117,7 +1136,9 @@ static struct sr_prefix *get_ext_prefix_ + 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, +@@ -1379,7 +1400,7 @@ void ospf_sr_ri_lsa_update(struct ospf_l + 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", +@@ -1407,8 +1428,15 @@ void ospf_sr_ri_lsa_update(struct ospf_l + 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; +@@ -1425,7 +1453,9 @@ void ospf_sr_ri_lsa_update(struct ospf_l + 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 */ +Index: b/ospfd/ospf_te.c +=================================================================== +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -2152,7 +2152,7 @@ static int ospf_te_parse_te(struct ls_te + 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 */ +@@ -2182,11 +2182,19 @@ static int ospf_te_parse_te(struct ls_te + + 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: +@@ -2281,7 +2289,9 @@ static int ospf_te_parse_te(struct ls_te + 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 */ +@@ -2381,7 +2391,7 @@ static int ospf_te_delete_te(struct ls_t + struct tlv_header *tlvh; + struct in_addr addr; + uint64_t key = 0; +- uint16_t len, sum; ++ uint32_t len, sum; + uint8_t lsa_id; + + /* Initialize TLV browsing */ +@@ -2393,13 +2403,24 @@ static int ospf_te_delete_te(struct ls_t + 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 = ((uint64_t)ntohl(addr.s_addr)) & 0xffffffff; + break; + } +- sum += TLV_SIZE(tlvh); ++ sum += tlv_size; ++ if (sum < len) ++ tlvh = TLV_HDR_NEXT(tlvh); + } + if (key == 0) + return 0; +@@ -2472,7 +2493,7 @@ static int ospf_te_parse_ri(struct ls_te + 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); +@@ -2483,13 +2504,18 @@ static int ospf_te_parse_ri(struct ls_te + + /* 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 || +@@ -2574,7 +2600,9 @@ static int ospf_te_parse_ri(struct ls_te + 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 */ +@@ -2786,7 +2814,8 @@ static int ospf_te_parse_ext_link(struct + 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 */ +@@ -2820,11 +2849,18 @@ static int ospf_te_parse_ext_link(struct + 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) +@@ -2903,7 +2939,9 @@ static int ospf_te_parse_ext_link(struct + default: + break; + } +- sum += TLV_SIZE(tlvh); ++ sum += tlv_size; ++ if (sum < len) ++ tlvh = TLV_HDR_NEXT(tlvh); + } + + /* Export Link State Edge if needed */ diff -Nru frr-8.4.4/debian/patches/CVE-2026-37457.patch frr-8.4.4/debian/patches/CVE-2026-37457.patch --- frr-8.4.4/debian/patches/CVE-2026-37457.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2026-37457.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,36 @@ +Description: fix off-by-one out-of-bounds write in FlowSpec operator array + An off-by-one error in the FlowSpec operator decoding (bgp_flowspec_op_decode / + bgp_flowspec_bitmask_decode) allows a crafted FlowSpec NLRI with more than the + maximum number of chained operators to write one element past the mval[] array, + leading to a stack out-of-bounds write (CVE-2026-37457). +Origin: backport, https://github.com/FRRouting/frr/commit/0e6882bc72c0278988a47b2f0f73b7a91099a25c +Bug: https://github.com/FRRouting/frr/pull/21054 +Forwarded: not-needed +Index: b/bgpd/bgp_flowspec_util.c +=================================================================== +--- a/bgpd/bgp_flowspec_util.c ++++ b/bgpd/bgp_flowspec_util.c +@@ -261,8 +261,10 @@ int bgp_flowspec_op_decode(enum bgp_flow + + *error = 0; + do { +- if (loop > BGP_PBR_MATCH_VAL_MAX) ++ if (loop >= BGP_PBR_MATCH_VAL_MAX) { + *error = -2; ++ return offset; ++ } + hex2bin(&nlri_ptr[offset], op); + offset++; + len = 2*op[2]+op[3]; +@@ -365,8 +367,10 @@ int bgp_flowspec_bitmask_decode(enum bgp + + *error = 0; + do { +- if (loop > BGP_PBR_MATCH_VAL_MAX) ++ if (loop >= BGP_PBR_MATCH_VAL_MAX) { + *error = -2; ++ return offset; ++ } + hex2bin(&nlri_ptr[offset], op); + /* if first element, AND bit can not be set */ + if (op[1] == 1 && loop == 0) diff -Nru frr-8.4.4/debian/patches/CVE-2026-37458.patch frr-8.4.4/debian/patches/CVE-2026-37458.patch --- frr-8.4.4/debian/patches/CVE-2026-37458.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2026-37458.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,30 @@ +Description: validate MP_REACH_NLRI attribute against incorrect next-hop + The IPv4 next-hop carried in an MP_REACH_NLRI attribute was not validated, so + a martian next-hop was accepted and could cause a denial of service. Reject the + attribute (treat-as-withdraw) when the next-hop is a martian address, unless + the operator explicitly allowed martian next-hops (CVE-2026-37458). +Origin: backport, https://github.com/FRRouting/frr/commit/8102a8aeceb9f86fdfe1f80cd77080522bab69c8 +Bug: https://github.com/FRRouting/frr/pull/21075 +Forwarded: not-needed +Index: b/bgpd/bgp_attr.c +=================================================================== +--- a/bgpd/bgp_attr.c ++++ b/bgpd/bgp_attr.c +@@ -2138,6 +2138,17 @@ int bgp_mp_reach_parse(struct bgp_attr_p + /* FALLTHRU */ + case BGP_ATTR_NHLEN_IPV4: + stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); ++ ++ /* We do already the same validation for NEXT_HOP attribute, ++ * so let's do it here as well for consistency and to avoid potential ++ * security issues with martian addresses in MP_REACH_NLRI. ++ */ ++ if (ipv4_martian(&attr->mp_nexthop_global_in) && !peer->bgp->allow_martian) { ++ zlog_warn("%s sent martian nexthop %pI4 in MP_REACH_NLRI", peer->host, ++ &attr->mp_nexthop_global_in); ++ return BGP_ATTR_PARSE_WITHDRAW; ++ } ++ + /* Probably needed for RFC 2283 */ + if (attr->nexthop.s_addr == INADDR_ANY) + memcpy(&attr->nexthop.s_addr, diff -Nru frr-8.4.4/debian/patches/CVE-2026-5107.patch frr-8.4.4/debian/patches/CVE-2026-5107.patch --- frr-8.4.4/debian/patches/CVE-2026-5107.patch 1970-01-01 00:00:00.000000000 +0000 +++ frr-8.4.4/debian/patches/CVE-2026-5107.patch 2026-06-02 07:30:27.000000000 +0000 @@ -0,0 +1,85 @@ +Description: improve packet parsing for EVPN and ENCAP/VNC + Missing validation of the EVPN NLRI ipaddr_len against psize in the EVPN + Type-2/3/4 route handlers (and a VNC/ENCAP sub-TLV length check) allowed + crafted BGP UPDATE messages to manipulate routes or trigger a limited DoS + (CVE-2026-5107). Hand-ported from upstream to the 8.4.4 EVPN code. +Origin: backport, https://github.com/FRRouting/frr/commit/7676cad65114aa23adde583d91d9d29e2debd045 +Bug: https://github.com/FRRouting/frr/pull/21098 +Forwarded: not-needed +Index: b/bgpd/bgp_evpn.c +=================================================================== +--- a/bgpd/bgp_evpn.c ++++ b/bgpd/bgp_evpn.c +@@ -3905,6 +3905,14 @@ static int process_type2_route(struct pe + goto fail; + } + ++ /* Validate ipaddr_len against the NLRI length */ ++ if ((psize != 33 + (ipaddr_len / 8)) && (psize != 36 + (ipaddr_len / 8))) { ++ flog_err(EC_BGP_EVPN_ROUTE_INVALID, ++ "%u:%s - Rx EVPN Type-2 NLRI with invalid IP address length %d", ++ peer->bgp->vrf_id, peer->host, ipaddr_len); ++ goto fail; ++ } ++ + if (ipaddr_len) { + ipaddr_len /= 8; /* Convert to bytes. */ + p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN) +@@ -4004,6 +4012,15 @@ static int process_type3_route(struct pe + + /* Get the IP. */ + ipaddr_len = *pfx++; ++ ++ /* Validate */ ++ if (psize != 13 + (ipaddr_len / 8)) { ++ flog_err(EC_BGP_EVPN_ROUTE_INVALID, ++ "%u:%s - Rx EVPN Type-3 NLRI with invalid IP address length %d", ++ peer->bgp->vrf_id, peer->host, ipaddr_len); ++ return -1; ++ } ++ + if (ipaddr_len == IPV4_MAX_BITLEN) { + p.prefix.imet_addr.ip.ipa_type = IPADDR_V4; + memcpy(&p.prefix.imet_addr.ip.ip.addr, pfx, IPV4_MAX_BYTELEN); +Index: b/bgpd/bgp_evpn_mh.c +=================================================================== +--- a/bgpd/bgp_evpn_mh.c ++++ b/bgpd/bgp_evpn_mh.c +@@ -734,9 +734,17 @@ int bgp_evpn_type4_route_process(struct + memcpy(&esi, pfx, ESI_BYTES); + pfx += ESI_BYTES; + +- + /* Get the IP. */ + ipaddr_len = *pfx++; ++ ++ /* Validate */ ++ if (psize != 19 + (ipaddr_len / 8)) { ++ flog_err(EC_BGP_EVPN_ROUTE_INVALID, ++ "%u:%s - Rx EVPN Type-4 NLRI with invalid IP address length %d", ++ peer->bgp->vrf_id, peer->host, ipaddr_len); ++ return -1; ++ } ++ + if (ipaddr_len == IPV4_MAX_BITLEN) { + memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN); + } else { +Index: b/bgpd/rfapi/rfapi_rib.c +=================================================================== +--- a/bgpd/rfapi/rfapi_rib.c ++++ b/bgpd/rfapi/rfapi_rib.c +@@ -629,6 +629,14 @@ static void rfapiRibBi2Ri(struct bgp_pat + break; + + case BGP_VNC_SUBTLV_TYPE_RFPOPTION: ++ /* Check for short subtlv: drop */ ++ if (pEncap->length < 3) ++ break; ++ ++ /* Length of zero not valid */ ++ if (pEncap->value[1] == 0) ++ break; ++ + hop = XCALLOC(MTYPE_BGP_TEA_OPTIONS, + sizeof(struct bgp_tea_options)); + assert(hop); diff -Nru frr-8.4.4/debian/patches/series frr-8.4.4/debian/patches/series --- frr-8.4.4/debian/patches/series 2023-09-01 08:56:56.000000000 +0000 +++ frr-8.4.4/debian/patches/series 2026-06-02 07:30:27.000000000 +0000 @@ -1,3 +1,14 @@ CVE-2023-38802.patch CVE-2023-41358.patch CVE-2023-41360.patch +CVE-2023-3748.patch +CVE-2024-27913.patch +CVE-2024-31950.patch +CVE-2024-31951.patch +CVE-2024-34088.patch +CVE-2026-37458.patch +CVE-2025-61104.patch +CVE-2026-37457.patch +CVE-2026-28532.patch +CVE-2026-5107.patch +CVE-2025-61099_61107.patch