]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
Fix: try to make json_pointer_set_with_array_cb a public api
authorlone <lonechan314@qq.com>
Mon, 26 Jan 2026 09:33:00 +0000 (17:33 +0800)
committerlone <lonechan314@qq.com>
Mon, 26 Jan 2026 09:33:00 +0000 (17:33 +0800)
make json_pointer_set_with_array_cb a public api, along with a function with wrapped callback

Signed-off-by: lone <lonechan314@qq.com>
json_pointer.c
json_pointer.h

index 5a3a7efa05060981050e8cd2a1fa1be7d044e8c9..edaabca3a6686320d49aea97e5410b35ba2f86d5 100644 (file)
@@ -423,3 +423,39 @@ out:
        free(path_copy);
        return rc;
 }
+
+int json_pointer_set_with_limit_index(struct json_object **obj, const char *path,
+                                    struct json_object *value, size_t limit_index)
+{
+       // -1 means no limits
+    if (limit_index == (size_t)-1)
+    {
+        return json_pointer_set_with_array_cb(obj, path, value, json_object_array_put_idx_cb, NULL);
+    }
+    return json_pointer_set_with_array_cb(obj, path, value,
+                      json_object_array_put_idx_with_limit_cb, &limit_index);
+}
+
+/* safe callback for array index limit */
+int json_object_array_put_idx_with_limit_cb(struct json_object *jso, size_t idx,
+                                       struct json_object *jso_new, void *priv)
+{
+    // use priv as a size_t pointer to pass in the maximum allowed index
+       if (!priv)
+       {
+               errno = EINVAL;
+               return -1;
+       }
+    size_t max_idx = *(size_t*)priv;
+
+    // Check against a maximum to prevent excessive memory allocations.
+       // An extremely large index, even if it doesn't overflow size_t,
+       // will cause a huge memory allocation request via realloc,
+       // leading to an OOM.
+       if (idx > max_idx)
+    {
+        errno = EINVAL;
+        return -1;
+    }
+    return json_object_array_put_idx(jso, idx, jso_new);
+}
index a44a0f9d245638cb0341640ac2e4557050719a01..d96d624541be6ea782917e4f8556422adca400b8 100644 (file)
 extern "C" {
 #endif
 
-/**
- * Maximum array index for JSON Pointer, preventing excessive memory allocations.
- * The default value is 10,000,000.
- */
-#ifndef JSON_C_POINTER_MAX_ARRAY_IDX
-#define JSON_C_POINTER_MAX_ARRAY_IDX 10000000
-#endif
-
 /**
  * Retrieves a JSON sub-object from inside another JSON object
  * using the JSON pointer notation as defined in RFC 6901
@@ -89,6 +81,10 @@ JSON_EXPORT int json_pointer_getf(struct json_object *obj, struct json_object **
  * That also implies that 'json_pointer_set()' does not do any refcount incrementing.
  * (Just that single decrement that was mentioned above).
  *
+ * @warning This function is vulnerable to an OOM.
+ *          To prevent this, use the safer variant 'json_pointer_set_with_limit_index()'
+ *          or the flexible 'json_pointer_set_with_array_cb()' with a custom callback.
+ *
  * @param obj the json_object instance/tree to which to add a sub-object
  * @param path a (RFC6901) string notation for the sub-object to set in the tree
  * @param value object to set at path
@@ -118,6 +114,65 @@ JSON_EXPORT int json_pointer_set(struct json_object **obj, const char *path,
 JSON_EXPORT int json_pointer_setf(struct json_object **obj, struct json_object *value,
                                   const char *path_fmt, ...);
 
+/**
+ * A convenient and safe variant of 'json_pointer_set()' that prevents excessive memory allocations
+ * by enforcing a limit on array indices.
+ *
+ * @param obj the json_object instance/tree to which to add a sub-object
+ * @param path a (RFC6901) string notation for the sub-object to set in the tree
+ * @param value object to set at path
+ * @param limit_index The maximum allowed value for an array index. If a path
+ *                    contains an index larger than this, the function will fail
+ *                    with errno set to EINVAL. A value of -1 can be used to specify
+ *                    no limit, reverting to the original behavior
+ *
+ * @return negative if an error (or not found), or 0 if succeeded
+ */
+JSON_EXPORT int json_pointer_set_with_limit_index(struct json_object **obj, const char *path,
+                                                struct json_object *value, size_t limit_index);
+
+/**
+ * Callback function type.
+ */
+typedef int(*json_pointer_array_set_cb)(json_object *parent, size_t idx,
+                                        json_object *value, void *priv);
+
+/**
+ * Variant of 'json_pointer_set()' that allows specifying a custom callback
+ *
+ * @param obj the json_object instance/tree to which to add a sub-object
+ * @param path a (RFC6901) string notation for the sub-object to set in the tree
+ * @param value object to set at path
+ * @param array_set_cb A custom callback function to handle setting the element
+ *                     within an array
+ * @param priv A private pointer passed through to the array_set_cb callback,
+ *             for user-defined context
+ *
+ * @return negative if an error (or not found), or 0 if succeeded
+ */
+JSON_EXPORT int json_pointer_set_with_array_cb(struct json_object **obj, const char *path,
+                                   struct json_object *value,
+                                   json_pointer_array_set_cb array_set_cb, void *priv);
+
+/**
+ * A secure callback for 'json_pointer_set_with_array_cb()' that enforces a
+ * maximum array index.
+ *
+ * This function can be used as the 'array_set_cb' argument to prevent OOM.
+ * It expects the 'priv' argument to be a valid pointer to a 'size_t' variable
+ * that holds the maximum allowed index.
+ *
+ * @param jso the parent json_object array.
+ * @param idx the index where the element is to be placed.
+ * @param jso_new the new json_object to place at the index.
+ * @param priv A pointer to a 'size_t' variable specifying the maximum index.
+ *             This pointer must not be NULL.
+ *
+ * @return 0 on success, or a negative value if idx exceeds the limit or 'priv' is NULL.
+ */
+JSON_EXPORT int json_object_array_put_idx_with_limit_cb(struct json_object *jso, size_t idx,
+                                                   struct json_object *jso_new, void *priv);
+
 #ifdef __cplusplus
 }
 #endif