From: John Wolfe Date: Wed, 23 Mar 2022 19:04:31 +0000 (-0700) Subject: VGAuth: Customize libxml2 to open local file with unescaped file name only. X-Git-Tag: stable-12.1.0~115 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b571bf4026b6f2dee31102a55dd7338c276646f9;p=thirdparty%2Fopen-vm-tools.git VGAuth: Customize libxml2 to open local file with unescaped file name only. --- diff --git a/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c b/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c index aaa5082ac..f5541a9a7 100644 --- a/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c +++ b/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2016-2021 VMware, Inc. All rights reserved. + * Copyright (C) 2016-2022 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -53,6 +55,60 @@ static xmlSchemaValidCtxtPtr gSchemaValidateCtx = NULL; #define CATALOG_FILENAME "catalog.xml" #define SAML_SCHEMA_FILENAME "saml-schema-assertion-2.0.xsd" + +/* + ****************************************************************************** + * UserXmlFileOpen -- */ /** + * + * User defined version of libxml2 export xmlFileOpen. + * + * This function opens a file with its unescaped name only. + * + * xmlInitParser() calls xmlRegisterDefaultInputCallbacks() which calls + * xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, + * xmlFileRead, xmlFileClose) + * + * UserXmlFileOpen is registered at the end of the xmlInputCallback table by + * xmlRegisterInputCallbacks(xmlFileMatch, UserXmlFileOpen, + * xmlFileRead, xmlFileClose) + * + * Based on libxml2 xmlIO.c, precedence is given to user defined handlers. + * + * @param[in] filename The URI file name. + * + * @return A handler or NULL in case of failure. + ****************************************************************************** + */ + +static void * +UserXmlFileOpen(const char *filename) +{ + char *unescaped; + void *retval = NULL; + + g_debug("%s: Incoming file name is \"%s\"\n", __FUNCTION__, filename); + + unescaped = xmlURIUnescapeString(filename, 0, NULL); + if (unescaped != NULL) { + g_debug("%s: Opening file \"%s\"\n", __FUNCTION__, unescaped); + retval = xmlFileOpen(unescaped); + xmlFree(unescaped); + } + + if (retval == NULL) { + g_warning("%s: Failed to open file \"%s\"\n", __FUNCTION__, filename); + /* + * Do not retry xmlFileOpen(filename) here. + * Calling system API to open escaped file paths is risky. This can + * cause unexpected not-secured paths being accessed and expose + * privilege escalation vulnerabilities. + */ + } + + return retval; +} + + /* * Hack to test expired tokens and by-pass the time checks. * @@ -204,9 +260,9 @@ LoadCatalogAndSchema(void) catalogPath = g_build_filename(schemaDir, CATALOG_FILENAME, NULL); schemaPath = g_build_filename(schemaDir, SAML_SCHEMA_FILENAME, NULL); - xmlInitializeCatalog(); - /* + * Skip calling xmlInitializeCatalog(). + * * xmlLoadCatalog() just adds to the default catalog, and won't return an * error if it doesn't exist so long as a default catalog is set. * @@ -354,6 +410,12 @@ SAML_Init(void) /* set up the xml2 error handler */ xmlSetGenericErrorFunc(NULL, XmlErrorHandler); + /* + * Register user defined UserXmlFileOpen + */ + xmlRegisterInputCallbacks(xmlFileMatch, UserXmlFileOpen, + xmlFileRead, xmlFileClose); + /* * Load schemas */