From b7220480b838599f40eae1b6ce7e3a29b9bdb99b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 31 Aug 2022 22:11:25 +0200 Subject: [PATCH] [CVE-2022-40304] Fix dict corruption caused by entity reference cycles When an entity reference cycle is detected, the entity content is cleared by setting its first byte to zero. But the entity content might be allocated from a dict. In this case, the dict entry becomes corrupted leading to all kinds of logic errors, including memory errors like double-frees. Stop storing entity content, orig, ExternalID and SystemID in a dict. These values are unlikely to occur multiple times in a document, so they shouldn't have been stored in a dict in the first place. Thanks to Ned Williamson and Nathan Wachholz working with Google Project Zero for the report! Change-Id: Ic72980e9951365347f484203817b37fa41e65d52 Signed-off-by: DongHun Kwak --- entities.c | 55 ++++++++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/entities.c b/entities.c index 1a8f86f..ec1b9a7 100644 --- a/entities.c +++ b/entities.c @@ -112,36 +112,19 @@ xmlFreeEntity(xmlEntityPtr entity) if ((entity->children) && (entity->owner == 1) && (entity == (xmlEntityPtr) entity->children->parent)) xmlFreeNodeList(entity->children); - if (dict != NULL) { - if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name))) - xmlFree((char *) entity->name); - if ((entity->ExternalID != NULL) && - (!xmlDictOwns(dict, entity->ExternalID))) - xmlFree((char *) entity->ExternalID); - if ((entity->SystemID != NULL) && - (!xmlDictOwns(dict, entity->SystemID))) - xmlFree((char *) entity->SystemID); - if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI))) - xmlFree((char *) entity->URI); - if ((entity->content != NULL) - && (!xmlDictOwns(dict, entity->content))) - xmlFree((char *) entity->content); - if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig))) - xmlFree((char *) entity->orig); - } else { - if (entity->name != NULL) - xmlFree((char *) entity->name); - if (entity->ExternalID != NULL) - xmlFree((char *) entity->ExternalID); - if (entity->SystemID != NULL) - xmlFree((char *) entity->SystemID); - if (entity->URI != NULL) - xmlFree((char *) entity->URI); - if (entity->content != NULL) - xmlFree((char *) entity->content); - if (entity->orig != NULL) - xmlFree((char *) entity->orig); - } + if ((entity->name != NULL) && + ((dict == NULL) || (!xmlDictOwns(dict, entity->name)))) + xmlFree((char *) entity->name); + if (entity->ExternalID != NULL) + xmlFree((char *) entity->ExternalID); + if (entity->SystemID != NULL) + xmlFree((char *) entity->SystemID); + if (entity->URI != NULL) + xmlFree((char *) entity->URI); + if (entity->content != NULL) + xmlFree((char *) entity->content); + if (entity->orig != NULL) + xmlFree((char *) entity->orig); xmlFree(entity); } @@ -177,18 +160,12 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, ret->SystemID = xmlStrdup(SystemID); } else { ret->name = xmlDictLookup(dict, name, -1); - if (ExternalID != NULL) - ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); - if (SystemID != NULL) - ret->SystemID = xmlDictLookup(dict, SystemID, -1); + ret->ExternalID = xmlStrdup(ExternalID); + ret->SystemID = xmlStrdup(SystemID); } if (content != NULL) { ret->length = xmlStrlen(content); - if ((dict != NULL) && (ret->length < 5)) - ret->content = (xmlChar *) - xmlDictLookup(dict, content, ret->length); - else - ret->content = xmlStrndup(content, ret->length); + ret->content = xmlStrndup(content, ret->length); } else { ret->length = 0; ret->content = NULL; -- 2.7.4