From: Andrey Volk Date: Thu, 7 May 2026 17:18:11 +0000 (+0300) Subject: Merge commit from fork X-Git-Tag: v1.11.0^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a7100053a2cdb9621d22a617034299bab79d9fb;p=thirdparty%2Ffreeswitch.git Merge commit from fork --- diff --git a/Freeswitch.2017.sln b/Freeswitch.2017.sln index fe36ea8714..54c119cc12 100644 --- a/Freeswitch.2017.sln +++ b/Freeswitch.2017.sln @@ -532,6 +532,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_tts_format", "tests\un EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_test", "src\mod\applications\mod_test\mod_test.2017.vcxproj", "{E9FF8127-D5F0-2398-59EB-702CE55F7800}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_switch_xml", "tests\unit\test_switch_xml.2017.vcxproj", "{FED39CFF-E6CD-1C09-844D-F1174B8A5C18}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2390,6 +2392,18 @@ Global {E9FF8127-D5F0-2398-59EB-702CE55F7800}.Release|Win32.Build.0 = Release|Win32 {E9FF8127-D5F0-2398-59EB-702CE55F7800}.Release|x64.ActiveCfg = Release|x64 {E9FF8127-D5F0-2398-59EB-702CE55F7800}.Release|x64.Build.0 = Release|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.All|Win32.ActiveCfg = Debug|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.All|Win32.Build.0 = Debug|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.All|x64.ActiveCfg = Debug|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.All|x64.Build.0 = Debug|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Debug|Win32.ActiveCfg = Debug|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Debug|Win32.Build.0 = Debug|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Debug|x64.ActiveCfg = Debug|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Debug|x64.Build.0 = Debug|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Release|Win32.ActiveCfg = Release|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Release|Win32.Build.0 = Release|Win32 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Release|x64.ActiveCfg = Release|x64 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2578,6 +2592,7 @@ Global {589A07E7-5DE5-49FD-A62C-27795B806AFB} = {9388C266-C3FC-468A-92EF-0CBC35941412} {3745B86B-6BE8-3E67-FCB9-BE62A6131D67} = {9388C266-C3FC-468A-92EF-0CBC35941412} {E9FF8127-D5F0-2398-59EB-702CE55F7800} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18} = {9388C266-C3FC-468A-92EF-0CBC35941412} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {09840DE7-9208-45AA-9667-1A71EE93BD1E} diff --git a/src/switch_xml.c b/src/switch_xml.c index 0194645640..027b8f093b 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -103,6 +103,10 @@ void globfree(glob_t *); #define SWITCH_XML_WS "\t\r\n " /* whitespace */ #define SWITCH_XML_ERRL 128 /* maximum error string length */ +/* Limits for entity expansion to prevent excessive resource consumption */ +#define SWITCH_XML_MAX_ENTITY_EXPANSION_DEPTH 20 /* Maximum recursion depth for entity expansion */ +#define SWITCH_XML_MAX_ENTITY_EXPANSION_COUNT 10000 /* Maximum number of entity expansions */ + static void preprocess_exec_set(char *keyval) { char *key = keyval; @@ -760,25 +764,56 @@ static switch_xml_t switch_xml_close_tag(switch_xml_root_t root, char *name, cha return NULL; } -/* checks for circular entity references, returns non-zero if no circular - references are found, zero otherwise */ -static int switch_xml_ent_ok(char *name, char *s, char **ent) +/* Depth-limited version with resource limits for entity validation */ +static int switch_xml_ent_ok_with_depth(char *name, char *s, char **ent, int depth, unsigned long *check_count) { int i; + /* Prevent excessive recursion during entity validation */ + if (depth > SWITCH_XML_MAX_ENTITY_EXPANSION_DEPTH) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Entity validation depth limit exceeded (%d > %d) for entity: %s\n", + depth, SWITCH_XML_MAX_ENTITY_EXPANSION_DEPTH, name); + + return 0; /* Treat as invalid - too deep */ + } + for (;; s++) { - while (*s && *s != '&') + while (*s && *s != '&') { s++; /* find next entity reference */ + } + if (!*s) return 1; + + /* Increment check counter for each entity reference found */ + if (++(*check_count) > SWITCH_XML_MAX_ENTITY_EXPANSION_COUNT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Entity validation count limit exceeded (%lu > %d) for entity: %s\n", + *check_count, SWITCH_XML_MAX_ENTITY_EXPANSION_COUNT, name); + + return 0; /* Treat as invalid - too many entity references */ + } + if (!strncmp(s + 1, name, strlen(name))) return 0; /* circular ref. */ + for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2); - if (ent[i] && !switch_xml_ent_ok(name, ent[i + 1], ent)) + + if (ent[i] && !switch_xml_ent_ok_with_depth(name, ent[i + 1], ent, depth + 1, check_count)) return 0; } } +/* checks for circular entity references, returns non-zero if no circular + references are found, zero otherwise */ +static int switch_xml_ent_ok(char *name, char *s, char **ent) +{ + unsigned long check_count = 0; + + return switch_xml_ent_ok_with_depth(name, s, ent, 0, &check_count); +} + /* called when the parser finds a processing instruction */ static void switch_xml_proc_inst(switch_xml_root_t root, char *s, switch_size_t len) { diff --git a/tests/unit/switch_xml.c b/tests/unit/switch_xml.c index a48aa4f032..0e5fc861d5 100644 --- a/tests/unit/switch_xml.c +++ b/tests/unit/switch_xml.c @@ -185,6 +185,71 @@ FST_MINCORE_BEGIN("./conf") } FST_TEST_END() + FST_TEST_BEGIN(test_exponential_entity_expansion) + { + /* Test handling of exponentially nested entity definitions + * Each entity references the previous one 10 times, creating + * 10^10 total references which would consume excessive memory + * if fully expanded. Parser should enforce expansion limits. + */ + const char *nested_entities = + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "]>\n" + "&lol10;"; + + switch_xml_t xml = switch_xml_parse_str_dynamic((char *)nested_entities, SWITCH_TRUE); + + if (xml) { + const char *error = switch_xml_error(xml); + if (error && *error) { + /* Parser enforced expansion limits */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Parser correctly enforced entity expansion limits: %s\n", error); + switch_xml_free(xml); + } else { + /* Parser did not enforce limits */ + switch_xml_free(xml); + fst_fail("Parser did not enforce entity expansion limits"); + } + } else { + /* Parser returned NULL */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Parser rejected excessive entity expansion\n"); + } + } + FST_TEST_END() + + FST_TEST_BEGIN(test_entity_expansion_limit) + { + /* Test that reasonable entity usage still works */ + const char *safe_entities = + "\n" + "\n" + "\n" + "]>\n" + "&product;"; + + switch_xml_t xml = switch_xml_parse_str_dynamic((char *)safe_entities, SWITCH_TRUE); + + fst_requires(xml); + fst_check_string_equals(xml->txt, "FreeSWITCH Media Server"); + switch_xml_free(xml); + } + FST_TEST_END() } FST_SUITE_END() } diff --git a/tests/unit/test_switch_xml.2017.vcxproj b/tests/unit/test_switch_xml.2017.vcxproj new file mode 100644 index 0000000000..60240f138b --- /dev/null +++ b/tests/unit/test_switch_xml.2017.vcxproj @@ -0,0 +1,208 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + test_switch_xml + test_switch_xml + Win32Proj + 10.0 + {FED39CFF-E6CD-1C09-844D-F1174B8A5C18} + + + + Application + MultiByte + $(DefaultPlatformToolset) + + + Application + MultiByte + $(DefaultPlatformToolset) + + + Application + MultiByte + $(DefaultPlatformToolset) + + + Application + MultiByte + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + + + + $(SolutionDir)src\include;%(AdditionalIncludeDirectories) + SWITCH_TEST_BASE_DIR_FOR_CONF="..\\..\\tests\\unit\\";%(PreprocessorDefinitions) + + + Bcrypt.lib;%(AdditionalDependencies) + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + true + 6031;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + $(OutDir);%(AdditionalLibraryDirectories) + true + Console + true + + + MachineX86 + + + + + + X64 + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + ProgramDatabase + true + 6031;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + $(OutDir);%(AdditionalLibraryDirectories) + true + Console + true + + + MachineX64 + + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + ProgramDatabase + 6031;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + $(OutDir);%(AdditionalLibraryDirectories) + false + Console + true + true + true + + + MachineX86 + + + + + + X64 + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + ProgramDatabase + 6031;6340;6246;6011;6387;%(DisableSpecificWarnings) + + + $(OutDir);%(AdditionalLibraryDirectories) + false + Console + true + true + true + + + MachineX64 + + + + + + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + \ No newline at end of file