1From 1b41ec4e9433b05bb0376be4725804c54ef1d80b Mon Sep 17 00:00:00 2001 2From: Nick Wellnhofer <wellnhofer@aevum.de> 3Date: Wed, 31 Aug 2022 22:11:25 +0200 4Subject: [PATCH] [CVE-2022-40304] Fix dict corruption caused by entity 5 reference cycles 6 7When an entity reference cycle is detected, the entity content is 8cleared by setting its first byte to zero. But the entity content might 9be allocated from a dict. In this case, the dict entry becomes corrupted 10leading to all kinds of logic errors, including memory errors like 11double-frees. 12 13Stop storing entity content, orig, ExternalID and SystemID in a dict. 14These values are unlikely to occur multiple times in a document, so they 15shouldn't have been stored in a dict in the first place. 16 17Thanks to Ned Williamson and Nathan Wachholz working with Google Project 18Zero for the report! 19--- 20 entities.c | 55 ++++++++++++++++-------------------------------------- 21 1 file changed, 16 insertions(+), 39 deletions(-) 22 23diff --git a/entities.c b/entities.c 24index 84435515..d4e5412e 100644 25--- a/entities.c 26+++ b/entities.c 27@@ -128,36 +128,19 @@ xmlFreeEntity(xmlEntityPtr entity) 28 if ((entity->children) && (entity->owner == 1) && 29 (entity == (xmlEntityPtr) entity->children->parent)) 30 xmlFreeNodeList(entity->children); 31- if (dict != NULL) { 32- if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name))) 33- xmlFree((char *) entity->name); 34- if ((entity->ExternalID != NULL) && 35- (!xmlDictOwns(dict, entity->ExternalID))) 36- xmlFree((char *) entity->ExternalID); 37- if ((entity->SystemID != NULL) && 38- (!xmlDictOwns(dict, entity->SystemID))) 39- xmlFree((char *) entity->SystemID); 40- if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI))) 41- xmlFree((char *) entity->URI); 42- if ((entity->content != NULL) 43- && (!xmlDictOwns(dict, entity->content))) 44- xmlFree((char *) entity->content); 45- if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig))) 46- xmlFree((char *) entity->orig); 47- } else { 48- if (entity->name != NULL) 49- xmlFree((char *) entity->name); 50- if (entity->ExternalID != NULL) 51- xmlFree((char *) entity->ExternalID); 52- if (entity->SystemID != NULL) 53- xmlFree((char *) entity->SystemID); 54- if (entity->URI != NULL) 55- xmlFree((char *) entity->URI); 56- if (entity->content != NULL) 57- xmlFree((char *) entity->content); 58- if (entity->orig != NULL) 59- xmlFree((char *) entity->orig); 60- } 61+ if ((entity->name != NULL) && 62+ ((dict == NULL) || (!xmlDictOwns(dict, entity->name)))) 63+ xmlFree((char *) entity->name); 64+ if (entity->ExternalID != NULL) 65+ xmlFree((char *) entity->ExternalID); 66+ if (entity->SystemID != NULL) 67+ xmlFree((char *) entity->SystemID); 68+ if (entity->URI != NULL) 69+ xmlFree((char *) entity->URI); 70+ if (entity->content != NULL) 71+ xmlFree((char *) entity->content); 72+ if (entity->orig != NULL) 73+ xmlFree((char *) entity->orig); 74 xmlFree(entity); 75 } 76 77@@ -193,18 +176,12 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, 78 ret->SystemID = xmlStrdup(SystemID); 79 } else { 80 ret->name = xmlDictLookup(dict, name, -1); 81- if (ExternalID != NULL) 82- ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); 83- if (SystemID != NULL) 84- ret->SystemID = xmlDictLookup(dict, SystemID, -1); 85+ ret->ExternalID = xmlStrdup(ExternalID); 86+ ret->SystemID = xmlStrdup(SystemID); 87 } 88 if (content != NULL) { 89 ret->length = xmlStrlen(content); 90- if ((dict != NULL) && (ret->length < 5)) 91- ret->content = (xmlChar *) 92- xmlDictLookup(dict, content, ret->length); 93- else 94- ret->content = xmlStrndup(content, ret->length); 95+ ret->content = xmlStrndup(content, ret->length); 96 } else { 97 ret->length = 0; 98 ret->content = NULL; 99-- 1002.27.0 101 102