util/xml.lua
branch0.11
changeset 12185 783056b4e448
parent 8558 4f0f5b49bb03
child 12205 e5e0ab93d7f4
--- a/util/xml.lua	Mon Dec 20 16:24:52 2021 +0100
+++ b/util/xml.lua	Mon Jan 10 18:23:54 2022 +0100
@@ -3,6 +3,7 @@
 local lxp = require "lxp";
 local t_insert = table.insert;
 local t_remove = table.remove;
+local error = error;
 
 local _ENV = nil;
 -- luacheck: std none
@@ -13,7 +14,7 @@
 	};
 	local ns_separator = "\1";
 	local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
-	return function(xml)
+	return function(xml, options)
 		--luacheck: ignore 212/self
 		local handler = {};
 		local stanza = st.stanza("root");
@@ -64,7 +65,27 @@
 		function handler:EndElement()
 			stanza:up();
 		end
-		local parser = lxp.new(handler, "\1");
+		local parser;
+		-- SECURITY: These two handlers, especially the Doctype one, are required to prevent exploits such as Billion Laughs.
+		function handler:StartDoctypeDecl()
+			if not parser.stop or not parser:stop() then
+				error("Failed to abort parsing");
+			end
+		end
+		function handler:ProcessingInstruction()
+			if not parser.stop or not parser:stop() then
+				error("Failed to abort parsing");
+			end
+		end
+		if not options or not options.allow_comments then
+			-- NOTE: comments are generally harmless and can be useful when parsing configuration files or other data, even user-provided data
+			function handler:Comment()
+				if not parser.stop or not parser:stop() then
+					error("Failed to abort parsing");
+				end
+			end
+		end
+		parser = lxp.new(handler, ns_separator);
 		local ok, err, line, col = parser:parse(xml);
 		if ok then ok, err, line, col = parser:parse(); end
 		--parser:close();