diff options
| author | Ankur Tyagi <ankur.tyagi85@gmail.com> | 2026-05-13 17:04:45 +1200 |
|---|---|---|
| committer | Anuj Mittal <anuj.mittal@oss.qualcomm.com> | 2026-05-21 08:57:45 +0530 |
| commit | fdd887bc2979ae4d1666d1fb5750c60201622ef2 (patch) | |
| tree | caca3b9457a6666b4bbc1f2928f944ccdef26b43 | |
| parent | 764a8f2154aa26b3716c12ace1119115d15768a9 (diff) | |
| download | meta-openembedded-fdd887bc2979ae4d1666d1fb5750c60201622ef2.tar.gz | |
frr: patch CVE-2026-28532
Details: https://nvd.nist.gov/vuln/detail/CVE-2026-28532
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
| -rw-r--r-- | meta-networking/recipes-protocols/frr/frr/CVE-2026-28532.patch | 309 | ||||
| -rw-r--r-- | meta-networking/recipes-protocols/frr/frr_9.1.3.bb | 1 |
2 files changed, 310 insertions, 0 deletions
diff --git a/meta-networking/recipes-protocols/frr/frr/CVE-2026-28532.patch b/meta-networking/recipes-protocols/frr/frr/CVE-2026-28532.patch new file mode 100644 index 0000000000..39f5f569de --- /dev/null +++ b/meta-networking/recipes-protocols/frr/frr/CVE-2026-28532.patch | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | From ea6982fe2ae7db40b0ea0ec42c283eb3b3178798 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jafar Al-Gharaibeh <jafar@atcorp.com> | ||
| 3 | Date: Wed, 4 Mar 2026 12:38:46 -0600 | ||
| 4 | Subject: [PATCH] ospfd: harden TE/SR TLV iteration against malformed lengths | ||
| 5 | |||
| 6 | Use 32-bit counters and per-iteration TLV size bounds checks | ||
| 7 | in OSPF TE/SR TLV parsers so malformed opaque LSAs cannot wrap | ||
| 8 | loop accounting and advance pointers beyond the LSA buffer. | ||
| 9 | |||
| 10 | - Change loop accumulators from 16-bit to 32-bit (uint32_t) to | ||
| 11 | prevent wraparound | ||
| 12 | - Rework TLV iteration so pointer advancement is controlled in-loop | ||
| 13 | - Add per-iteration guard before advancing: | ||
| 14 | - `tlv_size <= (len - sum)` (or `length - sum`) | ||
| 15 | - On malformed size, parser now logs and exits/breaks the loop | ||
| 16 | safely instead of stepping past buffer limits | ||
| 17 | |||
| 18 | Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com> | ||
| 19 | (cherry picked from commit d3e8aedb87671f38db59b0df908e25e1d4af027d) | ||
| 20 | |||
| 21 | CVE: CVE-2026-28532 | ||
| 22 | Upstream-Status: Backport [https://github.com/FRRouting/frr/commit/d3e8aedb87671f38db59b0df908e25e1d4af027d] | ||
| 23 | Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com> | ||
| 24 | --- | ||
| 25 | ospfd/ospf_sr.c | 50 ++++++++++++++++++++++++++++++-------- | ||
| 26 | ospfd/ospf_te.c | 64 +++++++++++++++++++++++++++++++++++++++---------- | ||
| 27 | 2 files changed, 91 insertions(+), 23 deletions(-) | ||
| 28 | |||
| 29 | diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c | ||
| 30 | index e26fe6f53a..11ca362a1b 100644 | ||
| 31 | --- a/ospfd/ospf_sr.c | ||
| 32 | +++ b/ospfd/ospf_sr.c | ||
| 33 | @@ -985,7 +985,8 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) | ||
| 34 | struct ext_subtlv_rmt_itf_addr *rmt_itf; | ||
| 35 | |||
| 36 | struct tlv_header *sub_tlvh; | ||
| 37 | - uint16_t length = 0, sum = 0, i = 0; | ||
| 38 | + uint32_t length = 0, sum = 0; | ||
| 39 | + uint16_t i = 0; | ||
| 40 | |||
| 41 | /* Check TLV size */ | ||
| 42 | if ((ntohs(tlvh->length) > size) | ||
| 43 | @@ -1000,7 +1001,15 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) | ||
| 44 | length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE; | ||
| 45 | sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE | ||
| 46 | + EXT_TLV_LINK_SIZE); | ||
| 47 | - for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { | ||
| 48 | + for (; sum < length && sub_tlvh;) { | ||
| 49 | + uint32_t tlv_size = TLV_SIZE(sub_tlvh); | ||
| 50 | + | ||
| 51 | + if (tlv_size > length - sum) { | ||
| 52 | + zlog_warn("Malformed Extended Link sub-TLV size %u (remaining %u)", | ||
| 53 | + tlv_size, length - sum); | ||
| 54 | + break; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | switch (ntohs(sub_tlvh->type)) { | ||
| 58 | case EXT_SUBTLV_ADJ_SID: | ||
| 59 | adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh; | ||
| 60 | @@ -1041,7 +1050,9 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) | ||
| 61 | default: | ||
| 62 | break; | ||
| 63 | } | ||
| 64 | - sum += TLV_SIZE(sub_tlvh); | ||
| 65 | + sum += tlv_size; | ||
| 66 | + if (sum < length) | ||
| 67 | + sub_tlvh = TLV_HDR_NEXT(sub_tlvh); | ||
| 68 | } | ||
| 69 | |||
| 70 | IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data); | ||
| 71 | @@ -1062,7 +1073,7 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, | ||
| 72 | struct ext_subtlv_prefix_sid *psid; | ||
| 73 | |||
| 74 | struct tlv_header *sub_tlvh; | ||
| 75 | - uint16_t length = 0, sum = 0; | ||
| 76 | + uint32_t length = 0, sum = 0; | ||
| 77 | |||
| 78 | /* Check TLV size */ | ||
| 79 | if ((ntohs(tlvh->length) > size) | ||
| 80 | @@ -1077,7 +1088,15 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, | ||
| 81 | length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE; | ||
| 82 | sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE | ||
| 83 | + EXT_TLV_PREFIX_SIZE); | ||
| 84 | - for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { | ||
| 85 | + for (; sum < length && sub_tlvh;) { | ||
| 86 | + uint32_t tlv_size = TLV_SIZE(sub_tlvh); | ||
| 87 | + | ||
| 88 | + if (tlv_size > length - sum) { | ||
| 89 | + zlog_warn("Malformed Extended Prefix sub-TLV size %u (remaining %u)", | ||
| 90 | + tlv_size, length - sum); | ||
| 91 | + break; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | switch (ntohs(sub_tlvh->type)) { | ||
| 95 | case EXT_SUBTLV_PREFIX_SID: | ||
| 96 | psid = (struct ext_subtlv_prefix_sid *)sub_tlvh; | ||
| 97 | @@ -1102,7 +1121,9 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, | ||
| 98 | default: | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | - sum += TLV_SIZE(sub_tlvh); | ||
| 102 | + sum += tlv_size; | ||
| 103 | + if (sum < length) | ||
| 104 | + sub_tlvh = TLV_HDR_NEXT(sub_tlvh); | ||
| 105 | } | ||
| 106 | |||
| 107 | osr_debug(" |- Found SID %u for prefix %pFX", srp->sid, | ||
| 108 | @@ -1364,7 +1385,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) | ||
| 109 | struct ri_sr_tlv_sid_label_range *ri_srlb = NULL; | ||
| 110 | struct ri_sr_tlv_sr_algorithm *algo = NULL; | ||
| 111 | struct sr_block srgb; | ||
| 112 | - uint16_t length = 0, sum = 0; | ||
| 113 | + uint32_t length = 0, sum = 0; | ||
| 114 | uint8_t msd = 0; | ||
| 115 | |||
| 116 | osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4", | ||
| 117 | @@ -1392,8 +1413,15 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) | ||
| 118 | srgb.range_size = 0; | ||
| 119 | srgb.lower_bound = 0; | ||
| 120 | |||
| 121 | - for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL); | ||
| 122 | - tlvh = TLV_HDR_NEXT(tlvh)) { | ||
| 123 | + for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);) { | ||
| 124 | + uint32_t tlv_size = TLV_SIZE(tlvh); | ||
| 125 | + | ||
| 126 | + if (tlv_size > length - sum) { | ||
| 127 | + zlog_warn("Malformed RI TLV size %u (remaining %u)", tlv_size, | ||
| 128 | + length - sum); | ||
| 129 | + break; | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | switch (ntohs(tlvh->type)) { | ||
| 133 | case RI_SR_TLV_SR_ALGORITHM: | ||
| 134 | algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; | ||
| 135 | @@ -1410,7 +1438,9 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) | ||
| 136 | default: | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | - sum += TLV_SIZE(tlvh); | ||
| 140 | + sum += tlv_size; | ||
| 141 | + if (sum < length) | ||
| 142 | + tlvh = TLV_HDR_NEXT(tlvh); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* Check if Segment Routing Capabilities has been found */ | ||
| 146 | diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c | ||
| 147 | index 1bddf97bde..8d01e4fd1d 100644 | ||
| 148 | --- a/ospfd/ospf_te.c | ||
| 149 | +++ b/ospfd/ospf_te.c | ||
| 150 | @@ -2121,7 +2121,7 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 151 | struct ls_attributes *old, attr = {}; | ||
| 152 | struct tlv_header *tlvh; | ||
| 153 | void *value; | ||
| 154 | - uint16_t len, sum; | ||
| 155 | + uint32_t len, sum; | ||
| 156 | uint8_t lsa_id; | ||
| 157 | |||
| 158 | /* Initialize Attribute */ | ||
| 159 | @@ -2151,11 +2151,19 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 160 | |||
| 161 | sum = sizeof(struct tlv_header); | ||
| 162 | /* Browse sub-TLV and fulfill Link State Attributes */ | ||
| 163 | - for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | ||
| 164 | + tlvh = TLV_DATA(tlvh); | ||
| 165 | + while (sum < len) { | ||
| 166 | + uint32_t tlv_size = TLV_SIZE(tlvh); | ||
| 167 | uint32_t val32, tab32[2]; | ||
| 168 | float valf, tabf[8]; | ||
| 169 | struct in_addr addr; | ||
| 170 | |||
| 171 | + if (tlv_size > len - sum) { | ||
| 172 | + zlog_warn("Malformed TE sub-TLV size %u (remaining %u)", tlv_size, | ||
| 173 | + len - sum); | ||
| 174 | + break; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | value = TLV_DATA(tlvh); | ||
| 178 | switch (ntohs(tlvh->type)) { | ||
| 179 | case TE_LINK_SUBTLV_LCLIF_IPADDR: | ||
| 180 | @@ -2250,7 +2258,9 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 181 | default: | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | - sum += TLV_SIZE(tlvh); | ||
| 185 | + sum += tlv_size; | ||
| 186 | + if (sum < len) | ||
| 187 | + tlvh = TLV_HDR_NEXT(tlvh); | ||
| 188 | } | ||
| 189 | |||
| 190 | /* Get corresponding Edge from Link State Data Base */ | ||
| 191 | @@ -2350,7 +2360,7 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 192 | struct tlv_header *tlvh; | ||
| 193 | struct in_addr addr; | ||
| 194 | struct ls_edge_key key = {.family = AF_UNSPEC}; | ||
| 195 | - uint16_t len, sum; | ||
| 196 | + uint32_t len, sum; | ||
| 197 | uint8_t lsa_id; | ||
| 198 | |||
| 199 | /* Initialize TLV browsing */ | ||
| 200 | @@ -2362,14 +2372,25 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 201 | sum = sizeof(struct tlv_header); | ||
| 202 | |||
| 203 | /* Browse sub-TLV to find Link ID */ | ||
| 204 | - for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | ||
| 205 | + tlvh = TLV_DATA(tlvh); | ||
| 206 | + while (sum < len) { | ||
| 207 | + uint32_t tlv_size = TLV_SIZE(tlvh); | ||
| 208 | + | ||
| 209 | + if (tlv_size > len - sum) { | ||
| 210 | + zlog_warn("Malformed TE sub-TLV size %u (remaining %u)", tlv_size, | ||
| 211 | + len - sum); | ||
| 212 | + break; | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | if (ntohs(tlvh->type) == TE_LINK_SUBTLV_LCLIF_IPADDR) { | ||
| 216 | memcpy(&addr, TLV_DATA(tlvh), TE_LINK_SUBTLV_DEF_SIZE); | ||
| 217 | key.family = AF_INET; | ||
| 218 | IPV4_ADDR_COPY(&key.k.addr, &addr); | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | - sum += TLV_SIZE(tlvh); | ||
| 222 | + sum += tlv_size; | ||
| 223 | + if (sum < len) | ||
| 224 | + tlvh = TLV_HDR_NEXT(tlvh); | ||
| 225 | } | ||
| 226 | if (key.family == AF_UNSPEC) | ||
| 227 | return 0; | ||
| 228 | @@ -2444,7 +2465,7 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 229 | struct ls_node *node; | ||
| 230 | struct lsa_header *lsah = lsa->data; | ||
| 231 | struct tlv_header *tlvh; | ||
| 232 | - uint16_t len = 0, sum = 0; | ||
| 233 | + uint32_t len = 0, sum = 0; | ||
| 234 | |||
| 235 | /* Get vertex / Node from LSA Advertised Router ID */ | ||
| 236 | vertex = get_vertex(ted, lsa); | ||
| 237 | @@ -2455,13 +2476,18 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 238 | |||
| 239 | /* Initialize TLV browsing */ | ||
| 240 | len = lsa->size - OSPF_LSA_HEADER_SIZE; | ||
| 241 | - for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh; | ||
| 242 | - tlvh = TLV_HDR_NEXT(tlvh)) { | ||
| 243 | + for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh;) { | ||
| 244 | + uint32_t tlv_size = TLV_SIZE(tlvh); | ||
| 245 | struct ri_sr_tlv_sr_algorithm *algo; | ||
| 246 | struct ri_sr_tlv_sid_label_range *range; | ||
| 247 | struct ri_sr_tlv_node_msd *msd; | ||
| 248 | uint32_t size, lower; | ||
| 249 | |||
| 250 | + if (tlv_size > len - sum) { | ||
| 251 | + zlog_warn("Malformed RI TLV size %u (remaining %u)", tlv_size, len - sum); | ||
| 252 | + break; | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | switch (ntohs(tlvh->type)) { | ||
| 256 | case RI_SR_TLV_SR_ALGORITHM: | ||
| 257 | if (TLV_BODY_SIZE(tlvh) < 1 || | ||
| 258 | @@ -2546,7 +2572,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 259 | default: | ||
| 260 | break; | ||
| 261 | } | ||
| 262 | - sum += TLV_SIZE(tlvh); | ||
| 263 | + sum += tlv_size; | ||
| 264 | + if (sum < len) | ||
| 265 | + tlvh = TLV_HDR_NEXT(tlvh); | ||
| 266 | } | ||
| 267 | |||
| 268 | /* Vertex has been created or updated: export it */ | ||
| 269 | @@ -2758,7 +2786,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 270 | struct ext_tlv_link *ext; | ||
| 271 | struct ls_edge *edge; | ||
| 272 | struct ls_attributes *atr; | ||
| 273 | - uint16_t len = 0, sum = 0, i; | ||
| 274 | + uint32_t len = 0, sum = 0; | ||
| 275 | + uint16_t i; | ||
| 276 | uint32_t label; | ||
| 277 | |||
| 278 | /* Get corresponding Edge from Link State Data Base */ | ||
| 279 | @@ -2792,11 +2821,18 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 280 | len -= EXT_TLV_LINK_SIZE; | ||
| 281 | tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE | ||
| 282 | + EXT_TLV_LINK_SIZE); | ||
| 283 | - for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { | ||
| 284 | + for (; sum < len;) { | ||
| 285 | + uint32_t tlv_size = TLV_SIZE(tlvh); | ||
| 286 | struct ext_subtlv_adj_sid *adj; | ||
| 287 | struct ext_subtlv_lan_adj_sid *ladj; | ||
| 288 | struct ext_subtlv_rmt_itf_addr *rmt; | ||
| 289 | |||
| 290 | + if (tlv_size > len - sum) { | ||
| 291 | + zlog_warn("Malformed Extended Link sub-TLV size %u (remaining %u)", | ||
| 292 | + tlv_size, len - sum); | ||
| 293 | + break; | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | switch (ntohs(tlvh->type)) { | ||
| 297 | case EXT_SUBTLV_ADJ_SID: | ||
| 298 | if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_ADJ_SID_SIZE) | ||
| 299 | @@ -2875,7 +2911,9 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) | ||
| 300 | default: | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | - sum += TLV_SIZE(tlvh); | ||
| 304 | + sum += tlv_size; | ||
| 305 | + if (sum < len) | ||
| 306 | + tlvh = TLV_HDR_NEXT(tlvh); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* Export Link State Edge if needed */ | ||
diff --git a/meta-networking/recipes-protocols/frr/frr_9.1.3.bb b/meta-networking/recipes-protocols/frr/frr_9.1.3.bb index 0287a6fb69..20a224b7d7 100644 --- a/meta-networking/recipes-protocols/frr/frr_9.1.3.bb +++ b/meta-networking/recipes-protocols/frr/frr_9.1.3.bb | |||
| @@ -18,6 +18,7 @@ SRC_URI = "git://github.com/FRRouting/frr.git;protocol=https;branch=stable/9.1 \ | |||
| 18 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_2.patch \ | 18 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_2.patch \ |
| 19 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_3.patch \ | 19 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_3.patch \ |
| 20 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_4.patch \ | 20 | file://CVE-2025-61099-61100-61101-61102-61103-61104-61105-61106-61107_4.patch \ |
| 21 | file://CVE-2026-28532.patch \ | ||
| 21 | " | 22 | " |
| 22 | 23 | ||
| 23 | SRCREV = "ad1766d17be022587fe05ebe1a7bf10e1b7dce19" | 24 | SRCREV = "ad1766d17be022587fe05ebe1a7bf10e1b7dce19" |
