diff --git a/SPECS/python-lxml/CVE-2026-41066.patch b/SPECS/python-lxml/CVE-2026-41066.patch new file mode 100644 index 00000000000..e49d3d07fde --- /dev/null +++ b/SPECS/python-lxml/CVE-2026-41066.patch @@ -0,0 +1,102 @@ +From 034dfbac902baa560423f1268dedf74e6730573a Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Wed, 29 Apr 2026 09:37:00 +0000 +Subject: [PATCH] LP#2146291: Set resolve_entities='internal' as default for + parser subclasses; update iterparse signature and docs accordingly. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/lxml/lxml/commit/ab431ea0b9a7357d968f1d1c5c614649e9aaf358.patch +--- + src/lxml/iterparse.pxi | 11 +++++++---- + src/lxml/parser.pxi | 10 +++++----- + 2 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/src/lxml/iterparse.pxi b/src/lxml/iterparse.pxi +index a7299da..52d0ea7 100644 +--- a/src/lxml/iterparse.pxi ++++ b/src/lxml/iterparse.pxi +@@ -6,7 +6,8 @@ cdef class iterparse: + u"""iterparse(self, source, events=("end",), tag=None, \ + attribute_defaults=False, dtd_validation=False, \ + load_dtd=False, no_network=True, remove_blank_text=False, \ +- remove_comments=False, remove_pis=False, encoding=None, \ ++ compact=True, resolve_entities='internal', remove_comments=False, \ ++ remove_pis=False, strip_cdata=True, encoding=None, \ + html=False, recover=None, huge_tree=False, schema=None) + + Incremental parser. +@@ -42,9 +43,11 @@ cdef class iterparse: + - remove_blank_text: discard blank text nodes + - remove_comments: discard comments + - remove_pis: discard processing instructions +- - strip_cdata: replace CDATA sections by normal text content (default: True) ++ - strip_cdata: replace CDATA sections by normal text content (default: ++ True for XML, ignored otherwise) + - compact: safe memory for short text content (default: True) +- - resolve_entities: replace entities by their text value (default: True) ++ - resolve_entities: replace entities by their text value ++ (default: 'internal' only) + - huge_tree: disable security restrictions and support very deep trees + and very long text content (only affects libxml2 2.7+) + - html: parse input as HTML (default: XML) +@@ -67,7 +70,7 @@ cdef class iterparse: + def __init__(self, source, events=(u"end",), *, tag=None, + attribute_defaults=False, dtd_validation=False, + load_dtd=False, no_network=True, remove_blank_text=False, +- compact=True, resolve_entities=True, remove_comments=False, ++ compact=True, resolve_entities='internal', remove_comments=False, + remove_pis=False, strip_cdata=True, encoding=None, + html=False, recover=None, huge_tree=False, collect_ids=True, + XMLSchema schema=None): +diff --git a/src/lxml/parser.pxi b/src/lxml/parser.pxi +index 068cdd3..c00c524 100644 +--- a/src/lxml/parser.pxi ++++ b/src/lxml/parser.pxi +@@ -1478,7 +1478,7 @@ _XML_DEFAULT_PARSE_OPTIONS = ( + ) + + cdef class XMLParser(_FeedParser): +- u"""XMLParser(self, encoding=None, attribute_defaults=False, dtd_validation=False, load_dtd=False, no_network=True, ns_clean=False, recover=False, schema: XMLSchema =None, huge_tree=False, remove_blank_text=False, resolve_entities=True, remove_comments=False, remove_pis=False, strip_cdata=True, collect_ids=True, target=None, compact=True) ++ u"""XMLParser(self, encoding=None, attribute_defaults=False, dtd_validation=False, load_dtd=False, no_network=True, ns_clean=False, recover=False, schema: XMLSchema =None, huge_tree=False, remove_blank_text=False, resolve_entities='internal', remove_comments=False, remove_pis=False, strip_cdata=True, collect_ids=True, target=None, compact=True) + + The XML parser. + +@@ -1508,7 +1508,7 @@ cdef class XMLParser(_FeedParser): + - strip_cdata - replace CDATA sections by normal text content (default: True) + - compact - save memory for short text content (default: True) + - collect_ids - use a hash table of XML IDs for fast access (default: True, always True with DTD validation) +- - resolve_entities - replace entities by their text value (default: True) ++ - resolve_entities - replace entities by their text value (default: 'internal') + - huge_tree - disable security restrictions and support very deep trees + and very long text content (only affects libxml2 2.7+) + +@@ -1525,7 +1525,7 @@ cdef class XMLParser(_FeedParser): + def __init__(self, *, encoding=None, attribute_defaults=False, + dtd_validation=False, load_dtd=False, no_network=True, + ns_clean=False, recover=False, XMLSchema schema=None, +- huge_tree=False, remove_blank_text=False, resolve_entities=True, ++ huge_tree=False, remove_blank_text=False, resolve_entities='internal', + remove_comments=False, remove_pis=False, strip_cdata=True, + collect_ids=True, target=None, compact=True): + cdef int parse_options +@@ -1594,7 +1594,7 @@ cdef class ETCompatXMLParser(XMLParser): + u"""ETCompatXMLParser(self, encoding=None, attribute_defaults=False, \ + dtd_validation=False, load_dtd=False, no_network=True, \ + ns_clean=False, recover=False, schema=None, \ +- huge_tree=False, remove_blank_text=False, resolve_entities=True, \ ++ huge_tree=False, remove_blank_text=False, resolve_entities='internal', \ + remove_comments=True, remove_pis=True, strip_cdata=True, \ + target=None, compact=True) + +@@ -1608,7 +1608,7 @@ cdef class ETCompatXMLParser(XMLParser): + def __init__(self, *, encoding=None, attribute_defaults=False, + dtd_validation=False, load_dtd=False, no_network=True, + ns_clean=False, recover=False, schema=None, +- huge_tree=False, remove_blank_text=False, resolve_entities=True, ++ huge_tree=False, remove_blank_text=False, resolve_entities='internal', + remove_comments=True, remove_pis=True, strip_cdata=True, + target=None, compact=True): + XMLParser.__init__(self, +-- +2.45.4 + diff --git a/SPECS/python-lxml/noexcept.patch b/SPECS/python-lxml/noexcept.patch index dd08f269d8d..fbedd341f07 100644 --- a/SPECS/python-lxml/noexcept.patch +++ b/SPECS/python-lxml/noexcept.patch @@ -1,5 +1,54 @@ +diff --git a/src/lxml/extensions.pxi b/src/lxml/extensions.pxi +index 35a321b..6282f0a 100644 +--- a/src/lxml/extensions.pxi ++++ b/src/lxml/extensions.pxi +@@ -129,7 +129,7 @@ cdef class _BaseContext: + python.Py_INCREF(utf) + return utf + +- cdef void _set_xpath_context(self, xpath.xmlXPathContext* xpathCtxt): ++ cdef void _set_xpath_context(self, xpath.xmlXPathContext* xpathCtxt) noexcept: + self._xpathCtxt = xpathCtxt + xpathCtxt.userData = self + xpathCtxt.error = _receiveXPathError +@@ -213,7 +213,7 @@ cdef class _BaseContext: + _xcstr(prefix_utf), NULL) + del self._global_namespaces[:] + +- cdef void _unregisterNamespace(self, prefix_utf): ++ cdef void _unregisterNamespace(self, prefix_utf) noexcept: + xpath.xmlXPathRegisterNs(self._xpathCtxt, + _xcstr(prefix_utf), NULL) + +@@ -393,7 +393,7 @@ cdef tuple LIBXML2_XPATH_ERROR_MESSAGES = ( + b"?? Unknown error ??\n", + ) + +-cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) with gil: ++cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) noexcept with gil: + cdef xmlerror.xmlError error + cdef int xpath_code + if c_error.message is not NULL: +@@ -414,7 +414,7 @@ cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) with gil: + + (<_BaseContext>c_ctxt)._error_log._receive(&error) + +-cdef void _receiveXPathError(void* c_context, xmlerror.xmlError* error) nogil: ++cdef void _receiveXPathError(void* c_context, xmlerror.xmlError* error) noexcept nogil: + if not __DEBUG: + return + if c_context is NULL: +@@ -851,7 +851,7 @@ cdef void _extension_function_call(_BaseContext context, function, + # lookup the function by name and call it + + cdef void _xpath_function_call(xpath.xmlXPathParserContext* ctxt, +- int nargs) with gil: ++ int nargs) noexcept with gil: + cdef _BaseContext context + cdef xpath.xmlXPathContext* rctxt = ctxt.context + context = <_BaseContext> rctxt.userData diff --git a/src/lxml/includes/xmlparser.pxd b/src/lxml/includes/xmlparser.pxd -index 45acfc84..a73713cd 100644 +index 45acfc8..a73713c 100644 --- a/src/lxml/includes/xmlparser.pxd +++ b/src/lxml/includes/xmlparser.pxd @@ -229,7 +229,7 @@ cdef extern from "libxml/parser.h": @@ -12,7 +61,7 @@ index 45acfc84..a73713cd 100644 cdef void xmlSetExternalEntityLoader(xmlExternalEntityLoader f) nogil diff --git a/src/lxml/includes/xslt.pxd b/src/lxml/includes/xslt.pxd -index 101fb7e7..05e02199 100644 +index 101fb7e..05e0219 100644 --- a/src/lxml/includes/xslt.pxd +++ b/src/lxml/includes/xslt.pxd @@ -53,7 +53,7 @@ cdef extern from "libxslt/extensions.h": @@ -42,15 +91,14 @@ index 101fb7e7..05e02199 100644 cdef xsltSecurityPrefs* xsltNewSecurityPrefs() nogil cdef void xsltFreeSecurityPrefs(xsltSecurityPrefs* sec) nogil - diff --git a/src/lxml/parser.pxi b/src/lxml/parser.pxi -index f0c8c6b6..1b748787 100644 +index f0c8c6b..068cdd3 100644 --- a/src/lxml/parser.pxi +++ b/src/lxml/parser.pxi @@ -283,7 +283,7 @@ cdef class _FileReaderContext: if close is not None: close() - + - cdef xmlparser.xmlParserInputBuffer* _createParserInputBuffer(self): + cdef xmlparser.xmlParserInputBuffer* _createParserInputBuffer(self) noexcept: cdef stdio.FILE* c_stream @@ -186,10 +234,121 @@ index f0c8c6b6..1b748787 100644 +cdef void _initSaxDocument(void* ctxt) noexcept with gil: xmlparser.xmlSAX2StartDocument(ctxt) c_ctxt = ctxt - c_doc = c_ctxt.myDoc - + c_doc = c_ctxt.myDoc +diff --git a/src/lxml/proxy.pxi b/src/lxml/proxy.pxi +index 3c6e306..849a36b 100644 +--- a/src/lxml/proxy.pxi ++++ b/src/lxml/proxy.pxi +@@ -146,7 +146,7 @@ cdef int attemptDeallocation(xmlNode* c_node): + return 1 + return 0 + +-cdef xmlNode* getDeallocationTop(xmlNode* c_node): ++cdef xmlNode* getDeallocationTop(xmlNode* c_node) noexcept: + u"""Return the top of the tree that can be deallocated, or NULL. + """ + cdef xmlNode* c_next +@@ -183,7 +183,7 @@ cdef xmlNode* getDeallocationTop(xmlNode* c_node): + c_next = c_next.next + return c_node + +-cdef int canDeallocateChildNodes(xmlNode* c_parent): ++cdef int canDeallocateChildNodes(xmlNode* c_parent) noexcept: + cdef xmlNode* c_node + c_node = c_parent.children + tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_parent, c_node, 1) +@@ -195,7 +195,7 @@ cdef int canDeallocateChildNodes(xmlNode* c_parent): + ################################################################################ + # fix _Document references and namespaces when a node changes documents + +-cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node) nogil: ++cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node) noexcept nogil: + u"""Copy the namespaces of all ancestors of c_from_node to c_to_node. + """ + cdef xmlNode* c_parent +@@ -395,7 +395,7 @@ cdef int moveNodeToDocument(_Document doc, xmlDoc* c_source_doc, + return 0 + + +-cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc): ++cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc) noexcept: + """Adaptation of 'xmlSetTreeDoc()' that deep-fixes the document links iteratively. + It avoids https://gitlab.gnome.org/GNOME/libxml2/issues/42 + """ +@@ -413,7 +413,7 @@ cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc): + tree.END_FOR_EACH_FROM(c_node) + + +-cdef inline void _fixDocChildren(xmlNode* c_child, xmlDoc* c_doc): ++cdef inline void _fixDocChildren(xmlNode* c_child, xmlDoc* c_doc) noexcept: + while c_child: + c_child.doc = c_doc + if c_child.children: +@@ -469,7 +469,7 @@ cdef void fixElementDocument(xmlNode* c_element, _Document doc, + + cdef void fixThreadDictNames(xmlNode* c_element, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + # re-assign the names of tags and attributes + # + # this should only be called when the element is based on a +@@ -492,7 +492,7 @@ cdef void fixThreadDictNames(xmlNode* c_element, + + cdef inline void _fixThreadDictPtr(const_xmlChar** c_ptr, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + c_str = c_ptr[0] + if c_str and c_src_dict and tree.xmlDictOwns(c_src_dict, c_str): + # return value can be NULL on memory error, but we don't handle that here +@@ -503,7 +503,7 @@ cdef inline void _fixThreadDictPtr(const_xmlChar** c_ptr, + + cdef void fixThreadDictNamesForNode(xmlNode* c_element, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + cdef xmlNode* c_node = c_element + tree.BEGIN_FOR_EACH_FROM(c_element, c_node, 1) + if c_node.type in (tree.XML_ELEMENT_NODE, tree.XML_XINCLUDE_START): +@@ -523,7 +523,7 @@ cdef void fixThreadDictNamesForNode(xmlNode* c_element, + + cdef inline void fixThreadDictNamesForAttributes(tree.xmlAttr* c_attr, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + cdef xmlNode* c_child + cdef xmlNode* c_node = c_attr + while c_node is not NULL: +@@ -539,7 +539,7 @@ cdef inline void fixThreadDictNamesForAttributes(tree.xmlAttr* c_attr, + + cdef inline void fixThreadDictContentForNode(xmlNode* c_node, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + if c_node.content is not NULL and \ + c_node.content is not &c_node.properties: + if tree.xmlDictOwns(c_src_dict, c_node.content): +@@ -549,7 +549,7 @@ cdef inline void fixThreadDictContentForNode(xmlNode* c_node, + + cdef inline void fixThreadDictNsForNode(xmlNode* c_node, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + cdef xmlNs* c_ns = c_node.nsDef + while c_ns is not NULL: + _fixThreadDictPtr(&c_ns.href, c_src_dict, c_dict) +@@ -559,7 +559,7 @@ cdef inline void fixThreadDictNsForNode(xmlNode* c_node, + + cdef void fixThreadDictNamesForDtd(tree.xmlDtd* c_dtd, + tree.xmlDict* c_src_dict, +- tree.xmlDict* c_dict) nogil: ++ tree.xmlDict* c_dict) noexcept nogil: + cdef xmlNode* c_node + cdef tree.xmlElement* c_element + cdef tree.xmlAttribute* c_attribute diff --git a/src/lxml/saxparser.pxi b/src/lxml/saxparser.pxi -index 49e72bea..85117f15 100644 +index 49e72be..85117f1 100644 --- a/src/lxml/saxparser.pxi +++ b/src/lxml/saxparser.pxi @@ -107,17 +107,17 @@ cdef class _SaxParserContext(_ParserContext): @@ -348,122 +507,8 @@ index 49e72bea..85117f15 100644 # can only be called when collecting comment events c_ctxt = ctxt if c_ctxt._private is NULL or c_ctxt.disableSAX: - -diff --git a/src/lxml/proxy.pxi b/src/lxml/proxy.pxi -index 3c6e3068..849a36bf 100644 ---- a/src/lxml/proxy.pxi -+++ b/src/lxml/proxy.pxi -@@ -146,7 +146,7 @@ cdef int attemptDeallocation(xmlNode* c_node): - return 1 - return 0 - --cdef xmlNode* getDeallocationTop(xmlNode* c_node): -+cdef xmlNode* getDeallocationTop(xmlNode* c_node) noexcept: - u"""Return the top of the tree that can be deallocated, or NULL. - """ - cdef xmlNode* c_next -@@ -183,7 +183,7 @@ cdef xmlNode* getDeallocationTop(xmlNode* c_node): - c_next = c_next.next - return c_node - --cdef int canDeallocateChildNodes(xmlNode* c_parent): -+cdef int canDeallocateChildNodes(xmlNode* c_parent) noexcept: - cdef xmlNode* c_node - c_node = c_parent.children - tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_parent, c_node, 1) -@@ -195,7 +195,7 @@ cdef int canDeallocateChildNodes(xmlNode* c_parent): - ################################################################################ - # fix _Document references and namespaces when a node changes documents - --cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node) nogil: -+cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node) noexcept nogil: - u"""Copy the namespaces of all ancestors of c_from_node to c_to_node. - """ - cdef xmlNode* c_parent -@@ -395,7 +395,7 @@ cdef int moveNodeToDocument(_Document doc, xmlDoc* c_source_doc, - return 0 - - --cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc): -+cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc) noexcept: - """Adaptation of 'xmlSetTreeDoc()' that deep-fixes the document links iteratively. - It avoids https://gitlab.gnome.org/GNOME/libxml2/issues/42 - """ -@@ -413,7 +413,7 @@ cdef void _setTreeDoc(xmlNode* c_node, xmlDoc* c_doc): - tree.END_FOR_EACH_FROM(c_node) - - --cdef inline void _fixDocChildren(xmlNode* c_child, xmlDoc* c_doc): -+cdef inline void _fixDocChildren(xmlNode* c_child, xmlDoc* c_doc) noexcept: - while c_child: - c_child.doc = c_doc - if c_child.children: -@@ -469,7 +469,7 @@ cdef void fixElementDocument(xmlNode* c_element, _Document doc, - - cdef void fixThreadDictNames(xmlNode* c_element, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - # re-assign the names of tags and attributes - # - # this should only be called when the element is based on a -@@ -492,7 +492,7 @@ cdef void fixThreadDictNames(xmlNode* c_element, - - cdef inline void _fixThreadDictPtr(const_xmlChar** c_ptr, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - c_str = c_ptr[0] - if c_str and c_src_dict and tree.xmlDictOwns(c_src_dict, c_str): - # return value can be NULL on memory error, but we don't handle that here -@@ -503,7 +503,7 @@ cdef inline void _fixThreadDictPtr(const_xmlChar** c_ptr, - - cdef void fixThreadDictNamesForNode(xmlNode* c_element, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - cdef xmlNode* c_node = c_element - tree.BEGIN_FOR_EACH_FROM(c_element, c_node, 1) - if c_node.type in (tree.XML_ELEMENT_NODE, tree.XML_XINCLUDE_START): -@@ -523,7 +523,7 @@ cdef void fixThreadDictNamesForNode(xmlNode* c_element, - - cdef inline void fixThreadDictNamesForAttributes(tree.xmlAttr* c_attr, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - cdef xmlNode* c_child - cdef xmlNode* c_node = c_attr - while c_node is not NULL: -@@ -539,7 +539,7 @@ cdef inline void fixThreadDictNamesForAttributes(tree.xmlAttr* c_attr, - - cdef inline void fixThreadDictContentForNode(xmlNode* c_node, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - if c_node.content is not NULL and \ - c_node.content is not &c_node.properties: - if tree.xmlDictOwns(c_src_dict, c_node.content): -@@ -549,7 +549,7 @@ cdef inline void fixThreadDictContentForNode(xmlNode* c_node, - - cdef inline void fixThreadDictNsForNode(xmlNode* c_node, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - cdef xmlNs* c_ns = c_node.nsDef - while c_ns is not NULL: - _fixThreadDictPtr(&c_ns.href, c_src_dict, c_dict) -@@ -559,7 +559,7 @@ cdef inline void fixThreadDictNsForNode(xmlNode* c_node, - - cdef void fixThreadDictNamesForDtd(tree.xmlDtd* c_dtd, - tree.xmlDict* c_src_dict, -- tree.xmlDict* c_dict) nogil: -+ tree.xmlDict* c_dict) noexcept nogil: - cdef xmlNode* c_node - cdef tree.xmlElement* c_element - cdef tree.xmlAttribute* c_attribute - diff --git a/src/lxml/serializer.pxi b/src/lxml/serializer.pxi -index 79a02829..d1b74a00 100644 +index 79a0282..d1b74a0 100644 --- a/src/lxml/serializer.pxi +++ b/src/lxml/serializer.pxi @@ -201,7 +201,7 @@ cdef _raiseSerialisationError(int error_result): @@ -569,95 +614,39 @@ index 79a02829..d1b74a00 100644 _writeNodeToBuffer( c_buffer, c_node, c_enc, c_doctype, c_method, write_xml_declaration, write_doctype, pretty_print, with_tail, standalone) - -diff --git a/src/lxml/xslt.pxi b/src/lxml/xslt.pxi -index 78b20ce6..5307b6e5 100644 ---- a/src/lxml/xslt.pxi -+++ b/src/lxml/xslt.pxi -@@ -112,7 +112,7 @@ cdef xmlDoc* _xslt_resolve_from_python(const_xmlChar* c_uri, void* c_context, - - - cdef void _xslt_store_resolver_exception(const_xmlChar* c_uri, void* context, -- xslt.xsltLoadType c_type) with gil: -+ xslt.xsltLoadType c_type) noexcept with gil: - try: - message = f"Cannot resolve URI {_decodeFilename(c_uri)}" - if c_type == xslt.XSLT_LOAD_DOCUMENT: -@@ -128,7 +128,7 @@ cdef void _xslt_store_resolver_exception(const_xmlChar* c_uri, void* context, - - cdef xmlDoc* _xslt_doc_loader(const_xmlChar* c_uri, tree.xmlDict* c_dict, - int parse_options, void* c_ctxt, -- xslt.xsltLoadType c_type) nogil: -+ xslt.xsltLoadType c_type) noexcept nogil: - # nogil => no Python objects here, may be called without thread context ! - cdef xmlDoc* c_doc - cdef xmlDoc* result - -diff --git a/src/lxml/xsltext.pxi b/src/lxml/xsltext.pxi -index c98ae1ff..cfa89f69 100644 ---- a/src/lxml/xsltext.pxi -+++ b/src/lxml/xsltext.pxi -@@ -162,7 +162,7 @@ cdef _registerXSLTExtensions(xslt.xsltTransformContext* c_ctxt, - cdef void _callExtensionElement(xslt.xsltTransformContext* c_ctxt, - xmlNode* c_context_node, - xmlNode* c_inst_node, -- void* dummy) with gil: -+ void* dummy) noexcept with gil: - cdef _XSLTContext context - cdef XSLTExtension extension - cdef python.PyObject* dict_result - -diff --git a/src/lxml/extensions.pxi b/src/lxml/extensions.pxi -index 35a321b7..6282f0a3 100644 ---- a/src/lxml/extensions.pxi -+++ b/src/lxml/extensions.pxi -@@ -129,7 +129,7 @@ cdef class _BaseContext: - python.Py_INCREF(utf) - return utf - -- cdef void _set_xpath_context(self, xpath.xmlXPathContext* xpathCtxt): -+ cdef void _set_xpath_context(self, xpath.xmlXPathContext* xpathCtxt) noexcept: - self._xpathCtxt = xpathCtxt - xpathCtxt.userData = self - xpathCtxt.error = _receiveXPathError -@@ -213,7 +213,7 @@ cdef class _BaseContext: - _xcstr(prefix_utf), NULL) - del self._global_namespaces[:] - -- cdef void _unregisterNamespace(self, prefix_utf): -+ cdef void _unregisterNamespace(self, prefix_utf) noexcept: - xpath.xmlXPathRegisterNs(self._xpathCtxt, - _xcstr(prefix_utf), NULL) - -@@ -393,7 +393,7 @@ cdef tuple LIBXML2_XPATH_ERROR_MESSAGES = ( - b"?? Unknown error ??\n", - ) - --cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) with gil: -+cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) noexcept with gil: - cdef xmlerror.xmlError error - cdef int xpath_code - if c_error.message is not NULL: -@@ -414,7 +414,7 @@ cdef void _forwardXPathError(void* c_ctxt, xmlerror.xmlError* c_error) with gil: +diff --git a/src/lxml/xmlschema.pxi b/src/lxml/xmlschema.pxi +index fe7a2ba..0f7dbb5 100644 +--- a/src/lxml/xmlschema.pxi ++++ b/src/lxml/xmlschema.pxi +@@ -175,7 +175,7 @@ cdef class _ParserSchemaValidationContext: + return self._schema._newSaxValidator( + self._add_default_attributes) - (<_BaseContext>c_ctxt)._error_log._receive(&error) +- cdef void inject_default_attributes(self, xmlDoc* c_doc): ++ cdef void inject_default_attributes(self, xmlDoc* c_doc) noexcept: + # we currently need to insert default attributes manually + # after parsing, as libxml2 does not support this at parse + # time +@@ -198,7 +198,7 @@ cdef class _ParserSchemaValidationContext: + self._sax_plug = xmlschema.xmlSchemaSAXPlug( + self._valid_ctxt, &c_ctxt.sax, &c_ctxt.userData) --cdef void _receiveXPathError(void* c_context, xmlerror.xmlError* error) nogil: -+cdef void _receiveXPathError(void* c_context, xmlerror.xmlError* error) noexcept nogil: - if not __DEBUG: - return - if c_context is NULL: -@@ -851,7 +851,7 @@ cdef void _extension_function_call(_BaseContext context, function, - # lookup the function by name and call it +- cdef void disconnect(self): ++ cdef void disconnect(self) noexcept: + if self._sax_plug is not NULL: + xmlschema.xmlSchemaSAXUnplug(self._sax_plug) + self._sax_plug = NULL +@@ -206,7 +206,7 @@ cdef class _ParserSchemaValidationContext: + xmlschema.xmlSchemaSetValidStructuredErrors( + self._valid_ctxt, NULL, NULL) - cdef void _xpath_function_call(xpath.xmlXPathParserContext* ctxt, -- int nargs) with gil: -+ int nargs) noexcept with gil: - cdef _BaseContext context - cdef xpath.xmlXPathContext* rctxt = ctxt.context - context = <_BaseContext> rctxt.userData +- cdef bint isvalid(self): ++ cdef bint isvalid(self) noexcept: + if self._valid_ctxt is NULL: + return 1 # valid + return xmlschema.xmlSchemaIsValid(self._valid_ctxt) diff --git a/src/lxml/xpath.pxi b/src/lxml/xpath.pxi -index a7cae4bf..ac7177fd 100644 +index a7cae4b..ac7177f 100644 --- a/src/lxml/xpath.pxi +++ b/src/lxml/xpath.pxi @@ -26,7 +26,7 @@ cdef object _XPATH_EVAL_ERRORS = ( @@ -714,35 +703,38 @@ index a7cae4bf..ac7177fd 100644 if config.ENABLE_THREADING and self._eval_lock != NULL: python.PyThread_release_lock(self._eval_lock) - -diff --git a/src/lxml/xmlschema.pxi b/src/lxml/xmlschema.pxi -index fe7a2bac..0f7dbb5c 100644 ---- a/src/lxml/xmlschema.pxi -+++ b/src/lxml/xmlschema.pxi -@@ -175,7 +175,7 @@ cdef class _ParserSchemaValidationContext: - return self._schema._newSaxValidator( - self._add_default_attributes) +diff --git a/src/lxml/xslt.pxi b/src/lxml/xslt.pxi +index 559b277..9f55574 100644 +--- a/src/lxml/xslt.pxi ++++ b/src/lxml/xslt.pxi +@@ -112,7 +112,7 @@ cdef xmlDoc* _xslt_resolve_from_python(const_xmlChar* c_uri, void* c_context, -- cdef void inject_default_attributes(self, xmlDoc* c_doc): -+ cdef void inject_default_attributes(self, xmlDoc* c_doc) noexcept: - # we currently need to insert default attributes manually - # after parsing, as libxml2 does not support this at parse - # time -@@ -198,7 +198,7 @@ cdef class _ParserSchemaValidationContext: - self._sax_plug = xmlschema.xmlSchemaSAXPlug( - self._valid_ctxt, &c_ctxt.sax, &c_ctxt.userData) -- cdef void disconnect(self): -+ cdef void disconnect(self) noexcept: - if self._sax_plug is not NULL: - xmlschema.xmlSchemaSAXUnplug(self._sax_plug) - self._sax_plug = NULL -@@ -206,7 +206,7 @@ cdef class _ParserSchemaValidationContext: - xmlschema.xmlSchemaSetValidStructuredErrors( - self._valid_ctxt, NULL, NULL) + cdef void _xslt_store_resolver_exception(const_xmlChar* c_uri, void* context, +- xslt.xsltLoadType c_type) with gil: ++ xslt.xsltLoadType c_type) noexcept with gil: + try: + message = f"Cannot resolve URI {_decodeFilename(c_uri)}" + if c_type == xslt.XSLT_LOAD_DOCUMENT: +@@ -128,7 +128,7 @@ cdef void _xslt_store_resolver_exception(const_xmlChar* c_uri, void* context, -- cdef bint isvalid(self): -+ cdef bint isvalid(self) noexcept: - if self._valid_ctxt is NULL: - return 1 # valid - return xmlschema.xmlSchemaIsValid(self._valid_ctxt) + cdef xmlDoc* _xslt_doc_loader(const_xmlChar* c_uri, tree.xmlDict* c_dict, + int parse_options, void* c_ctxt, +- xslt.xsltLoadType c_type) nogil: ++ xslt.xsltLoadType c_type) noexcept nogil: + # nogil => no Python objects here, may be called without thread context ! + cdef xmlDoc* c_doc + cdef xmlDoc* result +diff --git a/src/lxml/xsltext.pxi b/src/lxml/xsltext.pxi +index c98ae1f..cfa89f6 100644 +--- a/src/lxml/xsltext.pxi ++++ b/src/lxml/xsltext.pxi +@@ -162,7 +162,7 @@ cdef _registerXSLTExtensions(xslt.xsltTransformContext* c_ctxt, + cdef void _callExtensionElement(xslt.xsltTransformContext* c_ctxt, + xmlNode* c_context_node, + xmlNode* c_inst_node, +- void* dummy) with gil: ++ void* dummy) noexcept with gil: + cdef _XSLTContext context + cdef XSLTExtension extension + cdef python.PyObject* dict_result diff --git a/SPECS/python-lxml/python-lxml.spec b/SPECS/python-lxml/python-lxml.spec index fc773bd5208..c27760a5a6e 100644 --- a/SPECS/python-lxml/python-lxml.spec +++ b/SPECS/python-lxml/python-lxml.spec @@ -3,7 +3,7 @@ Summary: XML and HTML with Python Name: python-lxml Version: 4.9.3 -Release: 1%{?dist} +Release: 2%{?dist} # Test suite (and only the test suite) is GPLv2+ License: BSD and GPLv2+ Vendor: Microsoft Corporation @@ -11,6 +11,7 @@ Distribution: Azure Linux URL: https://lxml.de Source0: https://github.com/lxml/lxml/releases/download/lxml-%{version}/lxml-%{version}.tar.gz Patch0: noexcept.patch +Patch1: CVE-2026-41066.patch BuildRequires: libxslt-devel BuildRequires: libxml2-devel BuildRequires: python3-Cython @@ -33,8 +34,7 @@ with the simplicity of a native Python API, mostly compatible but superior to th ElementTree API. %prep -%setup -n lxml-%{version} -patch -Np1 --ignore-whitespace < %{PATCH0} +%autosetup -p1 -n lxml-%{version} %build %{py3_build "--without-cython"} @@ -53,6 +53,9 @@ make test %{python3_sitelib}/* %changelog +* Wed Apr 29 2026 Azure Linux Security Servicing Account - 4.9.3-2 +- Patch for CVE-2026-41066 + * Fri Nov 10 2023 Andrew Phelps - 4.9.3-1 - Upgrade to version 4.9.3 diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 44c3eb773c8..ed43ea12144 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -545,7 +545,7 @@ python3-libcap-ng-0.8.4-1.azl3.aarch64.rpm python3-libmount-2.40.2-3.azl3.aarch64.rpm python3-libs-3.12.9-10.azl3.aarch64.rpm python3-libxml2-2.11.5-9.azl3.aarch64.rpm -python3-lxml-4.9.3-1.azl3.aarch64.rpm +python3-lxml-4.9.3-2.azl3.aarch64.rpm python3-magic-5.45-1.azl3.noarch.rpm python3-markupsafe-2.1.3-1.azl3.aarch64.rpm python3-newt-0.52.23-1.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index 672974a5f2f..b3e19eca595 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -553,7 +553,7 @@ python3-libcap-ng-0.8.4-1.azl3.x86_64.rpm python3-libmount-2.40.2-3.azl3.x86_64.rpm python3-libs-3.12.9-10.azl3.x86_64.rpm python3-libxml2-2.11.5-9.azl3.x86_64.rpm -python3-lxml-4.9.3-1.azl3.x86_64.rpm +python3-lxml-4.9.3-2.azl3.x86_64.rpm python3-magic-5.45-1.azl3.noarch.rpm python3-markupsafe-2.1.3-1.azl3.x86_64.rpm python3-newt-0.52.23-1.azl3.x86_64.rpm