This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git

commit 3b6b6a23c6d6dc3d7d285a29e4406878cbe9bf6f
Author: Szymon Janc <[email protected]>
AuthorDate: Wed Oct 7 15:56:36 2026 +0200

    cborattr: Limit nesting depth when skipping values
    
    Unknown or mismatched values were skipped with cbor_value_advance() which
    recursively walks nested containers with a limit much bigger than what
    is suitable for embedded task stacks.
    
    This adds a helper that walks containers iteratively with a configurable
    depth limit (CBORATTR_MAX_NESTING) and uses it for all skipped values.
    Array decoding now also stops when an element cannot be skipped.
    
    Assisted-by: Claude:claude-opus-5-5
---
 cborattr/src/cborattr.c | 79 +++++++++++++++++++++++++++++++++++++++++++++----
 cborattr/syscfg.yml     |  5 ++++
 2 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/cborattr/src/cborattr.c b/cborattr/src/cborattr.c
index a2e08df..0a9ef83 100644
--- a/cborattr/src/cborattr.c
+++ b/cborattr/src/cborattr.c
@@ -36,6 +36,11 @@
 #include "tinycbor/cbor_mbuf_writer.h"
 #include "os/os_mbuf.h"
 #define CBORATTR_MAX_SIZE MYNEWT_VAL(CBORATTR_MAX_SIZE)
+#define CBORATTR_MAX_NESTING MYNEWT_VAL(CBORATTR_MAX_NESTING)
+#endif
+
+#ifndef CBORATTR_MAX_NESTING
+#define CBORATTR_MAX_NESTING 16
 #endif
 
 /* this maps a CborType to a matching CborAtter Type. The mapping is not
@@ -104,6 +109,59 @@ valid_attr_type(CborType ct, CborAttrType at)
     return 0;
 }
 
+/*
+ * Advances past the value at *it. Unlike cbor_value_advance(), containers are
+ * walked iteratively with a fixed size stack, and values nested deeper than
+ * CBORATTR_MAX_NESTING are rejected with CborErrorNestingTooDeep.
+ */
+static CborError
+cborattr_advance(CborValue *it)
+{
+    CborValue stack[CBORATTR_MAX_NESTING];
+    CborValue *cur;
+    CborValue *parent;
+    CborError err;
+    int depth;
+
+    if (!cbor_value_is_container(it)) {
+        return cbor_value_advance(it);
+    }
+
+    err = cbor_value_enter_container(it, &stack[0]);
+    if (err) {
+        return err;
+    }
+    depth = 1;
+
+    while (depth > 0) {
+        cur = &stack[depth - 1];
+        if (cbor_value_at_end(cur)) {
+            parent = (depth == 1) ? it : &stack[depth - 2];
+            err = cbor_value_leave_container(parent, cur);
+            if (err) {
+                return err;
+            }
+            depth--;
+        } else if (cbor_value_is_container(cur)) {
+            if (depth >= CBORATTR_MAX_NESTING) {
+                return CborErrorNestingTooDeep;
+            }
+            err = cbor_value_enter_container(cur, &stack[depth]);
+            if (err) {
+                return err;
+            }
+            depth++;
+        } else {
+            err = cbor_value_advance(cur);
+            if (err) {
+                return err;
+            }
+        }
+    }
+
+    return CborNoError;
+}
+
 /* this function find the pointer to the memory location to
   * write or read and attribute from the cbor_attr_r structure */
 static char *
@@ -227,7 +285,7 @@ cbor_internal_read_object(CborValue *root_value,
 
             /* at least get the type of the next value so we can match the
              * attribute name and type for a perfect match */
-            err |= cbor_value_advance(&cur_value);
+            err |= cborattr_advance(&cur_value);
             if (cbor_value_is_valid(&cur_value)) {
                 type = cbor_value_get_type(&cur_value);
             } else {
@@ -306,7 +364,7 @@ cbor_internal_read_object(CborValue *root_value,
                 err |= CborErrorIllegalType;
             }
         }
-        err = cbor_value_advance(&cur_value);
+        err = cborattr_advance(&cur_value);
     }
     if (!err) {
         /* that should be it for this container */
@@ -319,6 +377,7 @@ int
 cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr)
 {
     CborError err = 0;
+    CborError adv_err = CborNoError;
     struct CborValue elem;
     int off, arrcount;
     size_t len;
@@ -372,7 +431,12 @@ cbor_read_array(struct CborValue *value, const struct 
cbor_array_t *arr)
         }
         arrcount++;
         if (arr->element_type != CborAttrStructObjectType) {
-            err |= cbor_value_advance(&elem);
+            adv_err = cborattr_advance(&elem);
+            err |= adv_err;
+            if (adv_err) {
+                /* elem was not advanced, no further progress is possible */
+                break;
+            }
         }
         if (!cbor_value_is_valid(&elem)) {
             break;
@@ -381,9 +445,14 @@ cbor_read_array(struct CborValue *value, const struct 
cbor_array_t *arr)
     if (arr->count) {
         *arr->count = arrcount;
     }
-    while (!cbor_value_at_end(&elem)) {
+    while (!adv_err && !cbor_value_at_end(&elem)) {
         err |= CborErrorDataTooLarge;
-        cbor_value_advance(&elem);
+        adv_err = cborattr_advance(&elem);
+        err |= adv_err;
+    }
+    if (adv_err) {
+        /* elem is not at the end of container so it cannot be left */
+        return err;
     }
     err |= cbor_value_leave_container(value, &elem);
     return err;
diff --git a/cborattr/syscfg.yml b/cborattr/syscfg.yml
index cc93c26..793ff75 100644
--- a/cborattr/syscfg.yml
+++ b/cborattr/syscfg.yml
@@ -22,3 +22,8 @@ syscfg.defs:
     CBORATTR_MAX_SIZE:
         description: 'The maximum size of a CBOR attribute during decoding'
         value: 512
+    CBORATTR_MAX_NESTING:
+        description: >
+            Maximum nesting depth of CBOR containers that can be skipped
+            while decoding. Values nested deeper are rejected.
+        value: 16

Reply via email to