diff --git a/SPECS/frr/CVE-2025-61099.patch b/SPECS/frr/CVE-2025-61099.patch new file mode 100644 index 00000000000..bee20fef985 --- /dev/null +++ b/SPECS/frr/CVE-2025-61099.patch @@ -0,0 +1,583 @@ +From b7d9b7aa47627b31e4b50795284408ab6de98660 Mon Sep 17 00:00:00 2001 +From: s1awwhy +Date: Sun, 24 Aug 2025 21:17:55 +0800 +Subject: [PATCH] Address CVE-2025-61099 +[PATCH 1/4] ospfd: Add null check for vty_out in check_tlv_size +[PATCH 2/4] ospfd: Fix NULL Pointer Deference when dumping link info +[PATCH 3/4] ospfd: skip subsequent tlvs after invalid length +[PATCH 4/4] ospfd: reformat check_tlv_size macro + +Upstream Patch Reference: https://patch-diff.githubusercontent.com/raw/FRRouting/frr/pull/19983.patch +--- + ospfd/ospf_ext.c | 334 +++++++++++++++++++++++++++++++++++------------ + ospfd/ospf_ri.c | 23 ++-- + ospfd/ospf_te.c | 23 ++-- + 3 files changed, 278 insertions(+), 102 deletions(-) + +diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c +index 1288686..2e013fd 100644 +--- a/ospfd/ospf_ext.c ++++ b/ospfd/ospf_ext.c +@@ -44,6 +44,7 @@ + #include "network.h" + #include "if.h" + #include "libospf.h" /* for ospf interface types */ ++#include + + #include "ospfd/ospfd.h" + #include "ospfd/ospf_interface.h" +@@ -1717,111 +1718,222 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op) + * ------------------------------------ + */ + +-#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); \ +- return size + TLV_HDR_SIZE; \ +- } \ ++/* 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) { \ ++ if (vty != NULL) \ ++ vty_out(vty, \ ++ " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \ ++ msg, ntohs(tlvh->length), size); \ ++ else \ ++ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", \ ++ msg, ntohs(tlvh->length), size); \ ++ return OSPF_MAX_LSA_SIZE + 1; \ ++ } \ + } while (0) + + /* Cisco experimental SubTLV */ + static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty, +- struct tlv_header *tlvh) ++ struct tlv_header *tlvh, json_object *json) + { + struct ext_subtlv_rmt_itf_addr *top = + (struct ext_subtlv_rmt_itf_addr *)tlvh; + + 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 (!json) ++ 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); ++ } ++ else ++ json_object_string_addf(json, "remoteInterfaceAddress", "%pI4", ++ &top->value); + return TLV_SIZE(tlvh); + } + + /* Adjacency SID SubTLV */ + static uint16_t show_vty_ext_link_adj_sid(struct vty *vty, +- struct tlv_header *tlvh) ++ struct tlv_header *tlvh, json_object *json) + { + struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh; + + 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 (!json) { ++ /* Add security check for vty_out. 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)); ++ } ++ } else { ++ json_object_string_addf(json, "flags", "0x%x", top->flags); ++ json_object_string_addf(json, "mtID", "0x%x", top->mtid); ++ json_object_string_addf(json, "weight", "0x%x", top->weight); ++ if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)) ++ json_object_int_add(json, "label", ++ GET_LABEL(ntohl(top->value))); ++ else ++ json_object_int_add(json, "index", ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } + + /* LAN Adjacency SubTLV */ + static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty, +- struct tlv_header *tlvh) ++ struct tlv_header *tlvh, json_object *json) + { + struct ext_subtlv_lan_adj_sid *top = + (struct ext_subtlv_lan_adj_sid *)tlvh; + + 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 (!json) { ++ /* Add security check for vty_out. 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)); ++ } ++ } else { ++ json_object_string_addf(json, "flags", "0x%x", top->flags); ++ json_object_string_addf(json, "mtID", "0x%x", top->mtid); ++ json_object_string_addf(json, "weight", "0x%x", top->weight); ++ json_object_string_addf(json, "neighborID", "%pI4", ++ &top->neighbor_id); ++ if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)) ++ json_object_int_add(json, "label", ++ GET_LABEL(ntohl(top->value))); ++ else ++ json_object_int_add(json, "index", ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } + + static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, +- size_t buf_size) ++ size_t buf_size, json_object *json) + { ++ json_object *obj; ++ ++ /* Add security check for vty_out. 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 (!json) ++ 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)); ++ } ++ else { ++ obj = json_object_new_object(); ++ json_object_string_addf(obj, "type", "0x%x", ++ ntohs(tlvh->type)); ++ json_object_string_addf(obj, "length", "0x%x", ++ ntohs(tlvh->length)); ++ json_object_object_add(json, "unknownTLV", obj); ++ } + + return TLV_SIZE(tlvh); + } + + /* Extended Link Sub TLVs */ + static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, +- size_t buf_size) ++ size_t buf_size, json_object *json) + { + struct ext_tlv_link *top = (struct ext_tlv_link *)ext; + struct tlv_header *tlvh; + uint16_t length = ntohs(top->header.length); + uint16_t sum = 0; ++ json_object *jadj = NULL, *obj = NULL; + + /* 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); ++ /* Add security check for vty_out. 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 (!json) { ++ /* Add security check for vty_out. 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); ++ } ++ } else { ++ json_object_string_addf(json, "linkType", "0x%x", ++ top->link_type); ++ json_object_string_addf(json, "linkID", "%pI4", &top->link_id); ++ json_object_string_addf(json, "linkData", "%pI4", ++ &top->link_data); ++ jadj = json_object_new_array(); ++ json_object_object_add(json, "adjacencySID", jadj); ++ } ++ + + /* Skip Extended TLV and parse sub-TLVs */ + length -= EXT_TLV_LINK_SIZE; +@@ -1830,16 +1942,26 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, + for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case EXT_SUBTLV_ADJ_SID: +- sum += show_vty_ext_link_adj_sid(vty, tlvh); ++ if (json) { ++ obj = json_object_new_object(); ++ json_object_array_add(jadj, obj); ++ } else ++ obj = NULL; ++ sum += show_vty_ext_link_adj_sid(vty, tlvh, obj); + break; + case EXT_SUBTLV_LAN_ADJ_SID: +- sum += show_vty_ext_link_lan_adj_sid(vty, tlvh); ++ if (json) { ++ obj = json_object_new_object(); ++ json_object_array_add(jadj, obj); ++ } else ++ obj = NULL; ++ sum += show_vty_ext_link_lan_adj_sid(vty, tlvh, obj); + break; + case EXT_SUBTLV_RMT_ITF_ADDR: +- sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh); ++ sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh, json); + break; + default: +- sum += show_vty_unknown_tlv(vty, tlvh, length - sum); ++ sum += show_vty_unknown_tlv(vty, tlvh, length - sum, json); + break; + } + } +@@ -1854,9 +1976,12 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + struct lsa_header *lsah = lsa->data; + struct tlv_header *tlvh; + uint16_t length = 0, sum = 0; ++ json_object *jlink = NULL; + +- if (json) +- return; ++ if (json) { ++ jlink = json_object_new_object(); ++ json_object_object_add(json, "extendedLink", jlink); ++ } + + /* Initialize TLV browsing */ + length = lsa->size - OSPF_LSA_HEADER_SIZE; +@@ -1865,10 +1990,10 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case EXT_TLV_LINK: +- sum += show_vty_link_info(vty, tlvh, length - sum); ++ sum += show_vty_link_info(vty, tlvh, length - sum, jlink); + break; + default: +- sum += show_vty_unknown_tlv(vty, tlvh, length - sum); ++ sum += show_vty_unknown_tlv(vty, tlvh, length - sum, jlink); + break; + } + } +@@ -1876,48 +2001,94 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + + /* Prefix SID SubTLV */ + static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty, +- struct tlv_header *tlvh) ++ struct tlv_header *tlvh, json_object *json) + { + struct ext_subtlv_prefix_sid *top = + (struct ext_subtlv_prefix_sid *)tlvh; + + 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 (!json) { ++ 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)); ++ } ++ } else { ++ json_object_int_add(json, "algorithm", top->algorithm); ++ json_object_string_addf(json, "flags", "0x%x", top->flags); ++ json_object_string_addf(json, "mtID", "0x%x", top->mtid); ++ if (CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)) ++ json_object_int_add(json, "label", ++ GET_LABEL(ntohl(top->value))); ++ else ++ json_object_int_add(json, "index", ntohl(top->value)); ++ } + + return TLV_SIZE(tlvh); + } + + /* Extended Prefix SubTLVs */ + static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, +- size_t buf_size) ++ size_t buf_size, json_object *json) + { + struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext; + struct tlv_header *tlvh; + uint16_t length = ntohs(top->header.length); + uint16_t sum = 0; ++ json_object *jsid = NULL; + + /* 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 != 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 (!json) { ++ 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); ++ } ++ } else { ++ json_object_int_add(json, "routeType", top->route_type); ++ json_object_string_addf(json, "addressFamily", "0x%x", top->af); ++ json_object_string_addf(json, "flags", "0x%x", top->flags); ++ json_object_string_addf(json, "address", "%pI4", &top->address); ++ json_object_int_add(json, "prefixLength", top->pref_length); ++ jsid = json_object_new_object(); ++ json_object_object_add(json, "prefixSID", jsid); ++ } + + /* Skip Extended Prefix TLV and parse sub-TLVs */ + length -= EXT_TLV_PREFIX_SIZE; +@@ -1926,10 +2097,10 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, + for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case EXT_SUBTLV_PREFIX_SID: +- sum += show_vty_ext_pref_pref_sid(vty, tlvh); ++ sum += show_vty_ext_pref_pref_sid(vty, tlvh, jsid); + break; + default: +- sum += show_vty_unknown_tlv(vty, tlvh, length - sum); ++ sum += show_vty_unknown_tlv(vty, tlvh, length - sum, json); + break; + } + } +@@ -1944,9 +2115,12 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + struct lsa_header *lsah = lsa->data; + struct tlv_header *tlvh; + uint16_t length = 0, sum = 0; ++ json_object *jpref = NULL; + +- if (json) +- return; ++ if (json) { ++ jpref = json_object_new_object(); ++ json_object_object_add(json, "extendedPrefix", jpref); ++ } + + /* Initialize TLV browsing */ + length = lsa->size - OSPF_LSA_HEADER_SIZE; +@@ -1955,10 +2129,10 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case EXT_TLV_PREFIX: +- sum += show_vty_pref_info(vty, tlvh, length - sum); ++ sum += show_vty_pref_info(vty, tlvh, length - sum, jpref); + break; + default: +- sum += show_vty_unknown_tlv(vty, tlvh, length - sum); ++ sum += show_vty_unknown_tlv(vty, tlvh, length - sum, jpref); + break; + } + } +diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c +index e227a31..099ccf3 100644 +--- a/ospfd/ospf_ri.c ++++ b/ospfd/ospf_ri.c +@@ -1226,17 +1226,18 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) + * Following are vty session control functions. + *------------------------------------------------------------------------*/ + +-#define check_tlv_size(size, msg) \ +- do { \ +- if (ntohs(tlvh->length) > size) { \ +- if (vty != NULL) \ +- vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \ +- msg, ntohs(tlvh->length), size); \ +- else \ +- zlog_debug(" Wrong %s TLV size: %d(%d)", \ +- msg, ntohs(tlvh->length), size); \ +- return size + TLV_HDR_SIZE; \ +- } \ ++#define check_tlv_size(size, msg) \ ++ do { \ ++ if (ntohs(tlvh->length) > size) { \ ++ if (vty != NULL) \ ++ vty_out(vty, \ ++ " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \ ++ msg, ntohs(tlvh->length), size); \ ++ else \ ++ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", \ ++ msg, ntohs(tlvh->length), size); \ ++ return OSPF_MAX_LSA_SIZE + 1; \ ++ } \ + } while (0) + + static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh) +diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c +index ffea80c..acfb8d7 100644 +--- a/ospfd/ospf_te.c ++++ b/ospfd/ospf_te.c +@@ -3213,17 +3213,18 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf) + /*------------------------------------------------------------------------* + * Following are vty session control functions. + *------------------------------------------------------------------------*/ +-#define check_tlv_size(size, msg) \ +- do { \ +- if (ntohs(tlvh->length) > size) { \ +- if (vty != NULL) \ +- vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \ +- msg, ntohs(tlvh->length), size); \ +- else \ +- zlog_debug(" Wrong %s TLV size: %d(%d)", \ +- msg, ntohs(tlvh->length), size); \ +- return size + TLV_HDR_SIZE; \ +- } \ ++ #define check_tlv_size(size, msg) \ ++ do { \ ++ if (ntohs(tlvh->length) > size) { \ ++ if (vty != NULL) \ ++ vty_out(vty, \ ++ " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \ ++ msg, ntohs(tlvh->length), size); \ ++ else \ ++ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", \ ++ msg, ntohs(tlvh->length), size); \ ++ return OSPF_MAX_LSA_SIZE + 1; \ ++ } \ + } while (0) + + static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) +-- +2.45.4 + diff --git a/SPECS/frr/CVE-2025-61100.nopatch b/SPECS/frr/CVE-2025-61100.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61101.nopatch b/SPECS/frr/CVE-2025-61101.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61102.nopatch b/SPECS/frr/CVE-2025-61102.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61103.nopatch b/SPECS/frr/CVE-2025-61103.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61104.nopatch b/SPECS/frr/CVE-2025-61104.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61106.nopatch b/SPECS/frr/CVE-2025-61106.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/CVE-2025-61107.nopatch b/SPECS/frr/CVE-2025-61107.nopatch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/SPECS/frr/frr.spec b/SPECS/frr/frr.spec index 913697155ad..080116236e4 100644 --- a/SPECS/frr/frr.spec +++ b/SPECS/frr/frr.spec @@ -3,7 +3,7 @@ Summary: Routing daemon Name: frr Version: 8.5.5 -Release: 4%{?dist} +Release: 5%{?dist} License: GPL-2.0-or-later Vendor: Microsoft Corporation Distribution: Mariner @@ -19,7 +19,9 @@ Patch4: 0004-remove-grpc-test.patch Patch5: CVE-2024-44070.patch Patch6: CVE-2024-55553.patch Patch7: 0001-Fix-frr-c90-complaint-error.patch - +# Following CVE fixes CVE-2025-61100, CVE-2025-61101, CVE-2025-61102, CVE-2025-61103, +# CVE-2025-61104, CVE-2025-61105, CVE-2025-61106 and CVE-2025-61107. +Patch8: CVE-2025-61099.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: bison @@ -201,6 +203,10 @@ rm tests/lib/*grpc* %{_sysusersdir}/%{name}.conf %changelog +* Wed Jan 21 2026 Archana Shettigar - 8.5.5-5 +- Patch CVE-2025-61099, CVE-2025-61100, CVE-2025-61101, CVE-2025-61102, + CVE-2025-61103, CVE-2025-61104, CVE-2025-61105, CVE-2025-61106 and CVE-2025-61107 + * Mon Dec 29 2025 Archana Shettigar - 8.5.5-4 - Rebuilt for net-snmp version up with c90 fix diff --git a/SPECS/hvloader/CVE-2026-22795.patch b/SPECS/hvloader/CVE-2026-22795.patch new file mode 100644 index 00000000000..b18e13f5f12 --- /dev/null +++ b/SPECS/hvloader/CVE-2026-22795.patch @@ -0,0 +1,77 @@ +From f6794d3f13d146454bad354b27b00ef4e8b724f7 Mon Sep 17 00:00:00 2001 +From: Bob Beck +Date: Wed, 7 Jan 2026 11:29:48 -0700 +Subject: [PATCH] Ensure ASN1 types are checked before use. + +Some of these were fixed by LibreSSL in commit https://github.com/openbsd/src/commit/aa1f637d454961d22117b4353f98253e984b3ba8 +this fix includes the other fixes in that commit, as well as fixes for others found by a scan +for a similar unvalidated access paradigm in the tree. + +Reviewed-by: Kurt Roeckx +Reviewed-by: Shane Lontis +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/29582) + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/openssl/openssl/commit/572844beca95068394c916626a6d3a490f831a49.patch +--- + CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c | 3 ++- + .../OpensslLib/openssl/crypto/pkcs12/p12_kiss.c | 10 ++++++++-- + .../Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c | 2 ++ + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c b/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c +index 00effc80..6e8cc6e9 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/apps/s_client.c +@@ -2698,8 +2698,9 @@ int s_client_main(int argc, char **argv) + goto end; + } + atyp = ASN1_generate_nconf(genstr, cnf); +- if (atyp == NULL) { ++ if (atyp == NULL || atyp->type != V_ASN1_SEQUENCE) { + NCONF_free(cnf); ++ ASN1_TYPE_free(atyp); + BIO_printf(bio_err, "ASN1_generate_nconf failed\n"); + goto end; + } +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c +index 7ab98385..d90404dd 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs12/p12_kiss.c +@@ -183,11 +183,17 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, + ASN1_BMPSTRING *fname = NULL; + ASN1_OCTET_STRING *lkid = NULL; + +- if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) ++ if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) { ++ if (attrib->type != V_ASN1_BMPSTRING) ++ return 0; + fname = attrib->value.bmpstring; ++ } + +- if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) ++ if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) { ++ if (attrib->type != V_ASN1_OCTET_STRING) ++ return 0; + lkid = attrib->value.octet_string; ++ } + + switch (PKCS12_SAFEBAG_get_nid(bag)) { + case NID_keyBag: +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c +index f63fbc50..4e0eb1e8 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/pkcs7/pk7_doit.c +@@ -1092,6 +1092,8 @@ ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) + ASN1_TYPE *astype; + if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL) + return NULL; ++ if (astype->type != V_ASN1_OCTET_STRING) ++ return NULL; + return astype->value.octet_string; + } + +-- +2.45.4 + diff --git a/SPECS/hvloader/hvloader.spec b/SPECS/hvloader/hvloader.spec index 0d8666e656f..793b5261849 100644 --- a/SPECS/hvloader/hvloader.spec +++ b/SPECS/hvloader/hvloader.spec @@ -4,7 +4,7 @@ Summary: HvLoader.efi is an EFI application for loading an external hypervisor loader. Name: hvloader Version: 1.0.1 -Release: 15%{?dist} +Release: 16%{?dist} License: MIT Vendor: Microsoft Corporation Distribution: Mariner @@ -36,6 +36,7 @@ Patch18: CVE-2023-45236.patch Patch19: CVE-2024-38796.patch Patch20: CVE-2025-3770.patch Patch21: CVE-2025-2296.patch +Patch22: CVE-2026-22795.patch BuildRequires: bc BuildRequires: gcc @@ -81,6 +82,9 @@ cp ./Build/MdeModule/RELEASE_GCC5/X64/MdeModulePkg/Application/%{name_github}-%{ /boot/efi/HvLoader.efi %changelog +* Wed Feb 04 2026 Azure Linux Security Servicing Account - 1.0.1-16 +- Patch for CVE-2026-22795 + * Wed Nov 20 2025 Jyoti kanase - 1.0.1-15 - Patch for CVE-2025-2296 diff --git a/SPECS/libvirt/CVE-2025-12748.patch b/SPECS/libvirt/CVE-2025-12748.patch new file mode 100644 index 00000000000..439565e9462 --- /dev/null +++ b/SPECS/libvirt/CVE-2025-12748.patch @@ -0,0 +1,1300 @@ +From 508a5ab49e83c1ac272108daae9ae92d906cde95 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 1/9] Pre-requisite for CVE-2025-12748 + +Upstream Patch reference: +1. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=508a5ab49e83c1ac272108daae9ae92d906cde95 +2. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=fabc09641da50196e4d0de949426023baccb41ae +3. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=f15dc1a7de65ab16163908b92cb479c713f8f052 +--- + src/qemu/qemu_driver.c | 46 ++++--- + src/qemu/qemu_saveimage.c | 268 +++++++++++++++++++++++--------------- + src/qemu/qemu_saveimage.h | 21 ++- + 3 files changed, 202 insertions(+), 133 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 4e680bc..9cf2c3e 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -5910,9 +5910,12 @@ qemuDomainRestoreFlags(virConnectPtr conn, + + virNWFilterReadLockFilterUpdates(); + +- fd = qemuSaveImageOpen(driver, NULL, path, &def, &data, ++ if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) ++ goto cleanup; ++ ++ fd = qemuSaveImageOpen(driver, path, + (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0, +- &wrapperFd, false, false); ++ &wrapperFd, false); + if (fd < 0) + goto cleanup; + +@@ -5999,15 +6002,11 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path, + virQEMUDriver *driver = conn->privateData; + char *ret = NULL; + g_autoptr(virDomainDef) def = NULL; +- int fd = -1; + virQEMUSaveData *data = NULL; + + virCheckFlags(VIR_DOMAIN_SAVE_IMAGE_XML_SECURE, NULL); + +- fd = qemuSaveImageOpen(driver, NULL, path, &def, &data, +- false, NULL, false, false); +- +- if (fd < 0) ++ if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) + goto cleanup; + + if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0) +@@ -6017,7 +6016,6 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path, + + cleanup: + virQEMUSaveDataFree(data); +- VIR_FORCE_CLOSE(fd); + return ret; + } + +@@ -6041,9 +6039,10 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path, + else if (flags & VIR_DOMAIN_SAVE_PAUSED) + state = 0; + +- fd = qemuSaveImageOpen(driver, NULL, path, &def, &data, +- false, NULL, true, false); ++ if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) ++ goto cleanup; + ++ fd = qemuSaveImageOpen(driver, path, 0, NULL, false); + if (fd < 0) + goto cleanup; + +@@ -6100,7 +6099,6 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags) + g_autofree char *path = NULL; + char *ret = NULL; + g_autoptr(virDomainDef) def = NULL; +- int fd = -1; + virQEMUSaveData *data = NULL; + qemuDomainObjPrivate *priv; + +@@ -6123,15 +6121,13 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags) + goto cleanup; + } + +- if ((fd = qemuSaveImageOpen(driver, priv->qemuCaps, path, &def, &data, +- false, NULL, false, false)) < 0) ++ if (qemuSaveImageGetMetadata(driver, priv->qemuCaps, path, &def, &data) < 0) + goto cleanup; + + ret = qemuDomainDefFormatXML(driver, priv->qemuCaps, def, flags); + + cleanup: + virQEMUSaveDataFree(data); +- VIR_FORCE_CLOSE(fd); + virDomainObjEndAPI(&vm); + return ret; + } +@@ -6187,14 +6183,26 @@ qemuDomainObjRestore(virConnectPtr conn, + virQEMUSaveData *data = NULL; + virFileWrapperFd *wrapperFd = NULL; + +- fd = qemuSaveImageOpen(driver, NULL, path, &def, &data, +- bypass_cache, &wrapperFd, false, true); +- if (fd < 0) { +- if (fd == -3) +- ret = 1; ++ ret = qemuSaveImageGetMetadata(driver, NULL, path, &def, &data); ++ if (ret < 0) { ++ if (qemuSaveImageIsCorrupt(driver, path)) { ++ if (unlink(path) < 0) { ++ virReportSystemError(errno, ++ _("cannot remove corrupt file: %1$s"), ++ path); ++ ret = -1; ++ } else { ++ virResetLastError(); ++ ret = 1; ++ } ++ } + goto cleanup; + } + ++ fd = qemuSaveImageOpen(driver, path, bypass_cache, &wrapperFd, false); ++ if (fd < 0) ++ goto cleanup; ++ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + int hookret; + +diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c +index e14e298..5f14d07 100644 +--- a/src/qemu/qemu_saveimage.c ++++ b/src/qemu/qemu_saveimage.c +@@ -90,6 +90,90 @@ virQEMUSaveDataFree(virQEMUSaveData *data) + + G_DEFINE_AUTOPTR_CLEANUP_FUNC(virQEMUSaveData, virQEMUSaveDataFree); + ++static int ++qemuSaveImageReadHeader(int fd, virQEMUSaveData **ret_data) ++{ ++ g_autoptr(virQEMUSaveData) data = NULL; ++ virQEMUSaveHeader *header; ++ size_t xml_len; ++ size_t cookie_len; ++ ++ data = g_new0(virQEMUSaveData, 1); ++ header = &data->header; ++ if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("failed to read qemu header")); ++ return -1; ++ } ++ ++ if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) { ++ if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("save image is incomplete")); ++ return -1; ++ } ++ ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("image magic is incorrect")); ++ return -1; ++ } ++ ++ if (header->version > QEMU_SAVE_VERSION) { ++ /* convert endianness and try again */ ++ qemuSaveImageBswapHeader(header); ++ } ++ ++ if (header->version > QEMU_SAVE_VERSION) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("image version is not supported (%1$d > %2$d)"), ++ header->version, QEMU_SAVE_VERSION); ++ return -1; ++ } ++ ++ if (header->compressed >= QEMU_SAVE_FORMAT_LAST) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("unsupported save image format: %1$d"), header->compressed); ++ return -1; ++ } ++ ++ if (header->data_len <= 0) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("invalid header data length: %1$d"), header->data_len); ++ return -1; ++ } ++ ++ if (header->cookieOffset) ++ xml_len = header->cookieOffset; ++ else ++ xml_len = header->data_len; ++ ++ cookie_len = header->data_len - xml_len; ++ ++ data->xml = g_new0(char, xml_len); ++ ++ if (saferead(fd, data->xml, xml_len) != xml_len) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("failed to read domain XML")); ++ return -1; ++ } ++ ++ if (cookie_len > 0) { ++ data->cookie = g_new0(char, cookie_len); ++ ++ if (saferead(fd, data->cookie, cookie_len) != cookie_len) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("failed to read cookie")); ++ return -1; ++ } ++ } ++ ++ if (ret_data) ++ *ret_data = g_steal_pointer(&data); ++ ++ return 0; ++} ++ ++ + /** + * This function steals @domXML on success. + */ +@@ -414,41 +498,99 @@ qemuSaveImageGetCompressionProgram(const char *imageFormat, + + + /** +- * qemuSaveImageOpen: ++ * qemuSaveImageIsCorrupt: + * @driver: qemu driver data ++ * @path: path of the save image ++ * ++ * Returns true if the save image file identified by @path does not exist or ++ * has a corrupt header. Returns false otherwise. ++ */ ++ ++bool ++qemuSaveImageIsCorrupt(virQEMUDriver *driver, const char *path) ++{ ++ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); ++ VIR_AUTOCLOSE fd = -1; ++ virQEMUSaveHeader header; ++ ++ if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0) ++ return true; ++ ++ if (saferead(fd, &header, sizeof(header)) != sizeof(header)) ++ return true; ++ ++ if (memcmp(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)) != 0 || ++ memcmp(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic)) == 0) ++ return true; ++ ++ return false; ++} ++ ++ ++/** ++ * qemuSaveImageGetMetadata: ++ * @driver: qemu driver dataqemuSaveImageOpen + * @qemuCaps: pointer to qemuCaps if the domain is running or NULL + * @path: path of the save image + * @ret_def: returns domain definition created from the XML stored in the image + * @ret_data: returns structure filled with data from the image header ++ * ++ * Open the save image file, read libvirt's save image metadata, and populate ++ * the @ret_def and @ret_data structures. Returns 0 on success and -1 on failure. ++ */ ++int ++qemuSaveImageGetMetadata(virQEMUDriver *driver, ++ virQEMUCaps *qemuCaps, ++ const char *path, ++ virDomainDef **ret_def, ++ virQEMUSaveData **ret_data) ++{ ++ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); ++ VIR_AUTOCLOSE fd = -1; ++ virQEMUSaveData *data; ++ g_autoptr(virDomainDef) def = NULL; ++ int rc; ++ ++ if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0) ++ return -1; ++ ++ if ((rc = qemuSaveImageReadHeader(fd, ret_data)) < 0) ++ return rc; ++ ++ data = *ret_data; ++ /* Create a domain from this XML */ ++ if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps, ++ VIR_DOMAIN_DEF_PARSE_INACTIVE | ++ VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) ++ return -1; ++ ++ *ret_def = g_steal_pointer(&def); ++ ++ return 0; ++} ++ ++ ++/** ++ * qemuSaveImageOpen: ++ * @driver: qemu driver data ++ * @path: path of the save image + * @bypass_cache: bypass cache when opening the file + * @wrapperFd: returns the file wrapper structure + * @open_write: open the file for writing (for updates) +- * @unlink_corrupt: remove the image file if it is corrupted + * +- * Returns the opened fd of the save image file and fills the appropriate fields +- * on success. On error returns -1 on most failures, -3 if corrupt image was +- * unlinked (no error raised). ++ * Returns the opened fd of the save image file on success, -1 on failure. + */ + int + qemuSaveImageOpen(virQEMUDriver *driver, +- virQEMUCaps *qemuCaps, + const char *path, +- virDomainDef **ret_def, +- virQEMUSaveData **ret_data, + bool bypass_cache, + virFileWrapperFd **wrapperFd, +- bool open_write, +- bool unlink_corrupt) ++ bool open_write) + { + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + VIR_AUTOCLOSE fd = -1; + int ret = -1; +- g_autoptr(virQEMUSaveData) data = NULL; +- virQEMUSaveHeader *header; +- g_autoptr(virDomainDef) def = NULL; + int oflags = open_write ? O_RDWR : O_RDONLY; +- size_t xml_len; +- size_t cookie_len; + + if (bypass_cache) { + int directFlag = virFileDirectFdFlag(); +@@ -468,101 +610,11 @@ qemuSaveImageOpen(virQEMUDriver *driver, + VIR_FILE_WRAPPER_BYPASS_CACHE))) + return -1; + +- data = g_new0(virQEMUSaveData, 1); +- +- header = &data->header; +- if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) { +- if (unlink_corrupt) { +- if (unlink(path) < 0) { +- virReportSystemError(errno, +- _("cannot remove corrupt file: %s"), +- path); +- return -1; +- } else { +- return -3; +- } +- } +- +- virReportError(VIR_ERR_OPERATION_FAILED, +- "%s", _("failed to read qemu header")); +- return -1; +- } +- +- if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) { +- if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) { +- if (unlink_corrupt) { +- if (unlink(path) < 0) { +- virReportSystemError(errno, +- _("cannot remove corrupt file: %s"), +- path); +- return -1; +- } else { +- return -3; +- } +- } +- +- virReportError(VIR_ERR_OPERATION_FAILED, "%s", +- _("save image is incomplete")); +- return -1; +- } +- +- virReportError(VIR_ERR_OPERATION_FAILED, "%s", +- _("image magic is incorrect")); +- return -1; +- } +- +- if (header->version > QEMU_SAVE_VERSION) { +- /* convert endianness and try again */ +- qemuSaveImageBswapHeader(header); +- } +- +- if (header->version > QEMU_SAVE_VERSION) { +- virReportError(VIR_ERR_OPERATION_FAILED, +- _("image version is not supported (%d > %d)"), +- header->version, QEMU_SAVE_VERSION); +- return -1; +- } +- +- if (header->data_len <= 0) { +- virReportError(VIR_ERR_OPERATION_FAILED, +- _("invalid header data length: %d"), header->data_len); +- return -1; +- } +- +- if (header->cookieOffset) +- xml_len = header->cookieOffset; +- else +- xml_len = header->data_len; +- +- cookie_len = header->data_len - xml_len; +- +- data->xml = g_new0(char, xml_len); +- +- if (saferead(fd, data->xml, xml_len) != xml_len) { +- virReportError(VIR_ERR_OPERATION_FAILED, +- "%s", _("failed to read domain XML")); +- return -1; +- } +- +- if (cookie_len > 0) { +- data->cookie = g_new0(char, cookie_len); +- +- if (saferead(fd, data->cookie, cookie_len) != cookie_len) { +- virReportError(VIR_ERR_OPERATION_FAILED, "%s", +- _("failed to read cookie")); +- return -1; +- } +- } +- +- /* Create a domain from this XML */ +- if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps, +- VIR_DOMAIN_DEF_PARSE_INACTIVE | +- VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) ++ /* Read the header to position the file pointer for QEMU. Unfortunately we ++ * can't use lseek with virFileWrapperFD. */ ++ if (qemuSaveImageReadHeader(fd, NULL) < 0) + return -1; + +- *ret_def = g_steal_pointer(&def); +- *ret_data = g_steal_pointer(&data); +- + ret = fd; + fd = -1; + +diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h +index 45c5f35..0dcdba2 100644 +--- a/src/qemu/qemu_saveimage.h ++++ b/src/qemu/qemu_saveimage.h +@@ -70,17 +70,26 @@ qemuSaveImageStartVM(virConnectPtr conn, + qemuDomainAsyncJob asyncJob) + ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6); + ++bool ++qemuSaveImageIsCorrupt(virQEMUDriver *driver, ++ const char *path) ++ ATTRIBUTE_NONNULL(2); ++ ++int ++qemuSaveImageGetMetadata(virQEMUDriver *driver, ++ virQEMUCaps *qemuCaps, ++ const char *path, ++ virDomainDef **ret_def, ++ virQEMUSaveData **ret_data) ++ ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); ++ + int + qemuSaveImageOpen(virQEMUDriver *driver, +- virQEMUCaps *qemuCaps, + const char *path, +- virDomainDef **ret_def, +- virQEMUSaveData **ret_data, + bool bypass_cache, + virFileWrapperFd **wrapperFd, +- bool open_write, +- bool unlink_corrupt) +- ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); ++ bool open_write) ++ ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4); + + int + qemuSaveImageGetCompressionProgram(const char *imageFormat, +-- +2.43.0 + +From f0c391572604abb82745ac96af942d39f854e990 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 2/9] conf: Add virDomainDefIDsParseString + +Upstream Patch reference: +1. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=f0c391572604abb82745ac96af942d39f854e990 +2. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=9df25774df5c6deef221bfb5b2a629d0066c7faf +3. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=fc32ad12e77b486d3546aeccc0687e3a713561f5 +4. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=29025d237545249e271719ecec1ba0ec03c8d2c3 +5. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=8f45c59db100a2a51d9a36dffc081068be94e17e +6. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=218e4e08bee6906c43a3b29cdc629f6b92368b14 +7. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=a79fb711143eb7e950fda889436bdd46e1515d73 +8. https://git.launchpad.net/ubuntu/+source/libvirt/patch/?id=d8e7d974dc418345c1454632d26ed1b59997fc52 +--- + src/conf/domain_conf.c | 48 ++++++++++++++++++++++++++++++++++++++++ + src/conf/domain_conf.h | 3 +++ + src/libvirt_private.syms | 1 + + 3 files changed, 52 insertions(+) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index f88405a..5a5c2d3 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -20524,6 +20524,54 @@ virDomainDefParse(const char *xmlStr, + return def; + } + ++virDomainDef * ++virDomainDefIDsParseString(const char *xmlStr, ++ virDomainXMLOption *xmlopt, ++ unsigned int flags) ++{ ++ g_autoptr(virDomainDef) def = NULL; ++ g_autoptr(xmlDoc) xml = NULL; ++ g_autoptr(xmlXPathContext) ctxt = NULL; ++ bool uuid_generated = false; ++ int keepBlanksDefault = xmlKeepBlanksDefault(0); ++ xmlNodePtr root; ++ ++ if (!(xml = virXMLParse(NULL, xmlStr, _("(domain_definition)"), "domain.rng", ++ false))) { ++ xmlKeepBlanksDefault(keepBlanksDefault); ++ return NULL; ++ } ++ ++ xmlKeepBlanksDefault(keepBlanksDefault); ++ ++ root = xmlDocGetRootElement(xml); ++ if (!virXMLNodeNameEqual(root, "domain")) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("unexpected root element <%s>, " ++ "expecting "), ++ root->name); ++ return NULL; ++ } ++ ++ if (!(ctxt = virXMLXPathContextNew(xml))) { ++ return NULL; ++ } ++ ++ ctxt->node = root; ++ ++ def = virDomainDefNew(xmlopt); ++ if (!def) ++ return NULL; ++ ++ if (virDomainDefParseIDs(def, ctxt, flags, &uuid_generated) < 0) ++ return NULL; ++ ++ if (uuid_generated) ++ memset(def->uuid, 0, VIR_UUID_BUFLEN); ++ ++ return g_steal_pointer(&def); ++} ++ + virDomainDef * + virDomainDefParseString(const char *xmlStr, + virDomainXMLOption *xmlopt, +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index c4a8dcc..066e365 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -3490,6 +3490,9 @@ virDomainDiskDef *virDomainDiskDefParse(const char *xmlStr, + virStorageSource *virDomainDiskDefParseSource(const char *xmlStr, + virDomainXMLOption *xmlopt, + unsigned int flags); ++virDomainDef * virDomainDefIDsParseString(const char *xmlStr, ++ virDomainXMLOption *xmlopt, ++ unsigned int flags); + virDomainDef *virDomainDefParseString(const char *xmlStr, + virDomainXMLOption *xmlopt, + void *parseOpaque, +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index b98cb0f..09850e1 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -336,6 +336,7 @@ virDomainDefHasUSB; + virDomainDefHasVcpusOffline; + virDomainDefHasVDPANet; + virDomainDefHasVFIOHostdev; ++virDomainDefIDsParseString; + virDomainDefLifecycleActionAllowed; + virDomainDefMaybeAddController; + virDomainDefMaybeAddInput; +-- +2.43.0 + +From 9df25774df5c6deef221bfb5b2a629d0066c7faf Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 3/9] bhyve: Check ACLs before parsing the whole domain XML + +--- + src/bhyve/bhyve_driver.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c +index eccf9b4..f933376 100644 +--- a/src/bhyve/bhyve_driver.c ++++ b/src/bhyve/bhyve_driver.c +@@ -520,6 +520,15 @@ bhyveDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag + if (!caps) + return NULL; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, provconn->xmlopt, parse_flags))) ++ return NULL; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) ++ return NULL; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ + if ((def = virDomainDefParseString(xml, privconn->xmlopt, + NULL, parse_flags)) == NULL) + goto cleanup; +@@ -527,9 +536,6 @@ bhyveDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag + if (virXMLCheckIllegalChars("name", def->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (bhyveDomainAssignAddresses(def, NULL) < 0) + goto cleanup; + +@@ -904,11 +910,17 @@ bhyveDomainCreateXML(virConnectPtr conn, + if (flags & VIR_DOMAIN_START_AUTODESTROY) + start_flags |= VIR_BHYVE_PROCESS_START_AUTODESTROY; + +- if ((def = virDomainDefParseString(xml, privconn->xmlopt, +- NULL, parse_flags)) == NULL) +- goto cleanup; ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, provconn->xmlopt, parse_flags))) ++ return NULL; + + if (virDomainCreateXMLEnsureACL(conn, def) < 0) ++ return NULL; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ ++ if ((def = virDomainDefParseString(xml, privconn->xmlopt, ++ NULL, parse_flags)) == NULL) + goto cleanup; + + if (bhyveDomainAssignAddresses(def, NULL) < 0) +-- +2.43.0 + +From fc32ad12e77b486d3546aeccc0687e3a713561f5 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 4/9] libxl: Check ACLs before parsing the whole domain XML + +--- + src/libxl/libxl_driver.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c +index 23a28dc..942a36f 100644 +--- a/src/libxl/libxl_driver.c ++++ b/src/libxl/libxl_driver.c +@@ -1020,13 +1020,18 @@ libxlDomainCreateXML(virConnectPtr conn, const char *xml, + if (flags & VIR_DOMAIN_START_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + +- if (!(def = virDomainDefParseString(xml, driver->xmlopt, +- NULL, parse_flags))) ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) + goto cleanup; + + if (virDomainCreateXMLEnsureACL(conn, def) < 0) + goto cleanup; + ++ g_clear_pointer(&def, virDomainDefFree); ++ ++ if (!(def = virDomainDefParseString(xml, driver->xmlopt, ++ NULL, parse_flags))) ++ goto cleanup; ++ + if (!(vm = virDomainObjListAdd(driver->domains, &def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | +@@ -2813,6 +2818,14 @@ libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag + if (flags & VIR_DOMAIN_DEFINE_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ goto cleanup; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) ++ goto cleanup; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ + if (!(def = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags))) + goto cleanup; +@@ -2820,9 +2833,6 @@ libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag + if (virXMLCheckIllegalChars("name", def->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (!(vm = virDomainObjListAdd(driver->domains, &def, + driver->xmlopt, + 0, +-- +2.43.0 + +From 29025d237545249e271719ecec1ba0ec03c8d2c3 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 5/9] lxc: Check ACLs before parsing the whole domain XML + +--- + src/lxc/lxc_driver.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index 3cdf73c..c6f9476 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -416,6 +416,15 @@ lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (!(caps = virLXCDriverGetCapabilities(driver, false))) + goto cleanup; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ goto cleanup; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) ++ goto cleanup; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ + if (!(def = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags))) + goto cleanup; +@@ -423,9 +432,6 @@ lxcDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (virXMLCheckIllegalChars("name", def->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (virSecurityManagerVerify(driver->securityManager, def) < 0) + goto cleanup; + +@@ -1100,13 +1106,19 @@ lxcDomainCreateXMLWithFiles(virConnectPtr conn, + if (!(caps = virLXCDriverGetCapabilities(driver, false))) + goto cleanup; + +- if (!(def = virDomainDefParseString(xml, driver->xmlopt, +- NULL, parse_flags))) ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) + goto cleanup; + + if (virDomainCreateXMLWithFilesEnsureACL(conn, def) < 0) + goto cleanup; + ++ g_clear_pointer(&def, virDomainDefFree); ++ ++ if (!(def = virDomainDefParseString(xml, driver->xmlopt, ++ NULL, parse_flags))) ++ goto cleanup; ++ + if (virSecurityManagerVerify(driver->securityManager, def) < 0) + goto cleanup; + +-- +2.43.0 + +From 8f45c59db100a2a51d9a36dffc081068be94e17e Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 6/9] vz: Check ACLs before parsing the whole domain XML + +--- + src/vz/vz_driver.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c +index 23b7795..6a3709c 100644 +--- a/src/vz/vz_driver.c ++++ b/src/vz/vz_driver.c +@@ -799,6 +799,15 @@ vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (flags & VIR_DOMAIN_DEFINE_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ return NULL; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) ++ return NULL; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ + if ((def = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags)) == NULL) + goto cleanup; +@@ -806,9 +815,6 @@ vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (virXMLCheckIllegalChars("name", def->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + dom = virDomainObjListFindByUUID(driver->domains, def->uuid); + if (dom == NULL) { + virResetLastError(); +@@ -2993,9 +2999,9 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, + | VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0) + goto cleanup; + +- if (!(def = virDomainDefParseString(dom_xml, driver->xmlopt, +- NULL, +- VIR_DOMAIN_DEF_PARSE_INACTIVE))) ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(dom_xml, driver->xmlopt, ++ VIR_DOMAIN_DEF_PARSE_INACTIVE))) + goto cleanup; + + if (dname) { +-- +2.43.0 + +From 218e4e08bee6906c43a3b29cdc629f6b92368b14 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 7/9] ch: Check ACLs before parsing the whole domain XML + +--- + src/ch/ch_driver.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c +index 464bcef..c86d43c 100644 +--- a/src/ch/ch_driver.c ++++ b/src/ch/ch_driver.c +@@ -228,14 +228,19 @@ chDomainCreateXML(virConnectPtr conn, + if (flags & VIR_DOMAIN_START_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(vmdef = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ return NULL; ++ ++ if (virDomainCreateXMLEnsureACL(conn, vmdef) < 0) ++ return NULL; ++ ++ g_clear_pointer(&vmdef, virDomainDefFree); + + if ((vmdef = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags)) == NULL) + goto cleanup; + +- if (virDomainCreateXMLEnsureACL(conn, vmdef) < 0) +- goto cleanup; +- + if (!(vm = virDomainObjListAdd(driver->domains, + &vmdef, + driver->xmlopt, +@@ -311,6 +316,15 @@ chDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (flags & VIR_DOMAIN_START_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(vmdef = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ return NULL; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, vmdef) < 0) ++ return NULL; ++ ++ g_clear_pointer(&vmdef, virDomainDefFree); ++ + if ((vmdef = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags)) == NULL) + goto cleanup; +@@ -318,9 +332,6 @@ chDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + if (virXMLCheckIllegalChars("name", vmdef->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, vmdef) < 0) +- goto cleanup; +- + if (!(vm = virDomainObjListAdd(driver->domains, &vmdef, + driver->xmlopt, + 0, NULL))) +-- +2.43.0 + +From a79fb711143eb7e950fda889436bdd46e1515d73 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 8/9] qemu: Check ACLs before parsing the whole domain XML + +--- + src/qemu/qemu_driver.c | 92 ++++++++++++++++++++------------------- + src/qemu/qemu_migration.c | 23 +++++++++- + src/qemu/qemu_migration.h | 4 +- + src/qemu/qemu_saveimage.c | 25 +++++++++-- + src/qemu/qemu_saveimage.h | 4 +- + 5 files changed, 97 insertions(+), 51 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 9cf2c3e..4a779e7 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -1719,11 +1719,17 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, + + virNWFilterReadLockFilterUpdates(); + +- if (!(def = virDomainDefParseString(xml, driver->xmlopt, +- NULL, parse_flags))) +- goto cleanup; ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ return NULL; + + if (virDomainCreateXMLEnsureACL(conn, def) < 0) ++ return NULL; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ ++ if (!(def = virDomainDefParseString(xml, driver->xmlopt, ++ NULL, parse_flags))) + goto cleanup; + + if (!(vm = virDomainObjListAdd(driver->domains, &def, +@@ -5910,7 +5916,9 @@ qemuDomainRestoreFlags(virConnectPtr conn, + + virNWFilterReadLockFilterUpdates(); + +- if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) ++ if (qemuSaveImageGetMetadata(driver, NULL, path, ++ virDomainRestoreFlagsEnsureACL, ++ conn, &def, &data) < 0) + goto cleanup; + + fd = qemuSaveImageOpen(driver, path, +@@ -5919,9 +5927,6 @@ qemuDomainRestoreFlags(virConnectPtr conn, + if (fd < 0) + goto cleanup; + +- if (virDomainRestoreFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + int hookret; + +@@ -6006,10 +6011,9 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path, + + virCheckFlags(VIR_DOMAIN_SAVE_IMAGE_XML_SECURE, NULL); + +- if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) +- goto cleanup; +- +- if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0) ++ if (qemuSaveImageGetMetadata(driver, NULL, path, ++ virDomainSaveImageGetXMLDescEnsureACL, ++ conn, &def, &data) < 0) + goto cleanup; + + ret = qemuDomainDefFormatXML(driver, NULL, def, flags); +@@ -6039,16 +6043,15 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path, + else if (flags & VIR_DOMAIN_SAVE_PAUSED) + state = 0; + +- if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0) ++ if (qemuSaveImageGetMetadata(driver, NULL, path, ++ virDomainSaveImageDefineXMLEnsureACL, ++ conn, &def, &data) < 0) + goto cleanup; + + fd = qemuSaveImageOpen(driver, path, 0, NULL, false); + if (fd < 0) + goto cleanup; + +- if (virDomainSaveImageDefineXMLEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (STREQ(data->xml, dxml) && + (state < 0 || state == data->header.was_running)) { + /* no change to the XML */ +@@ -6121,7 +6124,8 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags) + goto cleanup; + } + +- if (qemuSaveImageGetMetadata(driver, priv->qemuCaps, path, &def, &data) < 0) ++ if (qemuSaveImageGetMetadata(driver, priv->qemuCaps, path, ++ NULL, NULL, &def, &data) < 0) + goto cleanup; + + ret = qemuDomainDefFormatXML(driver, priv->qemuCaps, def, flags); +@@ -6183,7 +6187,7 @@ qemuDomainObjRestore(virConnectPtr conn, + virQEMUSaveData *data = NULL; + virFileWrapperFd *wrapperFd = NULL; + +- ret = qemuSaveImageGetMetadata(driver, NULL, path, &def, &data); ++ ret = qemuSaveImageGetMetadata(driver, NULL, path, NULL, NULL, &def, &data); + if (ret < 0) { + if (qemuSaveImageIsCorrupt(driver, path)) { + if (unlink(path) < 0) { +@@ -6599,6 +6603,15 @@ qemuDomainDefineXMLFlags(virConnectPtr conn, + if (flags & VIR_DOMAIN_DEFINE_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(def = virDomainDefIDsParseString(xml, driver->xmlopt, parse_flags))) ++ return NULL; ++ ++ if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) ++ return NULL; ++ ++ g_clear_pointer(&def, virDomainDefFree); ++ + if (!(def = virDomainDefParseString(xml, driver->xmlopt, + NULL, parse_flags))) + return NULL; +@@ -6606,9 +6619,6 @@ qemuDomainDefineXMLFlags(virConnectPtr conn, + if (virXMLCheckIllegalChars("name", def->name, "\n") < 0) + goto cleanup; + +- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +- goto cleanup; +- + if (!(vm = virDomainObjListAdd(driver->domains, &def, + driver->xmlopt, + 0, &oldDef))) +@@ -11283,10 +11293,9 @@ qemuDomainMigratePrepareTunnel(virConnectPtr dconn, + return -1; + } + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepareTunnelEnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepareTunnelEnsureACL))) + return -1; + + return qemuMigrationDstPrepareTunnel(driver, dconn, +@@ -11337,10 +11346,9 @@ qemuDomainMigratePrepare2(virConnectPtr dconn, + return -1; + } + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepare2EnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepare2EnsureACL))) + return -1; + + /* Do not use cookies in v2 protocol, since the cookie +@@ -11560,10 +11568,9 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, + QEMU_MIGRATION_DESTINATION))) + return -1; + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepare3EnsureACL))) + return -1; + + return qemuMigrationDstPrepareDirect(driver, dconn, +@@ -11672,10 +11679,9 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, + return -1; + } + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepare3ParamsEnsureACL))) + return -1; + + return qemuMigrationDstPrepareDirect(driver, dconn, +@@ -11717,10 +11723,9 @@ qemuDomainMigratePrepareTunnel3(virConnectPtr dconn, + QEMU_MIGRATION_DESTINATION))) + return -1; + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepareTunnel3EnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepareTunnel3EnsureACL))) + return -1; + + return qemuMigrationDstPrepareTunnel(driver, dconn, +@@ -11769,10 +11774,9 @@ qemuDomainMigratePrepareTunnel3Params(virConnectPtr dconn, + QEMU_MIGRATION_DESTINATION))) + return -1; + +- if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname))) +- return -1; +- +- if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0) ++ if (!(def = qemuMigrationAnyPrepareDef(driver, NULL, dom_xml, dname, &origname, ++ dconn, ++ virDomainMigratePrepareTunnel3ParamsEnsureACL))) + return -1; + + return qemuMigrationDstPrepareTunnel(driver, dconn, +diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c +index 8001792..5a57036 100644 +--- a/src/qemu/qemu_migration.c ++++ b/src/qemu/qemu_migration.c +@@ -3330,7 +3330,9 @@ qemuMigrationAnyPrepareDef(virQEMUDriver *driver, + virQEMUCaps *qemuCaps, + const char *dom_xml, + const char *dname, +- char **origname) ++ char **origname, ++ virConnectPtr sconn, ++ int (*ensureACL)(virConnectPtr, virDomainDef *)) + { + virDomainDef *def; + char *name = NULL; +@@ -3341,6 +3343,24 @@ qemuMigrationAnyPrepareDef(virQEMUDriver *driver, + return NULL; + } + ++ if (ensureACL) { ++ g_autoptr(virDomainDef) aclDef = NULL; ++ ++ /* Avoid parsing the whole domain definition for ACL checks */ ++ if (!(aclDef = virDomainDefIDsParseString(dom_xml, driver->xmlopt, ++ VIR_DOMAIN_DEF_PARSE_INACTIVE))) ++ return NULL; ++ ++ if (dname) { ++ VIR_FREE(aclDef->name); ++ aclDef->name = g_strdup(dname); ++ } ++ ++ if (ensureACL(sconn, aclDef) < 0) { ++ return NULL; ++ } ++ } ++ + if (!(def = virDomainDefParseString(dom_xml, driver->xmlopt, + qemuCaps, + VIR_DOMAIN_DEF_PARSE_INACTIVE | +@@ -4066,6 +4086,7 @@ qemuMigrationSrcRun(virQEMUDriver *driver, + if (!(persistDef = qemuMigrationAnyPrepareDef(driver, + priv->qemuCaps, + persist_xml, ++ NULL, NULL, + NULL, NULL))) + goto error; + } else { +diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h +index dd74f8b..c3ee5f6 100644 +--- a/src/qemu/qemu_migration.h ++++ b/src/qemu/qemu_migration.h +@@ -120,7 +120,9 @@ qemuMigrationAnyPrepareDef(virQEMUDriver *driver, + virQEMUCaps *qemuCaps, + const char *dom_xml, + const char *dname, +- char **origname); ++ char **origname, ++ virConnectPtr sconn, ++ int (*ensureACL)(virConnectPtr, virDomainDef *)); + + int + qemuMigrationDstPrepareTunnel(virQEMUDriver *driver, +diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c +index 5f14d07..0e84c39 100644 +--- a/src/qemu/qemu_saveimage.c ++++ b/src/qemu/qemu_saveimage.c +@@ -532,16 +532,21 @@ qemuSaveImageIsCorrupt(virQEMUDriver *driver, const char *path) + * @driver: qemu driver dataqemuSaveImageOpen + * @qemuCaps: pointer to qemuCaps if the domain is running or NULL + * @path: path of the save image ++ * @ensureACL: ACL callback to check against the definition or NULL ++ * @conn: parameter for the @ensureACL callback + * @ret_def: returns domain definition created from the XML stored in the image + * @ret_data: returns structure filled with data from the image header + * +- * Open the save image file, read libvirt's save image metadata, and populate +- * the @ret_def and @ret_data structures. Returns 0 on success and -1 on failure. ++ * Open the save image file, read libvirt's save image metadata, optionally ++ * check ACLs before parsing the whole domain definition and populate the ++ * @ret_def and @ret_data structures. Returns 0 on success and -1 on failure. + */ + int + qemuSaveImageGetMetadata(virQEMUDriver *driver, + virQEMUCaps *qemuCaps, + const char *path, ++ int (*ensureACL)(virConnectPtr, virDomainDef *), ++ virConnectPtr conn, + virDomainDef **ret_def, + virQEMUSaveData **ret_data) + { +@@ -549,6 +554,8 @@ qemuSaveImageGetMetadata(virQEMUDriver *driver, + VIR_AUTOCLOSE fd = -1; + virQEMUSaveData *data; + g_autoptr(virDomainDef) def = NULL; ++ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE | ++ VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; + int rc; + + if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0) +@@ -558,10 +565,20 @@ qemuSaveImageGetMetadata(virQEMUDriver *driver, + return rc; + + data = *ret_data; ++ ++ if (ensureACL) { ++ /* Parse only the IDs for ACL checks */ ++ g_autoptr(virDomainDef) aclDef = virDomainDefIDsParseString(data->xml, ++ driver->xmlopt, ++ parse_flags); ++ ++ if (!aclDef || ensureACL(conn, aclDef) < 0) ++ return -1; ++ } ++ + /* Create a domain from this XML */ + if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps, +- VIR_DOMAIN_DEF_PARSE_INACTIVE | +- VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) ++ parse_flags))) + return -1; + + *ret_def = g_steal_pointer(&def); +diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h +index 0dcdba2..d36b1bf 100644 +--- a/src/qemu/qemu_saveimage.h ++++ b/src/qemu/qemu_saveimage.h +@@ -79,9 +79,11 @@ int + qemuSaveImageGetMetadata(virQEMUDriver *driver, + virQEMUCaps *qemuCaps, + const char *path, ++ int (*ensureACL)(virConnectPtr, virDomainDef *), ++ virConnectPtr conn, + virDomainDef **ret_def, + virQEMUSaveData **ret_data) +- ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); ++ ATTRIBUTE_NONNULL(6) ATTRIBUTE_NONNULL(7); + + int + qemuSaveImageOpen(virQEMUDriver *driver, +-- +2.43.0 + +From d8e7d974dc418345c1454632d26ed1b59997fc52 Mon Sep 17 00:00:00 2001 +From: Marc Deslauriers +Date: Mon, 8 Dec 2025 13:08:06 -0500 +Subject: [PATCH 9/9] bhyve: s/provconn/privcon/ + +--- + src/bhyve/bhyve_driver.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c +index f933376..9451f79 100644 +--- a/src/bhyve/bhyve_driver.c ++++ b/src/bhyve/bhyve_driver.c +@@ -521,7 +521,7 @@ bhyveDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag + return NULL; + + /* Avoid parsing the whole domain definition for ACL checks */ +- if (!(def = virDomainDefIDsParseString(xml, provconn->xmlopt, parse_flags))) ++ if (!(def = virDomainDefIDsParseString(xml, privconn->xmlopt, parse_flags))) + return NULL; + + if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0) +@@ -911,7 +911,7 @@ bhyveDomainCreateXML(virConnectPtr conn, + start_flags |= VIR_BHYVE_PROCESS_START_AUTODESTROY; + + /* Avoid parsing the whole domain definition for ACL checks */ +- if (!(def = virDomainDefIDsParseString(xml, provconn->xmlopt, parse_flags))) ++ if (!(def = virDomainDefIDsParseString(xml, privconn->xmlopt, parse_flags))) + return NULL; + + if (virDomainCreateXMLEnsureACL(conn, def) < 0) +-- +2.43.0 + diff --git a/SPECS/libvirt/libvirt.spec b/SPECS/libvirt/libvirt.spec index f793ecf22f6..afd98d412b3 100644 --- a/SPECS/libvirt/libvirt.spec +++ b/SPECS/libvirt/libvirt.spec @@ -9,7 +9,7 @@ Summary: Virtualization API library that supports KVM, QEMU, Xen, ESX etc Name: libvirt Version: 7.10.0 -Release: 10%{?dist} +Release: 11%{?dist} License: LGPLv2+ Vendor: Microsoft Corporation Distribution: Mariner @@ -20,8 +20,9 @@ Source0: https://libvirt.org/sources/%{name}-%{version}.tar.xz Patch1: CVE-2023-2700.patch Patch2: CVE-2024-1441.patch Patch3: CVE-2024-2496.patch -Patch4: CVE-2024-2494.patch +Patch4: CVE-2024-2494.patch Patch5: CVE-2024-4418.patch +Patch6: CVE-2025-12748.patch BuildRequires: audit-libs-devel BuildRequires: augeas @@ -1059,6 +1060,9 @@ exit 0 %{_libdir}/libnss_libvirt_guest.so.2 %changelog +* Mon Jan 19 2026 Akhila Guruju - 7.10.0-11 +- Patch CVE-2025-12748 + * Wed May 22 2024 Juan Camposeco - 7.10.0-10 - Patch to address CVE-2024-4418 diff --git a/SPECS/libxml2/CVE-2025-7425.patch b/SPECS/libxml2/CVE-2025-7425.patch new file mode 100644 index 00000000000..ea3514d99cd --- /dev/null +++ b/SPECS/libxml2/CVE-2025-7425.patch @@ -0,0 +1,801 @@ +From 2aee165caa6a8c7b0f1a080b3c3e3dc26e35c35f Mon Sep 17 00:00:00 2001 +From: David Kilzer +Date: Mon, 23 Jun 2025 14:41:56 -0700 +Subject: [PATCH] libxslt: heap-use-after-free in xmlFreeID caused by `atype` + corruption + +* include/libxml/tree.h: +(XML_ATTR_CLEAR_ATYPE): Add. +(XML_ATTR_GET_ATYPE): Add. +(XML_ATTR_SET_ATYPE): Add. +(XML_NODE_ADD_EXTRA): Add. +(XML_NODE_CLEAR_EXTRA): Add. +(XML_NODE_GET_EXTRA): Add. +(XML_NODE_SET_EXTRA): Add. +(XML_DOC_ADD_PROPERTIES): Add. +(XML_DOC_CLEAR_PROPERTIES): Add. +(XML_DOC_GET_PROPERTIES): Add. +(XML_DOC_SET_PROPERTIES): Add. +- Add macros for accessing fields with upper bits that may be set by + libxslt. + +* HTMLparser.c: +(htmlNewDocNoDtD): +* SAX2.c: +(xmlSAX2StartDocument): +(xmlSAX2EndDocument): +* parser.c: +(xmlParseEntityDecl): +(xmlParseExternalSubset): +(xmlParseReference): +(xmlCtxtParseDtd): +* runxmlconf.c: +(xmlconfTestInvalid): +(xmlconfTestValid): +* tree.c: +(xmlNewDoc): +(xmlFreeProp): +(xmlNodeSetDoc): +(xmlSetNsProp): +(xmlDOMWrapAdoptBranch): +* valid.c: +(xmlFreeID): +(xmlAddIDInternal): +(xmlValidateAttributeValueInternal): +(xmlValidateOneAttribute): +(xmlValidateRef): +* xmlreader.c: +(xmlTextReaderStartElement): +(xmlTextReaderStartElementNs): +(xmlTextReaderValidateEntity): +(xmlTextReaderRead): +(xmlTextReaderNext): +(xmlTextReaderIsEmptyElement): +(xmlTextReaderPreserve): +* xmlschemas.c: +(xmlSchemaPValAttrNodeID): +* xmlschemastypes.c: +(xmlSchemaValAtomicType): +- Adopt macros by renaming the struct fields, recompiling and fixing + compiler failures, then changing the struct field names back. + +Upstream patch reference: https://gitlab.gnome.org/-/project/1762/uploads/302ecfda701895ebd0fa438a66d1a7a4/gnome-libxslt-bug-140-apple-fix.diff + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://raw.githubusercontent.com/akhila-guruju/azurelinux-test/ef30a4e2783c0aae0c8bf261a662babf70dec6f5/SPECS/libxml2/CVE-2025-7425.patch +--- + HTMLparser.c | 2 +- + SAX2.c | 6 ++-- + include/libxml/tree.h | 14 ++++++++- + parser.c | 8 ++--- + runxmlconf.c | 4 +-- + tree.c | 20 ++++++------- + valid.c | 68 +++++++++++++++++++++---------------------- + xmlreader.c | 30 +++++++++---------- + xmlschemas.c | 4 +-- + xmlschemastypes.c | 12 ++++---- + 10 files changed, 90 insertions(+), 78 deletions(-) + +diff --git a/HTMLparser.c b/HTMLparser.c +index ba88690..aa84f32 100644 +--- a/HTMLparser.c ++++ b/HTMLparser.c +@@ -2501,7 +2501,7 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) { + cur->refs = NULL; + cur->_private = NULL; + cur->charset = XML_CHAR_ENCODING_UTF8; +- cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT; ++ XML_DOC_SET_PROPERTIES(cur, XML_DOC_HTML | XML_DOC_USERBUILT); + if ((ExternalID != NULL) || + (URI != NULL)) + xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI); +diff --git a/SAX2.c b/SAX2.c +index 0d68590..0e89cdf 100644 +--- a/SAX2.c ++++ b/SAX2.c +@@ -949,7 +949,7 @@ xmlSAX2StartDocument(void *ctx) + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + return; + } +- ctxt->myDoc->properties = XML_DOC_HTML; ++ XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_HTML); + ctxt->myDoc->parseFlags = ctxt->options; + #else + xmlGenericError(xmlGenericErrorContext, +@@ -962,9 +962,9 @@ xmlSAX2StartDocument(void *ctx) + } else { + doc = ctxt->myDoc = xmlNewDoc(ctxt->version); + if (doc != NULL) { +- doc->properties = 0; ++ XML_DOC_CLEAR_PROPERTIES(doc); + if (ctxt->options & XML_PARSE_OLD10) +- doc->properties |= XML_DOC_OLD10; ++ XML_DOC_ADD_PROPERTIES(doc, XML_DOC_OLD10); + doc->parseFlags = ctxt->options; + if (ctxt->encoding != NULL) + doc->encoding = xmlStrdup(ctxt->encoding); +diff --git a/include/libxml/tree.h b/include/libxml/tree.h +index 98e2087..5973bef 100644 +--- a/include/libxml/tree.h ++++ b/include/libxml/tree.h +@@ -365,7 +365,6 @@ struct _xmlElement { + #endif + }; + +- + /** + * XML_LOCAL_NAMESPACE: + * +@@ -446,6 +445,10 @@ struct _xmlAttr { + void *psvi; /* for type/PSVI information */ + }; + ++#define XML_ATTR_CLEAR_ATYPE(attr) (((attr)->atype) = 0) ++#define XML_ATTR_GET_ATYPE(attr) (((attr)->atype) & ~(15U << 27)) ++#define XML_ATTR_SET_ATYPE(attr, type) ((attr)->atype = ((((attr)->atype) & (15U << 27)) | ((type) & ~(15U << 27)))) ++ + /** + * xmlID: + * +@@ -507,6 +510,11 @@ struct _xmlNode { + unsigned short extra; /* extra data for XPath/XSLT */ + }; + ++#define XML_NODE_ADD_EXTRA(node, type) ((node)->extra |= ((type) & ~(15U << 12))) ++#define XML_NODE_CLEAR_EXTRA(node) (((node)->extra) = 0) ++#define XML_NODE_GET_EXTRA(node) (((node)->extra) & ~(15U << 12)) ++#define XML_NODE_SET_EXTRA(node, type) ((node)->extra = ((((node)->extra) & (15U << 12)) | ((type) & ~(15U << 12)))) ++ + /** + * XML_GET_CONTENT: + * +@@ -585,6 +593,10 @@ struct _xmlDoc { + set at the end of parsing */ + }; + ++#define XML_DOC_ADD_PROPERTIES(doc, type) ((doc)->properties |= ((type) & ~(15U << 27))) ++#define XML_DOC_CLEAR_PROPERTIES(doc) (((doc)->properties) = 0) ++#define XML_DOC_GET_PROPERTIES(doc) (((doc)->properties) & ~(15U << 27)) ++#define XML_DOC_SET_PROPERTIES(doc, type) ((doc)->properties = ((((doc)->properties) & (15U << 27)) | ((type) & ~(15U << 27)))) + + typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt; + typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr; +diff --git a/parser.c b/parser.c +index 7947997..1e8a739 100644 +--- a/parser.c ++++ b/parser.c +@@ -5518,7 +5518,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { + xmlErrMemory(ctxt, "New Doc failed"); + return; + } +- ctxt->myDoc->properties = XML_DOC_INTERNAL; ++ XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_INTERNAL); + } + if (ctxt->myDoc->intSubset == NULL) + ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, +@@ -5589,7 +5589,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { + xmlErrMemory(ctxt, "New Doc failed"); + return; + } +- ctxt->myDoc->properties = XML_DOC_INTERNAL; ++ XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_INTERNAL); + } + + if (ctxt->myDoc->intSubset == NULL) +@@ -7030,7 +7030,7 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, + xmlErrMemory(ctxt, "New Doc failed"); + return; + } +- ctxt->myDoc->properties = XML_DOC_INTERNAL; ++ XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_INTERNAL); + } + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL)) + xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID); +@@ -7415,7 +7415,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { + (nw != NULL) && + (nw->type == XML_ELEMENT_NODE) && + (nw->children == NULL)) +- nw->extra = 1; ++ XML_NODE_SET_EXTRA(nw, 1); + + break; + } +diff --git a/runxmlconf.c b/runxmlconf.c +index 5e88f80..e217da2 100644 +--- a/runxmlconf.c ++++ b/runxmlconf.c +@@ -197,7 +197,7 @@ xmlconfTestInvalid(const char *id, const char *filename, int options) { + id, filename); + } else { + /* invalidity should be reported both in the context and in the document */ +- if ((ctxt->valid != 0) || (doc->properties & XML_DOC_DTDVALID)) { ++ if ((ctxt->valid != 0) || (XML_DOC_GET_PROPERTIES(doc) & XML_DOC_DTDVALID)) { + test_log("test %s : %s failed to detect invalid document\n", + id, filename); + nb_errors++; +@@ -229,7 +229,7 @@ xmlconfTestValid(const char *id, const char *filename, int options) { + ret = 0; + } else { + /* validity should be reported both in the context and in the document */ +- if ((ctxt->valid == 0) || ((doc->properties & XML_DOC_DTDVALID) == 0)) { ++ if ((ctxt->valid == 0) || ((XML_DOC_GET_PROPERTIES(doc) & XML_DOC_DTDVALID) == 0)) { + test_log("test %s : %s failed to validate a valid document\n", + id, filename); + nb_errors++; +diff --git a/tree.c b/tree.c +index c0b0d70..c22f52d 100644 +--- a/tree.c ++++ b/tree.c +@@ -1189,7 +1189,7 @@ xmlNewDoc(const xmlChar *version) { + cur->compression = -1; /* not initialized */ + cur->doc = cur; + cur->parseFlags = 0; +- cur->properties = XML_DOC_USERBUILT; ++ XML_DOC_SET_PROPERTIES(cur, XML_DOC_USERBUILT); + /* + * The in memory encoding is always UTF8 + * This field will never change and would +@@ -2116,7 +2116,7 @@ xmlFreeProp(xmlAttrPtr cur) { + xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); + + /* Check for ID removal -> leading to invalid references ! */ +- if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { ++ if ((cur->doc != NULL) && (XML_ATTR_GET_ATYPE(cur) == XML_ATTRIBUTE_ID)) { + xmlRemoveID(cur->doc, cur); + } + if (cur->children != NULL) xmlFreeNodeList(cur->children); +@@ -2864,7 +2864,7 @@ xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { + if(tree->type == XML_ELEMENT_NODE) { + prop = tree->properties; + while (prop != NULL) { +- if (prop->atype == XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(prop) == XML_ATTRIBUTE_ID) { + xmlRemoveID(tree->doc, prop); + } + +@@ -7016,9 +7016,9 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, + /* + * Modify the attribute's value. + */ +- if (prop->atype == XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(prop) == XML_ATTRIBUTE_ID) { + xmlRemoveID(node->doc, prop); +- prop->atype = XML_ATTRIBUTE_ID; ++ XML_ATTR_SET_ATYPE(prop, XML_ATTRIBUTE_ID); + } + if (prop->children != NULL) + xmlFreeNodeList(prop->children); +@@ -7038,7 +7038,7 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, + tmp = tmp->next; + } + } +- if (prop->atype == XML_ATTRIBUTE_ID) ++ if (XML_ATTR_GET_ATYPE(prop) == XML_ATTRIBUTE_ID) + xmlAddID(NULL, node->doc, value, prop); + return(prop); + } +@@ -9328,7 +9328,7 @@ ns_end: + if (cur->type == XML_ELEMENT_NODE) { + cur->psvi = NULL; + cur->line = 0; +- cur->extra = 0; ++ XML_NODE_CLEAR_EXTRA(cur); + /* + * Walk attributes. + */ +@@ -9344,11 +9344,11 @@ ns_end: + * Attributes. + */ + if ((sourceDoc != NULL) && +- (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) ++ (XML_ATTR_GET_ATYPE((xmlAttrPtr) cur) == XML_ATTRIBUTE_ID)) + { + xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); + } +- ((xmlAttrPtr) cur)->atype = 0; ++ XML_ATTR_CLEAR_ATYPE((xmlAttrPtr) cur); + ((xmlAttrPtr) cur)->psvi = NULL; + } + break; +@@ -10069,7 +10069,7 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, + } + + XML_TREE_ADOPT_STR(attr->name); +- attr->atype = 0; ++ XML_ATTR_CLEAR_ATYPE(attr); + attr->psvi = NULL; + /* + * Walk content. +diff --git a/valid.c b/valid.c +index 7a5be3e..fe93341 100644 +--- a/valid.c ++++ b/valid.c +@@ -1891,7 +1891,7 @@ xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) { + if (elem == NULL) return(0); + cur = elem->attributes; + while (cur != NULL) { +- if (cur->atype == XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(cur) == XML_ATTRIBUTE_ID) { + ret ++; + if ((ret > 1) && (err)) + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID, +@@ -2264,7 +2264,7 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, attr->name); +- switch (attr->atype) { ++ switch (XML_ATTR_GET_ATYPE(attr)) { + case XML_ATTRIBUTE_CDATA: + xmlBufferWriteChar(buf, " CDATA"); + break; +@@ -2737,7 +2737,7 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, + return(NULL); + } + if (attr != NULL) +- attr->atype = XML_ATTRIBUTE_ID; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_ID); + return(ret); + } + +@@ -2816,7 +2816,7 @@ xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { + if ((fullelemname != felem) && (fullelemname != elem->name)) + xmlFree(fullelemname); + +- if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) ++ if ((attrDecl != NULL) && (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ID)) + return(1); + } + return(0); +@@ -2857,7 +2857,7 @@ xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { + + xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry); + xmlFree(ID); +- attr->atype = 0; ++ XML_ATTR_CLEAR_ATYPE(attr); + return(0); + } + +@@ -3142,8 +3142,8 @@ xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { + elem->name, attr->name); + + if ((attrDecl != NULL) && +- (attrDecl->atype == XML_ATTRIBUTE_IDREF || +- attrDecl->atype == XML_ATTRIBUTE_IDREFS)) ++ (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREF || ++ XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREFS)) + return(1); + } + return(0); +@@ -3521,7 +3521,7 @@ xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { + + static int + xmlIsDocNameStartChar(xmlDocPtr doc, int c) { +- if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { ++ if ((doc == NULL) || (XML_DOC_GET_PROPERTIES(doc) & XML_DOC_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 +@@ -3551,7 +3551,7 @@ xmlIsDocNameStartChar(xmlDocPtr doc, int c) { + + static int + xmlIsDocNameChar(xmlDocPtr doc, int c) { +- if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { ++ if ((doc == NULL) || (XML_DOC_GET_PROPERTIES(doc) & XML_DOC_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 +@@ -4101,7 +4101,7 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + + if (attrDecl == NULL) + return(NULL); +- if (attrDecl->atype == XML_ATTRIBUTE_CDATA) ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_CDATA) + return(NULL); + + ret = xmlStrdup(value); +@@ -4163,7 +4163,7 @@ xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, + + if (attrDecl == NULL) + return(NULL); +- if (attrDecl->atype == XML_ATTRIBUTE_CDATA) ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_CDATA) + return(NULL); + + ret = xmlStrdup(value); +@@ -4178,7 +4178,7 @@ xmlValidateAttributeIdCallback(void *payload, void *data, + const xmlChar *name ATTRIBUTE_UNUSED) { + xmlAttributePtr attr = (xmlAttributePtr) payload; + int *count = (int *) data; +- if (attr->atype == XML_ATTRIBUTE_ID) (*count)++; ++ if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID) (*count)++; + } + + /** +@@ -4210,7 +4210,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + /* Attribute Default Legal */ + /* Enumeration */ + if (attr->defaultValue != NULL) { +- val = xmlValidateAttributeValueInternal(doc, attr->atype, ++ val = xmlValidateAttributeValueInternal(doc, XML_ATTR_GET_ATYPE(attr), + attr->defaultValue); + if (val == 0) { + xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT, +@@ -4221,7 +4221,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + } + + /* ID Attribute Default */ +- if ((attr->atype == XML_ATTRIBUTE_ID)&& ++ if ((XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID)&& + (attr->def != XML_ATTRIBUTE_IMPLIED) && + (attr->def != XML_ATTRIBUTE_REQUIRED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED, +@@ -4231,7 +4231,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + } + + /* One ID per Element Type */ +- if (attr->atype == XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID) { + int nbId; + + /* the trick is that we parse DtD as their own internal subset */ +@@ -4490,9 +4490,9 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + attr->name, elem->name, NULL); + return(0); + } +- attr->atype = attrDecl->atype; ++ XML_ATTR_SET_ATYPE(attr, attrDecl->atype); + +- val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); ++ val = xmlValidateAttributeValueInternal(doc, XML_ATTR_GET_ATYPE(attrDecl), value); + if (val == 0) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, + "Syntax of value for attribute %s of %s is not valid\n", +@@ -4511,19 +4511,19 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + } + + /* Validity Constraint: ID uniqueness */ +- if (attrDecl->atype == XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ID) { + if (xmlAddID(ctxt, doc, value, attr) == NULL) + ret = 0; + } + +- if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || +- (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { ++ if ((XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREF) || ++ (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREFS)) { + if (xmlAddRef(ctxt, doc, value, attr) == NULL) + ret = 0; + } + + /* Validity Constraint: Notation Attributes */ +- if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_NOTATION) { + xmlEnumerationPtr tree = attrDecl->tree; + xmlNotationPtr nota; + +@@ -4553,7 +4553,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + } + + /* Validity Constraint: Enumeration */ +- if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ENUMERATION) { + xmlEnumerationPtr tree = attrDecl->tree; + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; +@@ -4578,7 +4578,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + + /* Extra check for the attribute value */ + ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name, +- attrDecl->atype, value); ++ XML_ATTR_GET_ATYPE(attrDecl), value); + + return(ret); + } +@@ -4677,7 +4677,7 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { + return(0); + } + +- val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); ++ val = xmlValidateAttributeValueInternal(doc, XML_ATTR_GET_ATYPE(attrDecl), value); + if (val == 0) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, +@@ -4727,7 +4727,7 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { + #endif + + /* Validity Constraint: Notation Attributes */ +- if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_NOTATION) { + xmlEnumerationPtr tree = attrDecl->tree; + xmlNotationPtr nota; + +@@ -4769,7 +4769,7 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { + } + + /* Validity Constraint: Enumeration */ +- if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { ++ if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ENUMERATION) { + xmlEnumerationPtr tree = attrDecl->tree; + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; +@@ -4807,10 +4807,10 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { + /* Extra check for the attribute value */ + if (ns->prefix != NULL) { + ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix, +- attrDecl->atype, value); ++ XML_ATTR_GET_ATYPE(attrDecl), value); + } else { + ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns", +- attrDecl->atype, value); ++ XML_ATTR_GET_ATYPE(attrDecl), value); + } + + return(ret); +@@ -6560,7 +6560,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, + while (IS_BLANK_CH(*cur)) cur++; + } + xmlFree(dup); +- } else if (attr->atype == XML_ATTRIBUTE_IDREF) { ++ } else if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_IDREF) { + id = xmlGetID(ctxt->doc, name); + if (id == NULL) { + xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, +@@ -6568,7 +6568,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, + attr->name, name, NULL); + ctxt->valid = 0; + } +- } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { ++ } else if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_IDREFS) { + xmlChar *dup, *str = NULL, *cur, save; + + dup = xmlStrdup(name); +@@ -6768,7 +6768,7 @@ xmlValidateAttributeCallback(void *payload, void *data, + + if (cur == NULL) + return; +- switch (cur->atype) { ++ switch (XML_ATTR_GET_ATYPE(cur)) { + case XML_ATTRIBUTE_CDATA: + case XML_ATTRIBUTE_ID: + case XML_ATTRIBUTE_IDREF : +@@ -6783,7 +6783,7 @@ xmlValidateAttributeCallback(void *payload, void *data, + if (cur->defaultValue != NULL) { + + ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, +- cur->atype, cur->defaultValue); ++ XML_ATTR_GET_ATYPE(cur), cur->defaultValue); + if ((ret == 0) && (ctxt->valid == 1)) + ctxt->valid = 0; + } +@@ -6791,14 +6791,14 @@ xmlValidateAttributeCallback(void *payload, void *data, + xmlEnumerationPtr tree = cur->tree; + while (tree != NULL) { + ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, +- cur->name, cur->atype, tree->name); ++ cur->name, XML_ATTR_GET_ATYPE(cur), tree->name); + if ((ret == 0) && (ctxt->valid == 1)) + ctxt->valid = 0; + tree = tree->next; + } + } + } +- if (cur->atype == XML_ATTRIBUTE_NOTATION) { ++ if (XML_ATTR_GET_ATYPE(cur) == XML_ATTRIBUTE_NOTATION) { + doc = cur->doc; + if (cur->elem == NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, +diff --git a/xmlreader.c b/xmlreader.c +index daa2685..bbeb5f3 100644 +--- a/xmlreader.c ++++ b/xmlreader.c +@@ -613,7 +613,7 @@ xmlTextReaderStartElement(void *ctx, const xmlChar *fullname, + if ((ctxt->node != NULL) && (ctxt->input != NULL) && + (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && + (ctxt->input->cur[1] == '>')) +- ctxt->node->extra = NODE_IS_EMPTY; ++ XML_NODE_SET_EXTRA(ctxt->node, NODE_IS_EMPTY); + } + if (reader != NULL) + reader->state = XML_TEXTREADER_ELEMENT; +@@ -678,7 +678,7 @@ xmlTextReaderStartElementNs(void *ctx, + if ((ctxt->node != NULL) && (ctxt->input != NULL) && + (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && + (ctxt->input->cur[1] == '>')) +- ctxt->node->extra = NODE_IS_EMPTY; ++ XML_NODE_SET_EXTRA(ctxt->node, NODE_IS_EMPTY); + } + if (reader != NULL) + reader->state = XML_TEXTREADER_ELEMENT; +@@ -1076,7 +1076,7 @@ skip_children: + xmlNodePtr tmp; + if (reader->entNr == 0) { + while ((tmp = node->last) != NULL) { +- if ((tmp->extra & NODE_IS_PRESERVED) == 0) { ++ if ((XML_NODE_GET_EXTRA(tmp) & NODE_IS_PRESERVED) == 0) { + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); + } else +@@ -1328,7 +1328,7 @@ get_next_node: + if ((oldstate == XML_TEXTREADER_ELEMENT) && + (reader->node->type == XML_ELEMENT_NODE) && + (reader->node->children == NULL) && +- ((reader->node->extra & NODE_IS_EMPTY) == 0) ++ ((XML_NODE_GET_EXTRA(reader->node) & NODE_IS_EMPTY) == 0) + #ifdef LIBXML_XINCLUDE_ENABLED + && (reader->in_xinclude <= 0) + #endif +@@ -1342,7 +1342,7 @@ get_next_node: + xmlTextReaderValidatePop(reader); + #endif /* LIBXML_REGEXP_ENABLED */ + if ((reader->preserves > 0) && +- (reader->node->extra & NODE_IS_SPRESERVED)) ++ (XML_NODE_GET_EXTRA(reader->node) & NODE_IS_SPRESERVED)) + reader->preserves--; + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_ELEMENT; +@@ -1358,7 +1358,7 @@ get_next_node: + (reader->node->prev != NULL) && + (reader->node->prev->type != XML_DTD_NODE)) { + xmlNodePtr tmp = reader->node->prev; +- if ((tmp->extra & NODE_IS_PRESERVED) == 0) { ++ if ((XML_NODE_GET_EXTRA(tmp) & NODE_IS_PRESERVED) == 0) { + if (oldnode == tmp) + oldnode = NULL; + xmlUnlinkNode(tmp); +@@ -1371,7 +1371,7 @@ get_next_node: + if ((oldstate == XML_TEXTREADER_ELEMENT) && + (reader->node->type == XML_ELEMENT_NODE) && + (reader->node->children == NULL) && +- ((reader->node->extra & NODE_IS_EMPTY) == 0)) {; ++ ((XML_NODE_GET_EXTRA(reader->node) & NODE_IS_EMPTY) == 0)) {; + reader->state = XML_TEXTREADER_END; + goto node_found; + } +@@ -1380,7 +1380,7 @@ get_next_node: + xmlTextReaderValidatePop(reader); + #endif /* LIBXML_REGEXP_ENABLED */ + if ((reader->preserves > 0) && +- (reader->node->extra & NODE_IS_SPRESERVED)) ++ (XML_NODE_GET_EXTRA(reader->node) & NODE_IS_SPRESERVED)) + reader->preserves--; + reader->node = reader->node->parent; + if ((reader->node == NULL) || +@@ -1404,7 +1404,7 @@ get_next_node: + #endif + (reader->entNr == 0) && + (oldnode->type != XML_DTD_NODE) && +- ((oldnode->extra & NODE_IS_PRESERVED) == 0)) { ++ ((XML_NODE_GET_EXTRA(oldnode) & NODE_IS_PRESERVED) == 0)) { + xmlUnlinkNode(oldnode); + xmlTextReaderFreeNode(reader, oldnode); + } +@@ -1417,7 +1417,7 @@ get_next_node: + #endif + (reader->entNr == 0) && + (reader->node->last != NULL) && +- ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) { ++ ((XML_NODE_GET_EXTRA(reader->node->last) & NODE_IS_PRESERVED) == 0)) { + xmlNodePtr tmp = reader->node->last; + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); +@@ -1599,7 +1599,7 @@ xmlTextReaderNext(xmlTextReaderPtr reader) { + return(xmlTextReaderRead(reader)); + if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK) + return(xmlTextReaderRead(reader)); +- if (cur->extra & NODE_IS_EMPTY) ++ if (XML_NODE_GET_EXTRA(cur) & NODE_IS_EMPTY) + return(xmlTextReaderRead(reader)); + do { + ret = xmlTextReaderRead(reader); +@@ -3022,7 +3022,7 @@ xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) { + if (reader->in_xinclude > 0) + return(1); + #endif +- return((reader->node->extra & NODE_IS_EMPTY) != 0); ++ return((XML_NODE_GET_EXTRA(reader->node) & NODE_IS_EMPTY) != 0); + } + + /** +@@ -3884,15 +3884,15 @@ xmlTextReaderPreserve(xmlTextReaderPtr reader) { + return(NULL); + + if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) { +- cur->extra |= NODE_IS_PRESERVED; +- cur->extra |= NODE_IS_SPRESERVED; ++ XML_NODE_ADD_EXTRA(cur, NODE_IS_PRESERVED); ++ XML_NODE_ADD_EXTRA(cur, NODE_IS_SPRESERVED); + } + reader->preserves++; + + parent = cur->parent;; + while (parent != NULL) { + if (parent->type == XML_ELEMENT_NODE) +- parent->extra |= NODE_IS_PRESERVED; ++ XML_NODE_ADD_EXTRA(parent, NODE_IS_PRESERVED); + parent = parent->parent; + } + return(cur); +diff --git a/xmlschemas.c b/xmlschemas.c +index 8cae008..92344d3 100644 +--- a/xmlschemas.c ++++ b/xmlschemas.c +@@ -6024,7 +6024,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) + /* + * NOTE: the IDness might have already be declared in the DTD + */ +- if (attr->atype != XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(attr) != XML_ATTRIBUTE_ID) { + xmlIDPtr res; + xmlChar *strip; + +@@ -6047,7 +6047,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) + NULL, NULL, "Duplicate value '%s' of simple " + "type 'xs:ID'", value, NULL); + } else +- attr->atype = XML_ATTRIBUTE_ID; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_ID); + } + } else if (ret > 0) { + ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; +diff --git a/xmlschemastypes.c b/xmlschemastypes.c +index 26c033d..af703f0 100644 +--- a/xmlschemastypes.c ++++ b/xmlschemastypes.c +@@ -2868,7 +2868,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + /* + * NOTE: the IDness might have already be declared in the DTD + */ +- if (attr->atype != XML_ATTRIBUTE_ID) { ++ if (XML_ATTR_GET_ATYPE(attr) != XML_ATTRIBUTE_ID) { + xmlIDPtr res; + xmlChar *strip; + +@@ -2881,7 +2881,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + if (res == NULL) { + ret = 2; + } else { +- attr->atype = XML_ATTRIBUTE_ID; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_ID); + } + } + } +@@ -2906,7 +2906,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + xmlFree(strip); + } else + xmlAddRef(NULL, node->doc, value, attr); +- attr->atype = XML_ATTRIBUTE_IDREF; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_IDREF); + } + goto done; + case XML_SCHEMAS_IDREFS: +@@ -2920,7 +2920,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + +- attr->atype = XML_ATTRIBUTE_IDREFS; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_IDREFS); + } + goto done; + case XML_SCHEMAS_ENTITY:{ +@@ -2951,7 +2951,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + +- attr->atype = XML_ATTRIBUTE_ENTITY; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_ENTITY); + } + goto done; + } +@@ -2968,7 +2968,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + +- attr->atype = XML_ATTRIBUTE_ENTITIES; ++ XML_ATTR_SET_ATYPE(attr, XML_ATTRIBUTE_ENTITIES); + } + goto done; + case XML_SCHEMAS_NOTATION:{ +-- +2.45.4 + diff --git a/SPECS/libxml2/CVE-2026-0990.patch b/SPECS/libxml2/CVE-2026-0990.patch new file mode 100644 index 00000000000..0e998592b98 --- /dev/null +++ b/SPECS/libxml2/CVE-2026-0990.patch @@ -0,0 +1,78 @@ +From 9f4c3269fbe63615c4f9df620f734399ae04e307 Mon Sep 17 00:00:00 2001 +From: Daniel Garcia Moreno +Date: Wed, 17 Dec 2025 15:24:08 +0100 +Subject: [PATCH] catalog: prevent inf recursion in xmlCatalogXMLResolveURI + +Fix https://gitlab.gnome.org/GNOME/libxml2/-/issues/1018 + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://gitlab.gnome.org/GNOME/libxml2/-/commit/1961208e958ca22f80a0b4e4c9d71cfa050aa982.patch +--- + catalog.c | 31 +++++++++++++++++++++++-------- + 1 file changed, 23 insertions(+), 8 deletions(-) + +diff --git a/catalog.c b/catalog.c +index b7837e3..d66ee45 100644 +--- a/catalog.c ++++ b/catalog.c +@@ -2091,12 +2091,21 @@ static xmlChar * + xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { + xmlChar *ret = NULL; + xmlChar *urnID = NULL; ++ xmlCatalogEntryPtr cur = NULL; + + if (catal == NULL) + return(NULL); + if (URI == NULL) + return(NULL); + ++ if (catal->depth > MAX_CATAL_DEPTH) { ++ xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION, ++ "Detected recursion in catalog %s\n", ++ catal->name, NULL, NULL); ++ return(NULL); ++ } ++ catal->depth++; ++ + if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { + urnID = xmlCatalogUnWrapURN(URI); + if (xmlDebugCatalogs) { +@@ -2110,21 +2119,27 @@ xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { + ret = xmlCatalogListXMLResolve(catal, urnID, NULL); + if (urnID != NULL) + xmlFree(urnID); ++ catal->depth--; + return(ret); + } +- while (catal != NULL) { +- if (catal->type == XML_CATA_CATALOG) { +- if (catal->children == NULL) { +- xmlFetchXMLCatalogFile(catal); ++ cur = catal; ++ while (cur != NULL) { ++ if (cur->type == XML_CATA_CATALOG) { ++ if (cur->children == NULL) { ++ xmlFetchXMLCatalogFile(cur); + } +- if (catal->children != NULL) { +- ret = xmlCatalogXMLResolveURI(catal->children, URI); +- if (ret != NULL) ++ if (cur->children != NULL) { ++ ret = xmlCatalogXMLResolveURI(cur->children, URI); ++ if (ret != NULL) { ++ catal->depth--; + return(ret); ++ } + } + } +- catal = catal->next; ++ cur = cur->next; + } ++ ++ catal->depth--; + return(ret); + } + +-- +2.45.4 + diff --git a/SPECS/libxml2/CVE-2026-0992.patch b/SPECS/libxml2/CVE-2026-0992.patch new file mode 100644 index 00000000000..253a5240cb3 --- /dev/null +++ b/SPECS/libxml2/CVE-2026-0992.patch @@ -0,0 +1,85 @@ +rom f75abfcaa419a740a3191e56c60400f3ff18988d Mon Sep 17 00:00:00 2001 +From: Daniel Garcia Moreno +Date: Fri, 19 Dec 2025 11:02:18 +0100 +Subject: [PATCH] catalog: Ignore repeated nextCatalog entries + +This patch makes the catalog parsing to ignore repeated entries of +nextCatalog with the same value. + +Fix https://gitlab.gnome.org/GNOME/libxml2/-/issues/1019 + +Upstream Patch reference: https://gitlab.gnome.org/GNOME/libxml2/-/commit/f75abfcaa419a740a3191e56c60400f3ff18988d.patch +--- + catalog.c | 26 ++++++++++++++++++++++++++ + error.c | 11 +++++++++++ + 2 files changed, 37 insertions(+) + +diff --git a/catalog.c b/catalog.c +index 20e9576..3886d84 100644 +--- a/catalog.c ++++ b/catalog.c +@@ -242,6 +242,14 @@ xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error, + msg, str1, str2, str3); + } + ++static void ++xmlCatalogPrintDebug(const char *fmt, ...) { ++ va_list ap; ++ ++ va_start(ap, fmt); ++ xmlVPrintErrorMessage(fmt, ap); ++ va_end(ap); ++} + + /************************************************************************ + * * +@@ -1267,9 +1275,27 @@ xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, + BAD_CAST "delegateURI", BAD_CAST "uriStartString", + BAD_CAST "catalog", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { ++ xmlCatalogEntryPtr prev = parent->children; ++ + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, + BAD_CAST "nextCatalog", NULL, + BAD_CAST "catalog", prefer, cgroup); ++ /* Avoid duplication of nextCatalog */ ++ while (prev != NULL) { ++ if ((prev->type == XML_CATA_NEXT_CATALOG) && ++ (xmlStrEqual (prev->URL, entry->URL)) && ++ (xmlStrEqual (prev->value, entry->value)) && ++ (prev->prefer == entry->prefer) && ++ (prev->group == entry->group)) { ++ if (xmlDebugCatalogs) ++ xmlCatalogPrintDebug( ++ "Ignoring repeated nextCatalog %s\n", entry->URL); ++ xmlFreeCatalogEntry(entry, NULL); ++ entry = NULL; ++ break; ++ } ++ prev = prev->next; ++ } + } + if (entry != NULL) { + if (parent != NULL) { +diff --git a/error.c b/error.c +index 4de1418..a77e2da 100644 +--- a/error.c ++++ b/error.c +@@ -1022,3 +1022,14 @@ xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { + return 0; + } + ++/** ++ * Prints to stderr. ++ * ++ * @param fmt printf-like format string ++ * @param ap arguments ++ */ ++void ++xmlVPrintErrorMessage(const char *fmt, va_list ap) { ++ vfprintf(stderr, fmt, ap); ++} ++ +-- +2.43.0 + diff --git a/SPECS/libxml2/libxml2.spec b/SPECS/libxml2/libxml2.spec index 7cc048945cf..a28d3c9cddb 100644 --- a/SPECS/libxml2/libxml2.spec +++ b/SPECS/libxml2/libxml2.spec @@ -1,7 +1,7 @@ Summary: Libxml2 Name: libxml2 Version: 2.10.4 -Release: 9%{?dist} +Release: 10%{?dist} License: MIT Vendor: Microsoft Corporation Distribution: Mariner @@ -21,6 +21,9 @@ Patch9: CVE-2025-6170.patch Patch10: CVE-2025-6021.patch Patch11: CVE-2025-49794_CVE-2025-49796.patch Patch12: CVE-2025-49795.patch +Patch13: CVE-2025-7425.patch +Patch14: CVE-2026-0990.patch +Patch15: CVE-2026-0992.patch BuildRequires: python3-devel BuildRequires: python3-xml Provides: %{name}-tools = %{version}-%{release} @@ -91,6 +94,9 @@ find %{buildroot} -type f -name "*.la" -delete -print %{_libdir}/cmake/libxml2/libxml2-config.cmake %changelog +* Tue Jan 27 2026 Azure Linux Security Servicing Account - 2.10.4-10 +- Patch for CVE-2026-0992, CVE-2026-0990, CVE-2025-7425 + * Wed Oct 29 2025 Azure Linux Security Servicing Account - 2.10.4-9 - Patch for CVE-2025-49795 diff --git a/SPECS/msft-golang/msft-golang.signatures.json b/SPECS/msft-golang/msft-golang.signatures.json index eeaae08bfa9..e76d8f1a342 100644 --- a/SPECS/msft-golang/msft-golang.signatures.json +++ b/SPECS/msft-golang/msft-golang.signatures.json @@ -3,7 +3,7 @@ "go.20230802.5.src.tar.gz": "56b9e0e0c3c13ca95d5efa6de4e7d49a9d190eca77919beff99d33cd3fa74e95", "go.20240206.2.src.tar.gz": "7982e0011aa9ab95fd0530404060410af4ba57326d26818690f334fdcb6451cd", "go1.22.12-20250211.4.src.tar.gz": "e1cc3bff8fdf1f24843ffc9f0eaddfd344eb40fd9ca0d9ba2965165be519eeb7", - "go1.24.11-20251202.3.src.tar.gz": "7867b785bb3eb9c581f5d2a5f4bcf3b9d5111805ceec222065a9c31c049a8e05", + "go1.24.12-20260116.10.src.tar.gz": "d449be4b3ec37831f8515da709764c9a17e8ad758be981b71b9f79b2ed6e38bd", "go1.4-bootstrap-20171003.tar.gz": "f4ff5b5eb3a3cae1c993723f3eab519c5bae18866b5e5f96fe1102f0cb5c3e52" } } diff --git a/SPECS/msft-golang/msft-golang.spec b/SPECS/msft-golang/msft-golang.spec index 1c862eaf86f..22254409ff4 100644 --- a/SPECS/msft-golang/msft-golang.spec +++ b/SPECS/msft-golang/msft-golang.spec @@ -1,6 +1,6 @@ %global goroot %{_libdir}/golang %global gopath %{_datadir}/gocode -%global ms_go_filename go1.24.11-20251202.3.src.tar.gz +%global ms_go_filename go1.24.12-20260116.10.src.tar.gz %global ms_go_revision 1 %ifarch aarch64 %global gohostarch arm64 @@ -14,7 +14,7 @@ %define __find_requires %{nil} Summary: Go Name: msft-golang -Version: 1.24.11 +Version: 1.24.12 Release: 1%{?dist} License: BSD Vendor: Microsoft Corporation @@ -158,6 +158,9 @@ fi %{_bindir}/* %changelog +* Wed Jan 21 2026 Kanishk Bansal - 1.24.12-1 +- Upgrade to 1.24.12 + * Thu Dec 04 2025 Kanishk Bansal - 1.24.11-1 - Upgrade to 1.24.11 diff --git a/SPECS/nodejs/CVE-2025-55131.patch b/SPECS/nodejs/CVE-2025-55131.patch new file mode 100644 index 00000000000..2c37b3c7380 --- /dev/null +++ b/SPECS/nodejs/CVE-2025-55131.patch @@ -0,0 +1,306 @@ +From 51f4de4b4a52b5b0eb2c63ecbb4126577e05f636 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=A1=D0=BA=D0=BE=D0=B2=D0=BE=D1=80=D0=BE=D0=B4=D0=B0=20?= + =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=90=D0=BD=D0=B4=D1=80?= + =?UTF-8?q?=D0=B5=D0=B5=D0=B2=D0=B8=D1=87?= +Date: Fri, 7 Nov 2025 11:50:57 -0300 +Subject: [PATCH] src,lib: refactor unsafe buffer creation to remove zero-fill + toggle + +This removes the zero-fill toggle mechanism that allowed JavaScript +to control ArrayBuffer initialization via shared memory. Instead, +unsafe buffer creation now uses a dedicated C++ API. + +Refs: https://hackerone.com/reports/3405778 +Co-Authored-By: Rafael Gonzaga +Co-Authored-By: Joyee Cheung +Signed-off-by: RafaelGSS +PR-URL: https://github.com/nodejs-private/node-private/pull/759 +Backport-PR-URL: https://github.com/nodejs-private/node-private/pull/799 +CVE-ID: CVE-2025-55131 + +Upstream Patch Reference: https://github.com/nodejs/node/commit/51f4de4b4a.patch +--- + deps/v8/include/v8-array-buffer.h | 7 +++ + deps/v8/src/api/api.cc | 17 ++++++ + lib/internal/buffer.js | 23 ++----- + lib/internal/process/pre_execution.js | 2 - + src/api/environment.cc | 3 +- + src/node_buffer.cc | 86 ++++++++++++++++----------- + 6 files changed, 83 insertions(+), 55 deletions(-) + +diff --git a/deps/v8/include/v8-array-buffer.h b/deps/v8/include/v8-array-buffer.h +index cc5d2d43..bf1df3e7 100644 +--- a/deps/v8/include/v8-array-buffer.h ++++ b/deps/v8/include/v8-array-buffer.h +@@ -223,6 +223,13 @@ class V8_EXPORT ArrayBuffer : public Object { + */ + static std::unique_ptr NewBackingStore(Isolate* isolate, + size_t byte_length); ++ /** ++ * Returns a new standalone BackingStore with uninitialized memory and ++ * return nullptr on failure. ++ * This variant is for not breaking ABI on Node.js LTS. DO NOT USE. ++ */ ++ static std::unique_ptr NewBackingStoreForNodeLTS( ++ Isolate* isolate, size_t byte_length); + /** + * Returns a new standalone BackingStore that takes over the ownership of + * the given buffer. The destructor of the BackingStore invokes the given +diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc +index 3b1a8168..e542eb5a 100644 +--- a/deps/v8/src/api/api.cc ++++ b/deps/v8/src/api/api.cc +@@ -8213,6 +8213,23 @@ std::unique_ptr v8::SharedArrayBuffer::NewBackingStore( + static_cast(backing_store.release())); + } + ++std::unique_ptr v8::ArrayBuffer::NewBackingStoreForNodeLTS( ++ Isolate* v8_isolate, size_t byte_length) { ++ i::Isolate* i_isolate = reinterpret_cast(v8_isolate); ++ API_RCS_SCOPE(i_isolate, ArrayBuffer, NewBackingStore); ++ CHECK_LE(byte_length, i::JSArrayBuffer::kMaxByteLength); ++ ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); ++ std::unique_ptr backing_store = ++ i::BackingStore::Allocate(i_isolate, byte_length, ++ i::SharedFlag::kNotShared, ++ i::InitializedFlag::kUninitialized); ++ if (!backing_store) { ++ return nullptr; ++ } ++ return std::unique_ptr( ++ static_cast(backing_store.release())); ++} ++ + std::unique_ptr v8::SharedArrayBuffer::NewBackingStore( + void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, + void* deleter_data) { +diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js +index fbe9de24..23df382f 100644 +--- a/lib/internal/buffer.js ++++ b/lib/internal/buffer.js +@@ -30,7 +30,7 @@ const { + hexWrite, + ucs2Write, + utf8Write, +- getZeroFillToggle, ++ createUnsafeArrayBuffer, + } = internalBinding('buffer'); + + const { +@@ -1053,26 +1053,14 @@ function markAsUntransferable(obj) { + obj[untransferable_object_private_symbol] = true; + } + +-// A toggle used to access the zero fill setting of the array buffer allocator +-// in C++. +-// |zeroFill| can be undefined when running inside an isolate where we +-// do not own the ArrayBuffer allocator. Zero fill is always on in that case. +-let zeroFill = getZeroFillToggle(); + function createUnsafeBuffer(size) { +- zeroFill[0] = 0; +- try { ++ if (size <= 64) { ++ // Allocated in heap, doesn't call backing store anyway ++ // This is the same that the old impl did implicitly, but explicit now + return new FastBuffer(size); +- } finally { +- zeroFill[0] = 1; + } +-} + +-// The connection between the JS land zero fill toggle and the +-// C++ one in the NodeArrayBufferAllocator gets lost if the toggle +-// is deserialized from the snapshot, because V8 owns the underlying +-// memory of this toggle. This resets the connection. +-function reconnectZeroFillToggle() { +- zeroFill = getZeroFillToggle(); ++ return new FastBuffer(createUnsafeArrayBuffer(size)); + } + + module.exports = { +@@ -1082,5 +1070,4 @@ module.exports = { + createUnsafeBuffer, + readUInt16BE, + readUInt32BE, +- reconnectZeroFillToggle, + }; +diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js +index 4795be82..f95ab3de 100644 +--- a/lib/internal/process/pre_execution.js ++++ b/lib/internal/process/pre_execution.js +@@ -16,7 +16,6 @@ const { + getOptionValue, + refreshOptions, + } = require('internal/options'); +-const { reconnectZeroFillToggle } = require('internal/buffer'); + const { + defineOperation, + exposeInterface, +@@ -56,7 +55,6 @@ function prepareExecution(options) { + const { expandArgv1, initializeModules, isMainThread } = options; + + refreshRuntimeOptions(); +- reconnectZeroFillToggle(); + + // Patch the process object and get the resolved main entry point. + const mainEntry = patchProcessObject(expandArgv1); +diff --git a/src/api/environment.cc b/src/api/environment.cc +index de58a26f..cbe77199 100644 +--- a/src/api/environment.cc ++++ b/src/api/environment.cc +@@ -104,8 +104,9 @@ void* NodeArrayBufferAllocator::Allocate(size_t size) { + ret = allocator_->Allocate(size); + else + ret = allocator_->AllocateUninitialized(size); +- if (LIKELY(ret != nullptr)) ++ if (ret != nullptr) [[likely]] { + total_mem_usage_.fetch_add(size, std::memory_order_relaxed); ++ } + return ret; + } + +diff --git a/src/node_buffer.cc b/src/node_buffer.cc +index 4bc7336e..cf284fd6 100644 +--- a/src/node_buffer.cc ++++ b/src/node_buffer.cc +@@ -72,7 +72,6 @@ using v8::Object; + using v8::SharedArrayBuffer; + using v8::String; + using v8::Uint32; +-using v8::Uint32Array; + using v8::Uint8Array; + using v8::Value; + +@@ -1207,7 +1206,7 @@ static void EncodeInto(const FunctionCallbackInfo& args) { + size_t dest_length = dest->ByteLength(); + + // results = [ read, written ] +- Local result_arr = args[2].As(); ++ Local result_arr = args[2].As(); + uint32_t* results = reinterpret_cast( + static_cast(result_arr->Buffer()->Data()) + + result_arr->ByteOffset()); +@@ -1261,35 +1260,6 @@ void SetBufferPrototype(const FunctionCallbackInfo& args) { + env->set_buffer_prototype_object(proto); + } + +-void GetZeroFillToggle(const FunctionCallbackInfo& args) { +- Environment* env = Environment::GetCurrent(args); +- NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator(); +- Local ab; +- // It can be a nullptr when running inside an isolate where we +- // do not own the ArrayBuffer allocator. +- if (allocator == nullptr) { +- // Create a dummy Uint32Array - the JS land can only toggle the C++ land +- // setting when the allocator uses our toggle. With this the toggle in JS +- // land results in no-ops. +- ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t)); +- } else { +- uint32_t* zero_fill_field = allocator->zero_fill_field(); +- std::unique_ptr backing = +- ArrayBuffer::NewBackingStore(zero_fill_field, +- sizeof(*zero_fill_field), +- [](void*, size_t, void*) {}, +- nullptr); +- ab = ArrayBuffer::New(env->isolate(), std::move(backing)); +- } +- +- ab->SetPrivate( +- env->context(), +- env->untransferable_object_private_symbol(), +- True(env->isolate())).Check(); +- +- args.GetReturnValue().Set(Uint32Array::New(ab, 0, 1)); +-} +- + void DetachArrayBuffer(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + if (args[0]->IsArrayBuffer()) { +@@ -1357,6 +1327,54 @@ void CopyArrayBuffer(const FunctionCallbackInfo& args) { + memcpy(dest, src, bytes_to_copy); + } + ++// Converts a number parameter to size_t suitable for ArrayBuffer sizes ++// Could be larger than uint32_t ++// See v8::internal::TryNumberToSize and v8::internal::NumberToSize ++inline size_t CheckNumberToSize(Local number) { ++ CHECK(number->IsNumber()); ++ double value = number.As()->Value(); ++ // See v8::internal::TryNumberToSize on this (and on < comparison) ++ double maxSize = static_cast(std::numeric_limits::max()); ++ CHECK(value >= 0 && value < maxSize); ++ size_t size = static_cast(value); ++#ifdef V8_ENABLE_SANDBOX ++ CHECK_LE(size, kMaxSafeBufferSizeForSandbox); ++#endif ++ return size; ++} ++ ++void CreateUnsafeArrayBuffer(const FunctionCallbackInfo& args) { ++ Environment* env = Environment::GetCurrent(args); ++ if (args.Length() != 1) { ++ env->ThrowRangeError("Invalid array buffer length"); ++ return; ++ } ++ ++ size_t size = CheckNumberToSize(args[0]); ++ ++ Isolate* isolate = env->isolate(); ++ ++ Local buf; ++ ++ NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator(); ++ // 0-length, or zero-fill flag is set, or building snapshot ++ if (size == 0 || per_process::cli_options->zero_fill_all_buffers || ++ allocator == nullptr) { ++ buf = ArrayBuffer::New(isolate, size); ++ } else { ++ std::unique_ptr store = ++ ArrayBuffer::NewBackingStoreForNodeLTS(isolate, size); ++ if (!store) { ++ // This slightly differs from the old behavior, ++ // as in v8 that's a RangeError, and this is an Error with code ++ return env->ThrowRangeError("Array buffer allocation failed"); ++ } ++ buf = ArrayBuffer::New(isolate, std::move(store)); ++ } ++ ++ args.GetReturnValue().Set(buf); ++} ++ + void Initialize(Local target, + Local unused, + Local context, +@@ -1379,6 +1397,8 @@ void Initialize(Local target, + + SetMethod(context, target, "detachArrayBuffer", DetachArrayBuffer); + SetMethod(context, target, "copyArrayBuffer", CopyArrayBuffer); ++ SetMethodNoSideEffect( ++ context, target, "createUnsafeArrayBuffer", CreateUnsafeArrayBuffer); + + SetMethod(context, target, "swap16", Swap16); + SetMethod(context, target, "swap32", Swap32); +@@ -1418,8 +1438,6 @@ void Initialize(Local target, + SetMethod(context, target, "hexWrite", StringWrite); + SetMethod(context, target, "ucs2Write", StringWrite); + SetMethod(context, target, "utf8Write", StringWrite); +- +- SetMethod(context, target, "getZeroFillToggle", GetZeroFillToggle); + } + + } // anonymous namespace +@@ -1463,10 +1481,10 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(StringWrite); + registry->Register(StringWrite); + registry->Register(StringWrite); +- registry->Register(GetZeroFillToggle); + + registry->Register(DetachArrayBuffer); + registry->Register(CopyArrayBuffer); ++ registry->Register(CreateUnsafeArrayBuffer); + } + + } // namespace Buffer +-- +2.45.4 + diff --git a/SPECS/nodejs/nodejs18.spec b/SPECS/nodejs/nodejs18.spec index 720303845a1..f4869fffa5e 100644 --- a/SPECS/nodejs/nodejs18.spec +++ b/SPECS/nodejs/nodejs18.spec @@ -6,7 +6,7 @@ Name: nodejs18 # WARNINGS: MUST check and update the 'npm_version' macro for every version update of this package. # The version of NPM can be found inside the sources under 'deps/npm/package.json'. Version: 18.20.3 -Release: 10%{?dist} +Release: 11%{?dist} License: BSD and MIT and Public Domain and NAIST-2003 and Artistic-2.0 Group: Applications/System Vendor: Microsoft Corporation @@ -29,6 +29,7 @@ Patch9: CVE-2025-23166.patch Patch10: CVE-2025-7656.patch Patch11: CVE-2025-5889.patch Patch12: CVE-2025-5222.patch +Patch13: CVE-2025-55131.patch BuildRequires: brotli-devel BuildRequires: coreutils >= 8.22 BuildRequires: gcc @@ -129,6 +130,9 @@ make cctest %{_datadir}/systemtap/tapset/node.stp %changelog +* Fri Jan 23 2026 Aditya Singh - 18.20.3-11 +- Patch for CVE-2025-55131 + * Fri Nov 07 2025 Azure Linux Security Servicing Account - 18.20.3-10 - Patch for CVE-2025-5222 diff --git a/SPECS/python-urllib3/CVE-2025-50181.patch b/SPECS/python-urllib3/CVE-2025-50181.patch index dd849d02733..b03e8b33287 100644 --- a/SPECS/python-urllib3/CVE-2025-50181.patch +++ b/SPECS/python-urllib3/CVE-2025-50181.patch @@ -74,7 +74,7 @@ index 61715e9..ded7b38 100644 + p = PoolManager(retries=retries) merged = p._merge_pool_kwargs({"new_key": "value"}) - assert {"strict": True, "new_key": "value"} == merged -+ assert {"strict": retries, "new_key": "value"} == merged ++ assert {"retries": retries, "new_key": "value"} == merged def test_merge_pool_kwargs_none(self): """Assert false-y values to _merge_pool_kwargs result in defaults""" diff --git a/SPECS/python-urllib3/CVE-2025-66418.patch b/SPECS/python-urllib3/CVE-2025-66418.patch new file mode 100644 index 00000000000..c3eeaaa5d0f --- /dev/null +++ b/SPECS/python-urllib3/CVE-2025-66418.patch @@ -0,0 +1,80 @@ +From 4b4af90890a415a347e28cb21f20dbe5db243412 Mon Sep 17 00:00:00 2001 +From: Illia Volochii +Date: Fri, 5 Dec 2025 16:41:33 +0200 +Subject: [PATCH] Merge commit from fork + +* Add a hard-coded limit for the decompression chain + +* Reuse new list + +Upstream Patch Reference: https://github.com/urllib3/urllib3/commit/24d7b67eac89f94e11003424bcf0d8f7b72222a8.patch + +Signed-off-by: Azure Linux Security Servicing Account +Origin: https://github.com/urllib3/urllib3/commit/24d7b67eac89f94e11003424bcf0d8f7b72222a8.patch +Upstream-reference: https://raw.githubusercontent.com/azurelinux-security/azurelinux/22b34ffefbca93d9b67a608c9e9ea2c25ca89555/SPECS/python-urllib3/CVE-2025-66418.patch +--- + changelog/GHSA-gm62-xv2j-4w53.security.rst | 4 ++++ + src/urllib3/response.py | 13 ++++++++++++- + test/test_response.py | 10 ++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + create mode 100644 changelog/GHSA-gm62-xv2j-4w53.security.rst + +diff --git a/changelog/GHSA-gm62-xv2j-4w53.security.rst b/changelog/GHSA-gm62-xv2j-4w53.security.rst +new file mode 100644 +index 0000000..6646eaa +--- /dev/null ++++ b/changelog/GHSA-gm62-xv2j-4w53.security.rst +@@ -0,0 +1,4 @@ ++Fixed a security issue where an attacker could compose an HTTP response with ++virtually unlimited links in the ``Content-Encoding`` header, potentially ++leading to a denial of service (DoS) attack by exhausting system resources ++during decoding. The number of allowed chained encodings is now limited to 5. +diff --git a/src/urllib3/response.py b/src/urllib3/response.py +index 0bd13d4..0f8adbd 100644 +--- a/src/urllib3/response.py ++++ b/src/urllib3/response.py +@@ -135,8 +135,19 @@ class MultiDecoder(object): + they were applied. + """ + ++ ++ # Maximum allowed number of chained HTTP encodings in the ++ # Content-Encoding header. ++ max_decode_links = 5 ++ + def __init__(self, modes): +- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] ++ encodings = [m.strip() for m in modes.split(",")] ++ if len(encodings) > self.max_decode_links: ++ raise DecodeError( ++ "Too many content encodings in the chain: " ++ f"{len(encodings)} > {self.max_decode_links}" ++ ) ++ self._decoders = [_get_decoder(e) for e in encodings] + + def flush(self): + return self._decoders[0].flush() +diff --git a/test/test_response.py b/test/test_response.py +index e09e385..4bfa8af 100644 +--- a/test/test_response.py ++++ b/test/test_response.py +@@ -295,6 +295,16 @@ class TestResponse(object): + + assert r.data == b"foo" + ++ def test_read_multi_decoding_too_many_links(self) -> None: ++ fp = BytesIO(b"foo") ++ with pytest.raises( ++ DecodeError, match="Too many content encodings in the chain: 6 > 5" ++ ): ++ HTTPResponse( ++ fp, ++ headers={"content-encoding": "gzip, deflate, br, zstd, gzip, deflate"}, ++ ) ++ + def test_body_blob(self): + resp = HTTPResponse(b"foo") + assert resp.data == b"foo" +-- +2.45.4 + diff --git a/SPECS/python-urllib3/CVE-2026-21441.patch b/SPECS/python-urllib3/CVE-2026-21441.patch new file mode 100644 index 00000000000..78ae7d5390b --- /dev/null +++ b/SPECS/python-urllib3/CVE-2026-21441.patch @@ -0,0 +1,86 @@ +From 8864ac407bba8607950025e0979c4c69bc7abc7b Mon Sep 17 00:00:00 2001 +From: Illia Volochii +Date: Wed, 7 Jan 2026 18:07:30 +0200 +Subject: [PATCH] Merge commit from fork + +* Stop decoding response content during redirects needlessly + +* Rename the new query parameter + +* Add a changelog entry + +Upstream Patch reference: https://github.com/urllib3/urllib3/commit/8864ac407bba8607950025e0979c4c69bc7abc7b.patch +--- + dummyserver/handlers.py | 9 ++++++++- + src/urllib3/response.py | 4 +++- + test/with_dummyserver/test_connectionpool.py | 19 +++++++++++++++++++ + 3 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/dummyserver/handlers.py b/dummyserver/handlers.py +index acd181d..db38a39 100644 +--- a/dummyserver/handlers.py ++++ b/dummyserver/handlers.py +@@ -190,7 +190,14 @@ class TestingApp(RequestHandler): + status = status.decode("latin-1") + + headers = [("Location", target)] +- return Response(status=status, headers=headers) ++ compressed = request.params.get("compressed") == b"true" ++ if compressed: ++ headers.append(("Content-Encoding", "gzip")) ++ data = gzip.compress(b"foo") ++ else: ++ data = b"" ++ ++ return Response(data, status=status, headers=headers) + + def not_found(self, request): + return Response("Not found", status="404 Not Found") +diff --git a/src/urllib3/response.py b/src/urllib3/response.py +index 0f8adbd..428b8ec 100644 +--- a/src/urllib3/response.py ++++ b/src/urllib3/response.py +@@ -303,7 +303,9 @@ class HTTPResponse(io.IOBase): + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: +- self.read() ++ # Do not spend resources decoding the content unless decoding has already been initiated. ++ # In this backport we don't track that state, so we avoid decoding here. ++ self.read(decode_content=False) + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + +diff --git a/test/with_dummyserver/test_connectionpool.py b/test/with_dummyserver/test_connectionpool.py +index cde027b..c80a16d 100644 +--- a/test/with_dummyserver/test_connectionpool.py ++++ b/test/with_dummyserver/test_connectionpool.py +@@ -464,6 +464,25 @@ class TestConnectionPool(HTTPDummyServerTestCase): + assert r.status == 200 + assert r.data == b"Dummy server!" + ++ @mock.patch("urllib3.response.GzipDecoder.decompress") ++ def test_no_decoding_with_redirect_when_preload_disabled( ++ self, gzip_decompress: mock.MagicMock ++ ) -> None: ++ """ ++ Test that urllib3 does not attempt to decode a gzipped redirect ++ response when `preload_content` is set to `False`. ++ """ ++ with HTTPConnectionPool(self.host, self.port) as pool: ++ # Three requests are expected: two redirects and one final / 200 OK. ++ response = pool.request( ++ "GET", ++ "/redirect", ++ fields={"target": "/redirect?compressed=true", "compressed": "true"}, ++ preload_content=False, ++ ) ++ assert response.status == 200 ++ gzip_decompress.assert_not_called() ++ + def test_303_redirect_makes_request_lose_body(self): + with HTTPConnectionPool(self.host, self.port) as pool: + response = pool.request( +-- +2.43.0 + diff --git a/SPECS/python-urllib3/python-urllib3.spec b/SPECS/python-urllib3/python-urllib3.spec index dc9180fc492..e3eabd358a5 100644 --- a/SPECS/python-urllib3/python-urllib3.spec +++ b/SPECS/python-urllib3/python-urllib3.spec @@ -1,7 +1,7 @@ Summary: A powerful, sanity-friendly HTTP client for Python. Name: python-urllib3 Version: 1.26.19 -Release: 2%{?dist} +Release: 3%{?dist} License: MIT Vendor: Microsoft Corporation Distribution: Mariner @@ -22,10 +22,14 @@ BuildRequires: python3-setuptools BuildRequires: python3-xml %if %{with_check} BuildRequires: python3-pip +BuildRequires: python3-pytest +BuildRequires: python3-mock %endif Requires: python3 -Patch0: CVE-2025-50181.patch +Patch0: CVE-2025-50181.patch +Patch1: CVE-2025-66418.patch +Patch2: CVE-2026-21441.patch %description -n python3-urllib3 urllib3 is a powerful, sanity-friendly HTTP client for Python. Much of the Python ecosystem already uses urllib3 and you should too. @@ -43,9 +47,20 @@ rm -rf test/contrib/ %py3_install %check -pip3 install --user --upgrade nox -PATH="$PATH:/root/.local/bin/" -nox --reuse-existing-virtualenvs --sessions test-%{python3_version} +# Install nox to handle test environment setup +pip3 install nox + +# Patch dev-requirements.txt to use compatible versions with setuptools 69.x: +# - pytest 7.x+ is compatible with newer setuptools +# - flaky 3.8.0+ is compatible with pytest 7.x+ +sed -i 's/pytest==4.6.9.*/pytest>=7.0.0/' dev-requirements.txt +sed -i 's/pytest==6.2.4.*/pytest>=7.0.0/' dev-requirements.txt +sed -i 's/flaky==3.7.0/flaky>=3.8.0/' dev-requirements.txt + +# Run the test session for Python 3.9 +# Skip test_recent_date which uses hardcoded date that is now in the past +# Note: test/with_dummyserver and test/contrib are removed in %prep +nox -s test-3.9 -- -k "not test_recent_date" %files -n python3-urllib3 %defattr(-,root,root,-) @@ -53,6 +68,9 @@ nox --reuse-existing-virtualenvs --sessions test-%{python3_version} %{python3_sitelib}/* %changelog +* Fri Jan 09 2026 Azure Linux Security Servicing Account - 1.26.19-3 +- Patch for CVE-2025-66418, CVE-2026-21441 + * Thu Jun 26 2025 Durga Jagadeesh Palli - 1.26.19-2 - Patch CVE-2025-50181 diff --git a/SPECS/strongswan/CVE-2025-62291.patch b/SPECS/strongswan/CVE-2025-62291.patch new file mode 100644 index 00000000000..f5776bdf9a7 --- /dev/null +++ b/SPECS/strongswan/CVE-2025-62291.patch @@ -0,0 +1,46 @@ +From b9cb54351a93eee3a6a69b13580efc416088e9f8 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner +Date: Thu, 9 Oct 2025 11:33:45 +0200 +Subject: [PATCH] eap-mschapv2: Fix length check for Failure Request packets on + the client + +For message lengths between 6 and 8, subtracting HEADER_LEN (9) causes +`message_len` to become negative, which is then used in calls to malloc() +and memcpy() that both take size_t arguments, causing an integer +underflow. + +For 6 and 7, the huge size requested from malloc() will fail (it exceeds +PTRDIFF_MAX) and the returned NULL pointer will cause a segmentation +fault in memcpy(). + +However, for 8, the allocation is 0, which succeeds. But then the -1 +passed to memcpy() causes a heap-based buffer overflow (and possibly a +segmentation fault when attempting to read/write that much data). +Fortunately, if compiled with -D_FORTIFY_SOURCE=3 (the default on e.g. +Ubuntu), the compiler will use __memcpy_chk(), which prevents that buffer +overflow and causes the daemon to get aborted immediately instead. + +Fixes: f98cdf7a4765 ("adding plugin for EAP-MS-CHAPv2") +Fixes: CVE-2025-62291 +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://download.strongswan.org/security/CVE-2025-62291/strongswan-4.4.0-6.0.2_eap_mschapv2_failure_request_len.patch +--- + src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c +index 2e14bd9..1eedfeb 100644 +--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c ++++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c +@@ -972,7 +972,7 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this, + data = in->get_data(in); + eap = (eap_mschapv2_header_t*)data.ptr; + +- if (data.len < 3) /* we want at least an error code: E=e */ ++ if (data.len < HEADER_LEN + 3) /* we want at least an error code: E=e */ + { + DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short"); + return FAILED; +-- +2.45.4 + diff --git a/SPECS/strongswan/strongswan.spec b/SPECS/strongswan/strongswan.spec index f20bf875300..1de12c1664d 100644 --- a/SPECS/strongswan/strongswan.spec +++ b/SPECS/strongswan/strongswan.spec @@ -1,7 +1,7 @@ Summary: The OpenSource IPsec-based VPN Solution Name: strongswan Version: 5.9.10 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ Vendor: Microsoft Corporation Distribution: Mariner @@ -11,6 +11,7 @@ Source0: https://download.strongswan.org/%{name}-%{version}.tar.bz2 Patch0: strongswan-fix-make-check.patch Patch1: 0001-Extending-timeout-for-test-cases-with-multiple-read-.patch Patch2: strongswan-5.9.7-5.9.11_charon_tkm_dh_len.patch +Patch3: CVE-2025-62291.patch BuildRequires: autoconf BuildRequires: gmp-devel @@ -52,6 +53,9 @@ make check %{_datadir}/strongswan/* %changelog +* Mon Jan 19 2026 Azure Linux Security Servicing Account - 5.9.10-4 +- Patch for CVE-2025-62291 + * Wed Dec 13 2023 Elaine Zhao <@microsoft.com> - 5.9.10-3 - Fix for CVE-2023-41913 diff --git a/cgmanifest.json b/cgmanifest.json index 522fd7cbde8..ee2dadde0d7 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -13653,8 +13653,8 @@ "type": "other", "other": { "name": "msft-golang", - "version": "1.24.11", - "downloadUrl": "https://github.com/microsoft/go/releases/download/v1.24.11-1/go1.24.11-20251202.3.src.tar.gz" + "version": "1.24.12", + "downloadUrl": "https://github.com/microsoft/go/releases/download/v1.24.12-1/go1.24.12-20260116.10.src.tar.gz" } } }, diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index 61b0a0b58e3..ce5e23dbc23 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -194,8 +194,8 @@ curl-8.8.0-7.cm2.aarch64.rpm curl-devel-8.8.0-7.cm2.aarch64.rpm curl-libs-8.8.0-7.cm2.aarch64.rpm createrepo_c-0.17.5-1.cm2.aarch64.rpm -libxml2-2.10.4-9.cm2.aarch64.rpm -libxml2-devel-2.10.4-9.cm2.aarch64.rpm +libxml2-2.10.4-10.cm2.aarch64.rpm +libxml2-devel-2.10.4-10.cm2.aarch64.rpm docbook-dtd-xml-4.5-11.cm2.noarch.rpm docbook-style-xsl-1.79.1-14.cm2.noarch.rpm libsepol-3.2-2.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index 8e1b2cacdd8..a13e15a8c5a 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -194,8 +194,8 @@ curl-8.8.0-7.cm2.x86_64.rpm curl-devel-8.8.0-7.cm2.x86_64.rpm curl-libs-8.8.0-7.cm2.x86_64.rpm createrepo_c-0.17.5-1.cm2.x86_64.rpm -libxml2-2.10.4-9.cm2.x86_64.rpm -libxml2-devel-2.10.4-9.cm2.x86_64.rpm +libxml2-2.10.4-10.cm2.x86_64.rpm +libxml2-devel-2.10.4-10.cm2.x86_64.rpm docbook-dtd-xml-4.5-11.cm2.noarch.rpm docbook-style-xsl-1.79.1-14.cm2.noarch.rpm libsepol-3.2-2.cm2.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index c90a4b59b01..352f35adab2 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -209,9 +209,9 @@ libtasn1-debuginfo-4.19.0-2.cm2.aarch64.rpm libtasn1-devel-4.19.0-2.cm2.aarch64.rpm libtool-2.4.6-8.cm2.aarch64.rpm libtool-debuginfo-2.4.6-8.cm2.aarch64.rpm -libxml2-2.10.4-9.cm2.aarch64.rpm -libxml2-debuginfo-2.10.4-9.cm2.aarch64.rpm -libxml2-devel-2.10.4-9.cm2.aarch64.rpm +libxml2-2.10.4-10.cm2.aarch64.rpm +libxml2-debuginfo-2.10.4-10.cm2.aarch64.rpm +libxml2-devel-2.10.4-10.cm2.aarch64.rpm libxslt-1.1.34-10.cm2.aarch64.rpm libxslt-debuginfo-1.1.34-10.cm2.aarch64.rpm libxslt-devel-1.1.34-10.cm2.aarch64.rpm @@ -521,7 +521,7 @@ python3-gpg-1.16.0-2.cm2.aarch64.rpm python3-jinja2-3.0.3-7.cm2.noarch.rpm python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm python3-libs-3.9.19-17.cm2.aarch64.rpm -python3-libxml2-2.10.4-9.cm2.aarch64.rpm +python3-libxml2-2.10.4-10.cm2.aarch64.rpm python3-lxml-4.9.1-1.cm2.aarch64.rpm python3-magic-5.40-3.cm2.noarch.rpm python3-markupsafe-2.1.0-1.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index 55c5217a403..b434ffe6641 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -215,9 +215,9 @@ libtasn1-debuginfo-4.19.0-2.cm2.x86_64.rpm libtasn1-devel-4.19.0-2.cm2.x86_64.rpm libtool-2.4.6-8.cm2.x86_64.rpm libtool-debuginfo-2.4.6-8.cm2.x86_64.rpm -libxml2-2.10.4-9.cm2.x86_64.rpm -libxml2-debuginfo-2.10.4-9.cm2.x86_64.rpm -libxml2-devel-2.10.4-9.cm2.x86_64.rpm +libxml2-2.10.4-10.cm2.x86_64.rpm +libxml2-debuginfo-2.10.4-10.cm2.x86_64.rpm +libxml2-devel-2.10.4-10.cm2.x86_64.rpm libxslt-1.1.34-10.cm2.x86_64.rpm libxslt-debuginfo-1.1.34-10.cm2.x86_64.rpm libxslt-devel-1.1.34-10.cm2.x86_64.rpm @@ -527,7 +527,7 @@ python3-gpg-1.16.0-2.cm2.x86_64.rpm python3-jinja2-3.0.3-7.cm2.noarch.rpm python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm python3-libs-3.9.19-17.cm2.x86_64.rpm -python3-libxml2-2.10.4-9.cm2.x86_64.rpm +python3-libxml2-2.10.4-10.cm2.x86_64.rpm python3-lxml-4.9.1-1.cm2.x86_64.rpm python3-magic-5.40-3.cm2.noarch.rpm python3-markupsafe-2.1.0-1.cm2.x86_64.rpm