1From 154e565f6ef329c9ec97e6534c411ddde0b320c8 Mon Sep 17 00:00:00 2001 2From: Sebastian Pipping <sebastian@pipping.org> 3Date: Sun, 20 Feb 2022 03:26:57 +0100 4Subject: [PATCH] tests: Protect against nested element declaration 5 model regressions 6 7--- 8 tests/runtests.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ 9 1 file changed, 77 insertions(+) 10 11diff --git a/tests/runtests.c b/tests/runtests.c 12index 2cd4acb..e28670d 100644 13--- a/tests/runtests.c 14+++ b/tests/runtests.c 15@@ -2664,6 +2664,82 @@ START_TEST(test_dtd_elements) { 16 } 17 END_TEST 18 19+static void XMLCALL 20+element_decl_check_model(void *userData, const XML_Char *name, 21+ XML_Content *model) { 22+ UNUSED_P(userData); 23+ uint32_t errorFlags = 0; 24+ 25+ /* Expected model array structure is this: 26+ * [0] (type 6, quant 0) 27+ * [1] (type 5, quant 0) 28+ * [3] (type 4, quant 0, name "bar") 29+ * [4] (type 4, quant 0, name "foo") 30+ * [5] (type 4, quant 3, name "xyz") 31+ * [2] (type 4, quant 2, name "zebra") 32+ */ 33+ errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0)); 34+ errorFlags |= ((model != NULL) ? 0 : (1u << 1)); 35+ 36+ errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2)); 37+ errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3)); 38+ errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4)); 39+ errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5)); 40+ errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6)); 41+ 42+ errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7)); 43+ errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8)); 44+ errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9)); 45+ errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10)); 46+ errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11)); 47+ 48+ errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12)); 49+ errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13)); 50+ errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14)); 51+ errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15)); 52+ errorFlags |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16)); 53+ 54+ errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17)); 55+ errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18)); 56+ errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19)); 57+ errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20)); 58+ errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21)); 59+ 60+ errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22)); 61+ errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23)); 62+ errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24)); 63+ errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25)); 64+ errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26)); 65+ 66+ errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27)); 67+ errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28)); 68+ errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29)); 69+ errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30)); 70+ errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31)); 71+ 72+ XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags); 73+ XML_FreeContentModel(g_parser, model); 74+} 75+ 76+START_TEST(test_dtd_elements_nesting) { 77+ // Payload inspired by a test in Perl's XML::Parser 78+ const char *text = "<!DOCTYPE foo [\n" 79+ "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n" 80+ "]>\n" 81+ "<foo/>"; 82+ 83+ XML_SetUserData(g_parser, (void *)(uintptr_t)-1); 84+ 85+ XML_SetElementDeclHandler(g_parser, element_decl_check_model); 86+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) 87+ == XML_STATUS_ERROR) 88+ xml_failure(g_parser); 89+ 90+ if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0) 91+ fail("Element declaration model regression detected"); 92+} 93+END_TEST 94+ 95 /* Test foreign DTD handling */ 96 START_TEST(test_set_foreign_dtd) { 97 const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"; 98@@ -11863,6 +11939,7 @@ make_suite(void) { 99 tcase_add_test(tc_basic, test_memory_allocation); 100 tcase_add_test(tc_basic, test_default_current); 101 tcase_add_test(tc_basic, test_dtd_elements); 102+ tcase_add_test(tc_basic, test_dtd_elements_nesting); 103 tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd); 104 tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone); 105 tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd); 106-- 1071.8.3.1 108 109