Merge pull request #669 from leethomason/overflow

Fix stack overflows
This commit is contained in:
Lee Thomason
2018-04-05 22:56:48 -07:00
committed by GitHub
8 changed files with 88 additions and 23 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1004,7 +1004,11 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
// 'endTag' is the end tag for this node, it is returned by a call to a child.
// 'parentEnd' is the end tag for the parent, which is filled in and returned.
while( p && *p ) {
XMLDocument::DepthTracker tracker(_document);
if (_document->Error())
return 0;
while( p && *p ) {
XMLNode* node = 0;
p = _document->Identify( p, &node );
@@ -1986,7 +1990,8 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
"XML_ERROR_MISMATCHED_ELEMENT",
"XML_ERROR_PARSING",
"XML_CAN_NOT_CONVERT_TEXT",
"XML_NO_TEXT_NODE"
"XML_NO_TEXT_NODE",
"XML_ELEMENT_DEPTH_EXCEEDED"
};
@@ -2000,6 +2005,7 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
_errorLineNum( 0 ),
_charBuffer( 0 ),
_parseCurLineNum( 0 ),
_parsingDepth(0),
_unlinked(),
_elementPool(),
_attributePool(),
@@ -2044,6 +2050,7 @@ void XMLDocument::Clear()
delete [] _charBuffer;
_charBuffer = 0;
_parsingDepth = 0;
#if 0
_textPool.Trace( "text" );
@@ -2377,6 +2384,20 @@ void XMLDocument::Parse()
ParseDeep(p, 0, &_parseCurLineNum );
}
void XMLDocument::PushDepth()
{
_parsingDepth++;
if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
}
}
void XMLDocument::PopDepth()
{
TIXMLASSERT(_parsingDepth > 0);
--_parsingDepth;
}
XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_elementJustOpened( false ),
_stack(),

View File

@@ -106,6 +106,13 @@ static const int TIXML2_PATCH_VERSION = 0;
#define TINYXML2_MINOR_VERSION 1
#define TINYXML2_PATCH_VERSION 0
// A fixed element depth limit is problematic. There needs to be a
// limit to avoid a stack overflow. However, that limit varies per
// system, and the capacity of the stack. On the other hand, it's a trivial
// attack that can result from ill, malicious, or even correctly formed XML,
// so there needs to be a limit in place.
static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
namespace tinyxml2
{
class XMLDocument;
@@ -532,6 +539,7 @@ enum XMLError {
XML_ERROR_PARSING,
XML_CAN_NOT_CONVERT_TEXT,
XML_NO_TEXT_NODE,
XML_ELEMENT_DEPTH_EXCEEDED,
XML_ERROR_COUNT
};
@@ -1650,7 +1658,7 @@ enum Whitespace {
class TINYXML2_LIB XMLDocument : public XMLNode
{
friend class XMLElement;
// Gives access to SetError, but over-access for everything else.
// Gives access to SetError and Push/PopDepth, but over-access for everything else.
// Wishing C++ had "internal" scope.
friend class XMLNode;
friend class XMLText;
@@ -1874,6 +1882,7 @@ private:
int _errorLineNum;
char* _charBuffer;
int _parseCurLineNum;
int _parsingDepth;
// Memory tracking does add some overhead.
// However, the code assumes that you don't
// have a bunch of unlinked nodes around.
@@ -1893,6 +1902,24 @@ private:
void SetError( XMLError error, int lineNum, const char* format, ... );
// Something of an obvious security hole, once it was discovered.
// Either an ill-formed XML or an excessively deep one can overflow
// the stack. Track stack depth, and error out if needed.
class DepthTracker {
public:
DepthTracker(XMLDocument * document) {
this->_document = document;
document->PushDepth();
}
~DepthTracker() {
_document->PopDepth();
}
private:
XMLDocument * _document;
};
void PushDepth();
void PopDepth();
template<class NodeType, int PoolElementSize>
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
};

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug-Dll|Win32">
<Configuration>Debug-Dll</Configuration>
@@ -37,60 +37,60 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{E8FB2712-8666-4662-A5B8-2B5B0FB1A260}</ProjectGuid>
<RootNamespace>test</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<CharacterSet>Unicode</CharacterSet>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug-Dll|Win32">
<Configuration>Debug-Dll</Configuration>
@@ -38,60 +38,60 @@
<ProjectGuid>{D1C528B6-AA02-4D29-9D61-DC08E317A70D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>tinyxml2</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Lib|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dll|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Lib|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dll|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ConfigurationType>StaticLibrary</ConfigurationType>

View File

@@ -2025,6 +2025,20 @@ int main( int argc, const char ** argv )
}
}
{
// Bad bad crash. Parsing error results in stack overflow, if uncaught.
const char* TESTS[] = {
"./resources/xmltest-5330.xml",
"./resources/xmltest-4636783552757760.xml",
"./resources/xmltest-5720541257269248.xml",
0
};
for (int i=0; TESTS[i]; ++i) {
XMLDocument doc;
doc.LoadFile(TESTS[i]);
XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
}
}
{
// Crashing reported via email.
const char* xml =