mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-10-15 18:27:12 +00:00
cjson: patch CVE-2026-87933
Details: https://nvd.nist.gov/vuln/detail/cve-2026-87933 Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
1 parent
2cbb8e4840
commit
2b3f5cbbd8
2 files changed
+111
No files matched your search
@@ -0,0 +1,110 @@
|
||||
From a1b370963c98e1374e5538e97841f9d476a8932e Mon Sep 17 00:00:00 2001
|
||||
From: lilu5458 <lilu@kylinos.cn>
|
||||
Date: Wed, 16 Sep 2026 09:55:35 +0800
|
||||
Subject: [PATCH] Fix: heap-use-after-free in merge_patch when patch is subtree
|
||||
of target (#1065)
|
||||
|
||||
When cJSONUtils_MergePatch(target, patch) is called with a non-object
|
||||
patch (scalar, array, or NULL) that happens to be a subtree of target,
|
||||
merge_patch() called cJSON_Delete(target) first, which freed the patch
|
||||
memory, and then cJSON_Duplicate(patch, 1) read the already-freed memory,
|
||||
triggering a heap-use-after-free (detected by AddressSanitizer at
|
||||
cJSON_Duplicate_rec, cJSON.c:2808).
|
||||
|
||||
Fix: duplicate the patch first into a local variable, then delete the
|
||||
target, then return the duplicate. This matches the Option B approach
|
||||
proposed in issue #1060.
|
||||
|
||||
Verified locally:
|
||||
- Reproduced the UAF with a minimal PoC under ASan before the fix.
|
||||
- After the fix the PoC runs cleanly (exit 0, correct result [1,2,3]).
|
||||
- Added a regression unit test
|
||||
(merge_patch_should_not_read_freed_memory_when_patch_is_subtree).
|
||||
- Full ctest suite passes (22/22 tests).
|
||||
|
||||
Fixes #1060
|
||||
|
||||
Signed-off-by: lilu <lilu@kylinos.cn>
|
||||
(cherry picked from commit 6d9f2443ab071f86e5d9b43025a40929ec41c46c)
|
||||
|
||||
CVE: CVE-2026-87933
|
||||
Upstream-Status: Backport [https://github.com/DaveGamble/cJSON/commit/6d9f2443ab071f86e5d9b43025a40929ec41c46c]
|
||||
|
||||
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
---
|
||||
cJSON_Utils.c | 8 ++++++--
|
||||
tests/old_utils_tests.c | 34 ++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 40 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/cJSON_Utils.c b/cJSON_Utils.c
|
||||
index 8fa24f8..6f41875 100644
|
||||
--- a/cJSON_Utils.c
|
||||
+++ b/cJSON_Utils.c
|
||||
@@ -1324,9 +1324,13 @@ static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_
|
||||
|
||||
if (!cJSON_IsObject(patch))
|
||||
{
|
||||
- /* scalar value, array or NULL, just duplicate */
|
||||
+ /* scalar value, array or NULL, just duplicate.
|
||||
+ * Duplicate the patch first in case it is a subtree of target,
|
||||
+ * otherwise cJSON_Delete(target) would free the patch memory
|
||||
+ * and the subsequent cJSON_Duplicate would read freed memory. */
|
||||
+ cJSON *duplicate = cJSON_Duplicate(patch, 1);
|
||||
cJSON_Delete(target);
|
||||
- return cJSON_Duplicate(patch, 1);
|
||||
+ return duplicate;
|
||||
}
|
||||
|
||||
if (!cJSON_IsObject(target))
|
||||
diff --git a/tests/old_utils_tests.c b/tests/old_utils_tests.c
|
||||
index 690dbb5..bdc7393 100644
|
||||
--- a/tests/old_utils_tests.c
|
||||
+++ b/tests/old_utils_tests.c
|
||||
@@ -189,6 +189,39 @@ static void merge_tests(void)
|
||||
}
|
||||
}
|
||||
|
||||
+static void merge_patch_should_not_read_freed_memory_when_patch_is_subtree(void)
|
||||
+{
|
||||
+ /* When patch is a subtree of target, merge_patch must duplicate the patch
|
||||
+ * before deleting target. Otherwise cJSON_Delete(target) frees the patch
|
||||
+ * memory and the subsequent cJSON_Duplicate reads freed memory (UAF).
|
||||
+ * See CVE candidate: heap-use-after-free in merge_patch (cJSON_Utils.c). */
|
||||
+ cJSON *target = cJSON_Parse("{\"a\":[1,2,3]}");
|
||||
+ cJSON *patch = cJSON_GetObjectItem(target, "a");
|
||||
+ cJSON *result = NULL;
|
||||
+ cJSON *first = NULL;
|
||||
+ cJSON *second = NULL;
|
||||
+ cJSON *third = NULL;
|
||||
+
|
||||
+ TEST_ASSERT_NOT_NULL(target);
|
||||
+ TEST_ASSERT_NOT_NULL(patch);
|
||||
+
|
||||
+ /* patch (array [1,2,3]) is a subtree of target. This used to trigger
|
||||
+ * heap-use-after-free under AddressSanitizer before the fix. */
|
||||
+ result = cJSONUtils_MergePatch(target, patch);
|
||||
+ TEST_ASSERT_NOT_NULL(result);
|
||||
+ TEST_ASSERT_TRUE(cJSON_IsArray(result));
|
||||
+ TEST_ASSERT_EQUAL_INT(3, cJSON_GetArraySize(result));
|
||||
+
|
||||
+ first = cJSON_GetArrayItem(result, 0);
|
||||
+ second = cJSON_GetArrayItem(result, 1);
|
||||
+ third = cJSON_GetArrayItem(result, 2);
|
||||
+ TEST_ASSERT_EQUAL_INT(1, first->valueint);
|
||||
+ TEST_ASSERT_EQUAL_INT(2, second->valueint);
|
||||
+ TEST_ASSERT_EQUAL_INT(3, third->valueint);
|
||||
+
|
||||
+ cJSON_Delete(result);
|
||||
+}
|
||||
+
|
||||
static void generate_merge_tests(void)
|
||||
{
|
||||
size_t i = 0;
|
||||
@@ -219,6 +252,7 @@ int main(void)
|
||||
RUN_TEST(misc_tests);
|
||||
RUN_TEST(sort_tests);
|
||||
RUN_TEST(merge_tests);
|
||||
+ RUN_TEST(merge_patch_should_not_read_freed_memory_when_patch_is_subtree);
|
||||
RUN_TEST(generate_merge_tests);
|
||||
|
||||
return UNITY_END();
|
||||
@@ -7,6 +7,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=218947f77e8cb8e2fa02918dc41c50d0"
|
||||
SRC_URI = "git://github.com/DaveGamble/cJSON.git;branch=master;protocol=https \
|
||||
file://run-ptest \
|
||||
file://0001-allow-build-with-cmake-4.patch \
|
||||
file://CVE-2026-87933.patch \
|
||||
"
|
||||
SRCREV = "c859b25da02955fef659d658b8f324b5cde87be3"
|
||||
|
||||
|
||||
Reference in new issue
Block a user