@@ -27,11 +27,12 @@ #import "OFInvalidFormatException.h" int _OFDataArray_MessagePackValue_reference; -static size_t parseObject(const uint8_t *, size_t, id *); +static size_t parseObject(const uint8_t *buffer, size_t length, id *object, + size_t depthLimit); static uint16_t readUInt16(const uint8_t *buffer) { return ((uint16_t)buffer[0] << 8) | buffer[1]; @@ -52,14 +53,20 @@ ((uint64_t)buffer[4] << 24) | ((uint64_t)buffer[5] << 16) | ((uint64_t)buffer[6] << 8) | buffer[7]; } static size_t -parseArray(const uint8_t *buffer, size_t length, id *object, size_t count) +parseArray(const uint8_t *buffer, size_t length, id *object, size_t count, + size_t depthLimit) { void *pool; size_t pos = 0; + + if (--depthLimit == 0) { + *object = nil; + return 0; + } /* * Don't use capacity! For data and strings, this is safe, as we can * check if we still have enough bytes left. For an array however, we * can't know this, as every child can be more than one byte. @@ -70,11 +77,12 @@ id child; size_t childLength; pool = objc_autoreleasePoolPush(); - childLength = parseObject(buffer + pos, length - pos, &child); + childLength = parseObject(buffer + pos, length - pos, &child, + depthLimit); if (childLength == 0 || child == nil) { objc_autoreleasePoolPop(pool); *object = nil; return 0; @@ -88,14 +96,20 @@ return pos; } static size_t -parseTable(const uint8_t *buffer, size_t length, id *object, size_t count) +parseTable(const uint8_t *buffer, size_t length, id *object, size_t count, + size_t depthLimit) { void *pool; size_t pos = 0; + + if (--depthLimit == 0) { + *object = nil; + return 0; + } /* * Don't use capacity! For data and strings, this is safe, as we can * check if we still have enough bytes left. For a dictionary however, * we can't know this, as every key / value can be more than one byte. @@ -106,20 +120,22 @@ id key, value; size_t keyLength, valueLength; pool = objc_autoreleasePoolPush(); - keyLength = parseObject(buffer + pos, length - pos, &key); + keyLength = parseObject(buffer + pos, length - pos, &key, + depthLimit); if (keyLength == 0 || key == nil) { objc_autoreleasePoolPop(pool); *object = nil; return 0; } pos += keyLength; - valueLength = parseObject(buffer + pos, length - pos, &value); + valueLength = parseObject(buffer + pos, length - pos, &value, + depthLimit); if (valueLength == 0 || value == nil) { objc_autoreleasePoolPop(pool); *object = nil; return 0; @@ -134,11 +150,12 @@ return pos; } static size_t -parseObject(const uint8_t *buffer, size_t length, id *object) +parseObject(const uint8_t *buffer, size_t length, id *object, + size_t depthLimit) { size_t count; int8_t type; OFDataArray *data; @@ -171,16 +188,16 @@ } /* fixarray */ if ((buffer[0] & 0xF0) == 0x90) return parseArray(buffer + 1, length - 1, object, - buffer[0] & 0xF) + 1; + buffer[0] & 0xF, depthLimit) + 1; /* fixmap */ if ((buffer[0] & 0xF0) == 0x80) return parseTable(buffer + 1, length - 1, object, - buffer[0] & 0xF) + 1; + buffer[0] & 0xF, depthLimit) + 1; /* Prefix byte */ switch (*buffer) { /* Unsigned integers */ case 0xCC: /* uint8 */ @@ -425,11 +442,11 @@ } @finally { [data release]; } return 4; - case 0xD6: /* fixtext 4 */ + case 0xD6: /* fixext 4 */ if (length < 6) goto error; type = buffer[1]; @@ -444,11 +461,11 @@ } @finally { [data release]; } return 6; - case 0xD7: /* fixtext 8 */ + case 0xD7: /* fixext 8 */ if (length < 10) goto error; type = buffer[1]; @@ -528,30 +545,30 @@ case 0xDC: /* array 16 */ if (length < 3) goto error; return parseArray(buffer + 3, length - 3, object, - readUInt16(buffer + 1)) + 3; + readUInt16(buffer + 1), depthLimit) + 3; case 0xDD: /* array 32 */ if (length < 5) goto error; return parseArray(buffer + 5, length - 5, object, - readUInt32(buffer + 1)) + 5; + readUInt32(buffer + 1), depthLimit) + 5; /* Maps */ case 0xDE: /* map 16 */ if (length < 3) goto error; return parseTable(buffer + 3, length - 3, object, - readUInt16(buffer + 1)) + 3; + readUInt16(buffer + 1), depthLimit) + 3; case 0xDF: /* map 32 */ if (length < 5) goto error; return parseTable(buffer + 5, length - 5, object, - readUInt32(buffer + 1)) + 5; + readUInt32(buffer + 1), depthLimit) + 5; } error: *object = nil; return 0; @@ -558,15 +575,25 @@ } @implementation OFDataArray (MessagePackValue) - (id)messagePackValue { + return [self messagePackValueWithDepthLimit: 32]; +} + +- (id)messagePackValueWithDepthLimit: (size_t)depthLimit +{ + void *pool = objc_autoreleasePoolPush(); size_t count = [self count]; id object; - if (parseObject([self items], count, &object) != count || + if (parseObject([self items], count, &object, depthLimit) != count || object == nil) @throw [OFInvalidFormatException exception]; + [object retain]; + + objc_autoreleasePoolPop(pool); + return object; } @end