diff options
Diffstat (limited to 'indra/llcommon/llsdserialize.cpp')
-rw-r--r-- | indra/llcommon/llsdserialize.cpp | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index a487322d17..c3fb4ebc2c 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"); @@ -327,11 +328,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); } @@ -413,7 +414,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 ] @@ -428,6 +429,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. @@ -444,7 +449,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; @@ -463,7 +468,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; @@ -668,7 +673,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(); @@ -703,7 +708,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 @@ -728,7 +733,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(); @@ -747,7 +752,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; @@ -879,7 +884,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> @@ -903,12 +908,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; @@ -927,7 +936,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; @@ -1108,7 +1117,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; @@ -1138,7 +1147,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 @@ -1162,7 +1171,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; @@ -1178,7 +1187,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; @@ -2248,7 +2257,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; @@ -2263,13 +2272,24 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, //and trailers are different for the formats. U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size ) { + if (size == 0) + { + LL_WARNS() << "No data to unzip." << LL_ENDL; + return NULL; + } + U8* result = NULL; U32 cur_size = 0; z_stream strm; const U32 CHUNK = 0x4000; - U8 *in = new U8[size]; + U8 *in = new(std::nothrow) U8[size]; + if (in == NULL) + { + LL_WARNS() << "Memory allocation failure." << LL_ENDL; + return NULL; + } is.read((char*) in, size); U8 out[CHUNK]; @@ -2313,7 +2333,10 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 U8* new_result = (U8*) realloc(result, cur_size + have); if (new_result == NULL) { - LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size + << " bytes; requested " << cur_size + have + << " bytes; total syze: ." << size << " bytes." + << LL_ENDL; inflateEnd(&strm); if (result) { |