summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorandreykproductengine <andreykproductengine@lindenlab.com>2018-02-01 16:35:02 +0200
committerandreykproductengine <andreykproductengine@lindenlab.com>2018-02-01 16:35:02 +0200
commit64b9b4c771430dcb0d65d557402b5f8bf81aa5a0 (patch)
tree4ab64c390d1a435326a8679da2dbc3096c13c43b /indra/llcommon
parent25e19c0e6f1d6dfc21f3c1695e0d6bfcec6a8ee9 (diff)
MAINT-2338 Implemented binary parser depth control
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llsdserialize.cpp43
-rw-r--r--indra/llcommon/llsdserialize.h38
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp2
3 files changed, 52 insertions, 31 deletions
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index be54ed053b..580e87954b 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -51,6 +51,7 @@
// File constants
static const int MAX_HDR_LEN = 20;
+static const S32 UNZIP_LLSD_MAX_DEPTH = 96;
static const char LEGACY_NON_HEADER[] = "<llsd>";
const std::string LLSD_BINARY_HEADER("LLSD/Binary");
const std::string LLSD_XML_HEADER("LLSD/XML");
@@ -317,11 +318,11 @@ LLSDParser::LLSDParser()
LLSDParser::~LLSDParser()
{ }
-S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes)
+S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth)
{
mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true;
mMaxBytesLeft = max_bytes;
- return doParse(istr, data);
+ return doParse(istr, data, max_depth);
}
@@ -403,7 +404,7 @@ LLSDNotationParser::~LLSDNotationParser()
{ }
// virtual
-S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
+S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
{
// map: { string:object, string:object }
// array: [ object, object, object ]
@@ -418,6 +419,10 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
// binary: b##"ff3120ab1" | b(size)"raw data"
char c;
c = istr.peek();
+ if (max_depth == 0)
+ {
+ return PARSE_FAILURE;
+ }
while(isspace(c))
{
// pop the whitespace.
@@ -434,7 +439,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
{
case '{':
{
- S32 child_count = parseMap(istr, data);
+ S32 child_count = parseMap(istr, data, max_depth - 1);
if((child_count == PARSE_FAILURE) || data.isUndefined())
{
parse_count = PARSE_FAILURE;
@@ -453,7 +458,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
case '[':
{
- S32 child_count = parseArray(istr, data);
+ S32 child_count = parseArray(istr, data, max_depth - 1);
if((child_count == PARSE_FAILURE) || data.isUndefined())
{
parse_count = PARSE_FAILURE;
@@ -658,7 +663,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const
return parse_count;
}
-S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
+S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
{
// map: { string:object, string:object }
map = LLSD::emptyMap();
@@ -693,7 +698,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
}
putback(istr, c);
LLSD child;
- S32 count = doParse(istr, child);
+ S32 count = doParse(istr, child, max_depth);
if(count > 0)
{
// There must be a value for every key, thus
@@ -718,7 +723,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map) const
return parse_count;
}
-S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const
+S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
// array: [ object, object, object ]
array = LLSD::emptyArray();
@@ -737,7 +742,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array) const
continue;
}
putback(istr, c);
- S32 count = doParse(istr, child);
+ S32 count = doParse(istr, child, max_depth);
if(PARSE_FAILURE == count)
{
return PARSE_FAILURE;
@@ -869,7 +874,7 @@ LLSDBinaryParser::~LLSDBinaryParser()
}
// virtual
-S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
+S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
{
/**
* Undefined: '!'<br>
@@ -893,12 +898,16 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
{
return 0;
}
+ if (max_depth == 0)
+ {
+ return PARSE_FAILURE;
+ }
S32 parse_count = 1;
switch(c)
{
case '{':
{
- S32 child_count = parseMap(istr, data);
+ S32 child_count = parseMap(istr, data, max_depth - 1);
if((child_count == PARSE_FAILURE) || data.isUndefined())
{
parse_count = PARSE_FAILURE;
@@ -917,7 +926,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
case '[':
{
- S32 child_count = parseArray(istr, data);
+ S32 child_count = parseArray(istr, data, max_depth - 1);
if((child_count == PARSE_FAILURE) || data.isUndefined())
{
parse_count = PARSE_FAILURE;
@@ -1098,7 +1107,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
return parse_count;
}
-S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
+S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
{
map = LLSD::emptyMap();
U32 value_nbo = 0;
@@ -1128,7 +1137,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
}
}
LLSD child;
- S32 child_count = doParse(istr, child);
+ S32 child_count = doParse(istr, child, max_depth);
if(child_count > 0)
{
// There must be a value for every key, thus child_count
@@ -1152,7 +1161,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const
return parse_count;
}
-S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const
+S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
array = LLSD::emptyArray();
U32 value_nbo = 0;
@@ -1168,7 +1177,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const
while((c != ']') && (count < size) && istr.good())
{
LLSD child;
- S32 child_count = doParse(istr, child);
+ S32 child_count = doParse(istr, child, max_depth);
if(PARSE_FAILURE == child_count)
{
return PARSE_FAILURE;
@@ -2238,7 +2247,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
return ZR_MEM_ERROR;
}
- if (!LLSDSerialize::fromBinary(data, istr, cur_size))
+ if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH))
{
free(result);
return ZR_PARSE_ERROR;
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 9f58d44fe7..8165410e80 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -77,7 +77,7 @@ public:
* @return Returns the number of LLSD objects parsed into
* data. Returns PARSE_FAILURE (-1) on parse failure.
*/
- S32 parse(std::istream& istr, LLSD& data, S32 max_bytes);
+ S32 parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth = -1);
/** Like parse(), but uses a different call (istream.getline()) to read by lines
* This API is better suited for XML, where the parse cannot tell
@@ -103,10 +103,12 @@ protected:
* caller.
* @param istr The input stream.
* @param data[out] The newly parse structured data.
+ * @param max_depth Max depth parser will check before exiting
+ * with parse error, -1 - unlimited.
* @return Returns the number of LLSD objects parsed into
* data. Returns PARSE_FAILURE (-1) on parse failure.
*/
- virtual S32 doParse(std::istream& istr, LLSD& data) const = 0;
+ virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0;
/**
* @brief Virtual default function for resetting the parser
@@ -241,10 +243,12 @@ protected:
* caller.
* @param istr The input stream.
* @param data[out] The newly parse structured data. Undefined on failure.
+ * @param max_depth Max depth parser will check before exiting
+ * with parse error, -1 - unlimited.
* @return Returns the number of LLSD objects parsed into
* data. Returns PARSE_FAILURE (-1) on parse failure.
*/
- virtual S32 doParse(std::istream& istr, LLSD& data) const;
+ virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
private:
/**
@@ -252,18 +256,20 @@ private:
*
* @param istr The input stream.
* @param map The map to add the parsed data.
+ * @param max_depth Allowed parsing depth.
* @return Returns The number of LLSD objects parsed into data.
*/
- S32 parseMap(std::istream& istr, LLSD& map) const;
+ S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const;
/**
* @brief Parse an array from the istream.
*
* @param istr The input stream.
* @param array The array to append the parsed data.
+ * @param max_depth Allowed parsing depth.
* @return Returns The number of LLSD objects parsed into data.
*/
- S32 parseArray(std::istream& istr, LLSD& array) const;
+ S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const;
/**
* @brief Parse a string from the istream and assign it to data.
@@ -314,10 +320,12 @@ protected:
* caller.
* @param istr The input stream.
* @param data[out] The newly parse structured data.
+ * @param max_depth Max depth parser will check before exiting
+ * with parse error, -1 - unlimited.
* @return Returns the number of LLSD objects parsed into
* data. Returns PARSE_FAILURE (-1) on parse failure.
*/
- virtual S32 doParse(std::istream& istr, LLSD& data) const;
+ virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
/**
* @brief Virtual default function for resetting the parser
@@ -362,10 +370,12 @@ protected:
* caller.
* @param istr The input stream.
* @param data[out] The newly parse structured data.
+ * @param max_depth Max depth parser will check before exiting
+ * with parse error, -1 - unlimited.
* @return Returns the number of LLSD objects parsed into
* data. Returns -1 on parse failure.
*/
- virtual S32 doParse(std::istream& istr, LLSD& data) const;
+ virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const;
private:
/**
@@ -373,18 +383,20 @@ private:
*
* @param istr The input stream.
* @param map The map to add the parsed data.
+ * @param max_depth Allowed parsing depth.
* @return Returns The number of LLSD objects parsed into data.
*/
- S32 parseMap(std::istream& istr, LLSD& map) const;
+ S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const;
/**
* @brief Parse an array from the istream.
*
* @param istr The input stream.
* @param array The array to append the parsed data.
+ * @param max_depth Allowed parsing depth.
* @return Returns The number of LLSD objects parsed into data.
*/
- S32 parseArray(std::istream& istr, LLSD& array) const;
+ S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const;
/**
* @brief Parse a string from the istream and assign it to data.
@@ -800,16 +812,16 @@ public:
LLPointer<LLSDBinaryFormatter> f = new LLSDBinaryFormatter;
return f->format(sd, str, LLSDFormatter::OPTIONS_NONE);
}
- static S32 fromBinary(LLSD& sd, std::istream& str, S32 max_bytes)
+ static S32 fromBinary(LLSD& sd, std::istream& str, S32 max_bytes, S32 max_depth = -1)
{
LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser;
- return p->parse(str, sd, max_bytes);
+ return p->parse(str, sd, max_bytes, max_depth);
}
- static LLSD fromBinary(std::istream& str, S32 max_bytes)
+ static LLSD fromBinary(std::istream& str, S32 max_bytes, S32 max_depth = -1)
{
LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser;
LLSD sd;
- (void)p->parse(str, sd, max_bytes);
+ (void)p->parse(str, sd, max_bytes, max_depth);
return sd;
}
};
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 8d72a1c329..6d0fe862b9 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -917,7 +917,7 @@ void LLSDXMLParser::parsePart(const char *buf, int len)
}
// virtual
-S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
+S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
{
#ifdef XML_PARSER_PERFORMANCE_TESTS
XML_Timer timer( &parseTime );