[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1024745: marked as done (bullseye-pu: package node-xmldom/0.5.0-1+deb11u2)



Your message dated Sat, 17 Dec 2022 10:57:10 +0000
with message-id <03e9b90cf2f149b9e2835590c9ec0ccb048b744d.camel@adam-barratt.org.uk>
and subject line Closing p-u requests for fixes included in 11.6
has caused the Debian Bug report #1024745,
regarding bullseye-pu: package node-xmldom/0.5.0-1+deb11u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1024745: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1024745
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
node-xmldom is vulnerable: it doesn't verify that root element is uniq
(#1024736, CVE-2022-39353)

[ Impact ]
Medium vulnerability

[ Tests ]
Test still pass

[ Risks ]
Moderate risk: test still pass and patch isn't too big

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
Verify XML document before change it

Cheers,
Yadd
diff --git a/debian/changelog b/debian/changelog
index e486812..50d0288 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+node-xmldom (0.5.0-1+deb11u2) bullseye; urgency=medium
+
+  * Team upload
+  * Prevent inserting DOM nodes when they are not well-formed
+    (Closes: #1024736, CVE-2022-39353)
+
+ -- Yadd <yadd@debian.org>  Thu, 24 Nov 2022 09:22:10 +0100
+
 node-xmldom (0.5.0-1+deb11u1) bullseye; urgency=medium
 
   * Team upload
diff --git a/debian/patches/CVE-2022-39353.patch b/debian/patches/CVE-2022-39353.patch
new file mode 100644
index 0000000..b15040a
--- /dev/null
+++ b/debian/patches/CVE-2022-39353.patch
@@ -0,0 +1,270 @@
+Description: Prevent inserting DOM nodes when they are not well-formed
+Author: Christian Bewernitz <coder@karfau.de>
+Origin: upstream, https://github.com/xmldom/xmldom/commit/7ff7c10a
+Bug: https://github.com/xmldom/xmldom/security/advisories/GHSA-crh6-fp67-6883
+Bug-Debian: https://bugs.debian.org/1024736
+Forwarded: not-needed
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2022-11-24
+
+--- a/lib/dom.js
++++ b/lib/dom.js
+@@ -111,7 +111,31 @@
+ 			serializeToString(this[i],buf,isHTML,nodeFilter);
+ 		}
+ 		return buf.join('');
+-	}
++	},
++	/**
++	 * @private
++	 * @param {function (Node):boolean} predicate
++	 * @returns {Node | undefined}
++	 */
++	find: function (predicate) {
++		return Array.prototype.find.call(this, predicate);
++	},
++	/**
++	 * @private
++	 * @param {function (Node):boolean} predicate
++	 * @returns {Node[]}
++	 */
++	filter: function (predicate) {
++		return Array.prototype.filter.call(this, predicate);
++	},
++	/**
++	 * @private
++	 * @param {Node} item
++	 * @returns {number}
++	 */
++	indexOf: function (item) {
++		return Array.prototype.indexOf.call(this, item);
++	},
+ };
+ function LiveNodeList(node,refresh){
+ 	this._node = node;
+@@ -182,7 +206,7 @@
+ 			}
+ 		}
+ 	}else{
+-		throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
++		throw new DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
+ 	}
+ }
+ NamedNodeMap.prototype = {
+@@ -496,48 +520,177 @@
+ 	_onUpdateChild(parentNode.ownerDocument,parentNode);
+ 	return child;
+ }
++
+ /**
+- * preformance key(refChild == null)
++ * Returns `true` if `node` can be a parent for insertion.
++ * @param {Node} node
++ * @returns {boolean}
+  */
+-function _insertBefore(parentNode,newChild,nextChild){
+-	var cp = newChild.parentNode;
++function hasValidParentNodeType(node) {
++	return (
++		node &&
++		(node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.ELEMENT_NODE)
++	);
++}
++
++/**
++ * Returns `true` if `node` can be inserted according to it's `nodeType`.
++ * @param {Node} node
++ * @returns {boolean}
++ */
++function hasInsertableNodeType(node) {
++	return (
++		node &&
++		(isElementNode(node) ||
++			isTextNode(node) ||
++			isDocTypeNode(node) ||
++			node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
++			node.nodeType === Node.COMMENT_NODE ||
++			node.nodeType === Node.PROCESSING_INSTRUCTION_NODE)
++	);
++}
++
++/**
++ * Returns true if `node` is a DOCTYPE node
++ * @param {Node} node
++ * @returns {boolean}
++ */
++function isDocTypeNode(node) {
++	return node && node.nodeType === Node.DOCUMENT_TYPE_NODE;
++}
++
++/**
++ * Returns true if the node is an element
++ * @param {Node} node
++ * @returns {boolean}
++ */
++function isElementNode(node) {
++	return node && node.nodeType === Node.ELEMENT_NODE;
++}
++/**
++ * Returns true if `node` is a text node
++ * @param {Node} node
++ * @returns {boolean}
++ */
++function isTextNode(node) {
++	return node && node.nodeType === Node.TEXT_NODE;
++}
++
++/**
++ * Check if en element node can be inserted before `child`, or at the end if child is falsy,
++ * according to the presence and position of a doctype node on the same level.
++ *
++ * @param {Document} doc The document node
++ * @param {Node} child the node that would become the nextSibling if the element would be inserted
++ * @returns {boolean} `true` if an element can be inserted before child
++ * @private
++ * https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
++ */
++function isElementInsertionPossible(doc, child) {
++	var parentChildNodes = doc.childNodes || [];
++	if (parentChildNodes.find(isElementNode) || isDocTypeNode(child)) {
++		return false;
++	}
++	var docTypeNode = parentChildNodes.find(isDocTypeNode);
++	return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
++}
++/**
++ * @private
++ * @param {Node} parent the parent node to insert `node` into
++ * @param {Node} node the node to insert
++ * @param {Node=} child the node that should become the `nextSibling` of `node`
++ * @returns {Node}
++ * @throws DOMException for several node combinations that would create a DOM that is not well-formed.
++ * @throws DOMException if `child` is provided but is not a child of `parent`.
++ * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
++ */
++function _insertBefore(parent, node, child) {
++	if (!hasValidParentNodeType(parent)) {
++		throw new DOMException(HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
++	}
++	if (child && child.parentNode !== parent) {
++		throw new DOMException(NOT_FOUND_ERR, 'child not in parent');
++	}
++	if (
++		!hasInsertableNodeType(node) ||
++		// the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
++		// || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
++		(isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
++	) {
++		throw new DOMException(
++			HIERARCHY_REQUEST_ERR,
++			'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
++		);
++	}
++	var parentChildNodes = parent.childNodes || [];
++	var nodeChildNodes = node.childNodes || [];
++	if (parent.nodeType === Node.DOCUMENT_NODE) {
++		if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
++			let nodeChildElements = nodeChildNodes.filter(isElementNode);
++			if (nodeChildElements.length > 1 || nodeChildNodes.find(isTextNode)) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
++			}
++			if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
++			}
++		}
++		if (isElementNode(node)) {
++			if (parentChildNodes.find(isElementNode) || !isElementInsertionPossible(parent, child)) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
++			}
++		}
++		if (isDocTypeNode(node)) {
++			if (parentChildNodes.find(isDocTypeNode)) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
++			}
++			let parentElementChild = parentChildNodes.find(isElementNode);
++			if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
++			}
++			if (!child && parentElementChild) {
++				throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
++			}
++		}
++	}
++
++	var cp = node.parentNode;
+ 	if(cp){
+-		cp.removeChild(newChild);//remove and update
++		cp.removeChild(node);//remove and update
+ 	}
+-	if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
+-		var newFirst = newChild.firstChild;
++	if(node.nodeType === DOCUMENT_FRAGMENT_NODE){
++		var newFirst = node.firstChild;
+ 		if (newFirst == null) {
+-			return newChild;
++			return node;
+ 		}
+-		var newLast = newChild.lastChild;
++		var newLast = node.lastChild;
+ 	}else{
+-		newFirst = newLast = newChild;
++		newFirst = newLast = node;
+ 	}
+-	var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
++	var pre = child ? child.previousSibling : parent.lastChild;
+ 
+ 	newFirst.previousSibling = pre;
+-	newLast.nextSibling = nextChild;
+-	
+-	
++	newLast.nextSibling = child;
++
++
+ 	if(pre){
+ 		pre.nextSibling = newFirst;
+ 	}else{
+-		parentNode.firstChild = newFirst;
++		parent.firstChild = newFirst;
+ 	}
+-	if(nextChild == null){
+-		parentNode.lastChild = newLast;
++	if(child == null){
++		parent.lastChild = newLast;
+ 	}else{
+-		nextChild.previousSibling = newLast;
++		child.previousSibling = newLast;
+ 	}
+ 	do{
+-		newFirst.parentNode = parentNode;
++		newFirst.parentNode = parent;
+ 	}while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
+-	_onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
+-	//console.log(parentNode.lastChild.nextSibling == null)
+-	if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
+-		newChild.firstChild = newChild.lastChild = null;
++	_onUpdateChild(parent.ownerDocument||parent, parent);
++	//console.log(parent.lastChild.nextSibling == null)
++	if (node.nodeType == DOCUMENT_FRAGMENT_NODE) {
++		node.firstChild = node.lastChild = null;
+ 	}
+-	return newChild;
++	return node;
+ }
+ function _appendSingleChild(parentNode,newChild){
+ 	var cp = newChild.parentNode;
+@@ -578,11 +731,13 @@
+ 			}
+ 			return newChild;
+ 		}
+-		if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
++		_insertBefore(this, newChild, refChild);
++		newChild.ownerDocument = this;
++		if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) {
+ 			this.documentElement = newChild;
+ 		}
+ 		
+-		return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
++		return newChild;
+ 	},
+ 	removeChild :  function(oldChild){
+ 		if(this.documentElement == oldChild){
diff --git a/debian/patches/series b/debian/patches/series
index 8f56e74..d272af1 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
 CVE-2022-37616.patch
+CVE-2022-39353.patch

--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 11.6

Hi,

Each of the updates referred to in these requests was included in this
morning's 11.6 point release.

Regards,

Adam

--- End Message ---

Reply to: