diff options
Diffstat (limited to 'lib/ext/qcbor/src/qcbor_decode.c')
-rw-r--r-- | lib/ext/qcbor/src/qcbor_decode.c | 110 |
1 files changed, 76 insertions, 34 deletions
diff --git a/lib/ext/qcbor/src/qcbor_decode.c b/lib/ext/qcbor/src/qcbor_decode.c index fa89b091da..36a9d116e4 100644 --- a/lib/ext/qcbor/src/qcbor_decode.c +++ b/lib/ext/qcbor/src/qcbor_decode.c @@ -42,6 +42,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when who what, where, why -------- ---- --------------------------------------------------- + 11/07/19 llundblade Fix long long conversion to double compiler warning + 09/07/19 llundblade Fix bug decoding empty arrays and maps + 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR + 07/31/19 llundblade New error code for better end of data handling 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when bAllStrings set 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller @@ -127,28 +131,27 @@ inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting) // Called on every single item except breaks including the opening of a map/array inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting) { - if(!DecodeNesting_IsNested(pNesting)) { - // at top level where there is no tracking - return; - } - - if(DecodeNesting_IsIndefiniteLength(pNesting)) { - // There is no count for indefinite length arrays/maps - return; - } - - // Decrement the count of items in this array/map - pNesting->pCurrent->uCount--; + while(DecodeNesting_IsNested(pNesting)) { + // Not at the top level, so there is decrementing to be done. - // Pop up nesting levels if the counts at the levels are zero - while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) { - pNesting->pCurrent--; if(!DecodeNesting_IsIndefiniteLength(pNesting)) { + // Decrement the current nesting level if it is not indefinite. pNesting->pCurrent->uCount--; } + + if(pNesting->pCurrent->uCount != 0) { + // Did not close out an array or map, so nothing further + break; + } + + // Closed out an array or map so level up + pNesting->pCurrent--; + + // Continue with loop to see if closing out this doesn't close out more } } + // Called on every map/array inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem) { @@ -485,7 +488,7 @@ inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORIt } else { // C can't represent a negative integer in this range - // so it is an error. todo -- test this condition + // so it is an error. nReturn = QCBOR_ERR_INT_OVERFLOW; } } @@ -536,11 +539,7 @@ inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, pDecodedItem->uDataType = uAdditionalInfo; switch(uAdditionalInfo) { - case ADDINFO_RESERVED1: // 28 - case ADDINFO_RESERVED2: // 29 - case ADDINFO_RESERVED3: // 30 - nReturn = QCBOR_ERR_UNSUPPORTED; - break; + // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as it is caught before this is called. case HALF_PREC_FLOAT: pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber); @@ -660,7 +659,7 @@ inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem) /* The epoch formatted date. Turns lots of different forms of encoding date into uniform one */ -static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) +static int DecodeDateEpoch(QCBORItem *pDecodedItem) { // Stack usage: 1 QCBORError nReturn = QCBOR_SUCCESS; @@ -683,13 +682,33 @@ static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) case QCBOR_TYPE_DOUBLE: { + // This comparison needs to be done as a float before + // conversion to an int64_t to be able to detect doubles + // that are too large to fit into an int64_t. A double + // has 52 bits of preceision. An int64_t has 63. Casting + // INT64_MAX to a double actually causes a round up which + // is bad and wrong for the comparison because it will + // allow conversion of doubles that can't fit into a + // uint64_t. To remedy this INT64_MAX - 0x7ff is used as + // the cutoff point as if that rounds up in conversion to + // double it will still be less than INT64_MAX. 0x7ff is + // picked because it has 11 bits set. + // + // INT64_MAX seconds is on the order of 10 billion years, + // and the earth is less than 5 billion years old, so for + // most uses this conversion error won't occur even though + // doubles can go much larger. + // + // Without the 0x7ff there is a ~30 minute range of time + // values 10 billion years in the past and in the future + // where this this code would go wrong. const double d = pDecodedItem->val.dfnum; - if(d > INT64_MAX) { + if(d > (double)(INT64_MAX - 0x7ff)) { nReturn = QCBOR_ERR_DATE_OVERFLOW; goto Done; } - pDecodedItem->val.epochDate.nSeconds = (int64_t) d; // Float to integer conversion happening here. - pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds; + pDecodedItem->val.epochDate.nSeconds = (int64_t)d; + pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds; } break; @@ -735,21 +754,26 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf, uint64_t uNumber; uint8_t uAdditionalInfo; + memset(pDecodedItem, 0, sizeof(QCBORItem)); + nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo); // Error out here if we got into trouble on the type and number. // The code after this will not work if the type and number is not good. - if(nReturn) + if(nReturn) { goto Done; - - memset(pDecodedItem, 0, sizeof(QCBORItem)); + } // At this point the major type and the value are valid. We've got the type and the number that // starts every CBOR data item. switch (uMajorType) { case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1 - nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem); + if(uAdditionalInfo == LEN_IS_INDEFINITE) { + nReturn = QCBOR_ERR_BAD_INT; + } else { + nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem); + } break; case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2 @@ -778,8 +802,12 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf, break; case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags - pDecodedItem->val.uTagV = uNumber; - pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG; + if(uAdditionalInfo == LEN_IS_INDEFINITE) { + nReturn = QCBOR_ERR_BAD_INT; + } else { + pDecodedItem->val.uTagV = uNumber; + pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG; + } break; case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null... @@ -864,7 +892,8 @@ static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDe // Match data type of chunk to type at beginning. // Also catches error of other non-string types that don't belong. - if(StringChunkItem.uDataType != uStringType) { + // Also catches indefinite length strings inside indefinite length strings + if(StringChunkItem.uDataType != uStringType || StringChunkItem.val.string.len == SIZE_MAX) { nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK; break; } @@ -1060,6 +1089,12 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod // All the CBOR parsing work is here and in subordinate calls. QCBORError nReturn; + // Check if there are an + if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && !DecodeNesting_IsNested(&(me->nesting))) { + nReturn = QCBOR_ERR_NO_MORE_ITEMS; + goto Done; + } + nReturn = GetNext_MapEntry(me, pDecodedItem, pTags); if(nReturn) { goto Done; @@ -1084,7 +1119,10 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod // Maps and arrays do count in as items in the map/array that encloses // them so a decrement needs to be done for them too, but that is done // only when all the items in them have been processed, not when they - // are opened. + // are opened with the exception of an empty map or array. + if(pDecodedItem->val.uCount == 0) { + DecodeNesting_DecrementCount(&(me->nesting)); + } } else { // Decrement the count of items in the enclosing map/array // If the count in the enclosing map/array goes to zero, that @@ -1130,6 +1168,10 @@ QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecod pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting)); Done: + if(nReturn != QCBOR_SUCCESS) { + // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE + memset(pDecodedItem, 0, sizeof(QCBORItem)); + } return nReturn; } @@ -1199,7 +1241,7 @@ int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_ */ QCBORError QCBORDecode_Finish(QCBORDecodeContext *me) { - QCBORError nReturn = QCBOR_SUCCESS; + int nReturn = QCBOR_SUCCESS; // Error out if all the maps/arrays are not closed out if(DecodeNesting_IsNested(&(me->nesting))) { |