Parser: validate that maps have both key and value items
If a map end (Break byte) occurs before we've read the concrete item for
the value, then the map is invalid.
Fixes #167
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
diff --git a/src/cborparser.c b/src/cborparser.c
index 45de222..35cd78d 100644
--- a/src/cborparser.c
+++ b/src/cborparser.c
@@ -214,6 +214,10 @@
static CborError preparse_value(CborValue *it)
{
+ enum {
+ /* flags to keep */
+ FlagsToKeep = CborIteratorFlag_ContainerIsMap | CborIteratorFlag_NextIsMapKey
+ };
const CborParser *parser = it->parser;
it->type = CborInvalidType;
@@ -224,7 +228,7 @@
uint8_t descriptor = *it->ptr;
uint8_t type = descriptor & MajorTypeMask;
it->type = type;
- it->flags = 0;
+ it->flags &= FlagsToKeep;
it->extra = (descriptor &= SmallValueMask);
if (descriptor > Value64Bit) {
@@ -302,6 +306,11 @@
{
if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
/* end of map or array */
+ if ((it->flags & CborIteratorFlag_ContainerIsMap && it->flags & CborIteratorFlag_NextIsMapKey)
+ || it->type == CborTagType) {
+ /* but we weren't expecting it! */
+ return CborErrorUnexpectedBreak;
+ }
++it->ptr;
it->type = CborInvalidType;
it->remaining = 0;
@@ -313,13 +322,20 @@
static CborError preparse_next_value(CborValue *it)
{
+ /* tags don't count towards item totals or whether we've successfully
+ * read a map's key or value */
+ bool itemCounts = it->type != CborTagType;
+
if (it->remaining != UINT32_MAX) {
- /* don't decrement the item count if the current item is tag: they don't count */
- if (it->type != CborTagType && --it->remaining == 0) {
+ if (itemCounts && --it->remaining == 0) {
it->type = CborInvalidType;
return CborNoError;
}
}
+ if (itemCounts) {
+ /* toggle the flag indicating whether this was a map key */
+ it->flags ^= CborIteratorFlag_NextIsMapKey;
+ }
return preparse_next_value_nodecrement(it);
}
@@ -381,6 +397,7 @@
it->parser = parser;
it->ptr = buffer;
it->remaining = 1; /* there's one type altogether, usually an array or map */
+ it->flags = 0;
return preparse_value(it);
}
@@ -586,6 +603,7 @@
*/
CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
{
+ cbor_static_assert(CborIteratorFlag_ContainerIsMap == (CborMapType & ~CborArrayType));
cbor_assert(cbor_value_is_container(it));
*recursed = *it;
@@ -618,6 +636,7 @@
return CborNoError;
}
}
+ recursed->flags = (recursed->type & CborIteratorFlag_ContainerIsMap);
return preparse_next_value_nodecrement(recursed);
}