[cJSON_Utils] decode_pointer_inplace off-by-one causes incorrect decoding of "~1" (JSON Pointer)
维护者通常 12 天内回复
还没有人认领这个 Issue。
- #998 来自 @某人 —— 已关闭,未合并
评估
调研方向
从 cJSON_Utils.c 的 decode_pointer_inplace() 开始,查看第 370 行附近的代码,并将其对 1 的处理与提供的复现进行比较。使用文档中记录的 gcc 命令构建并运行 poc_decode_pointer.c,然后验证应用 /a1b 会将现有的 "a/b" 键更新为 2,而不会创建 "a~/"。
由索引模型根据 Issue 内容生成。
描述
Description
decode_pointer_inplace() (used by JSON Patch helpers) writes decoded slashes to decoded_string[1] instead of the current output slot. As a result, pointers containing ~1 are decoded incorrectly during patch application—values are written under mutated object keys like "a~/" instead of the intended "a/b". The function reports success even though it corrupted the object.
Reproduction steps
- Clone
cJSON(currentmaster). - Drop the PoC below into
poc_decode_pointer.cat repo root. - Build and run:
cd cJSON gcc -std=c99 -Wall -Wextra poc_decode_pointer.c cJSON.c cJSON_Utils.c -o poc_decode_pointer ./poc_decode_pointer
PoC source
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
#include "cJSON_Utils.h"
static void print_json(const char *label, cJSON *item)
{
char *rendered = cJSON_PrintUnformatted(item);
if (rendered == NULL)
{
fprintf(stderr, "%s: <print error>\n", label);
return;
}
printf("%s: %s\n", label, rendered);
cJSON_free(rendered);
}
int main(void)
{
const char *document_text = "{\"a/b\":1}";
const char *patch_text = "[{\"op\":\"add\",\"path\":\"/a~1b\",\"value\":2}]";
cJSON *document = NULL;
cJSON *patches = NULL;
cJSON *value = NULL;
int status = 0;
document = cJSON_Parse(document_text);
patches = cJSON_Parse(patch_text);
if ((document == NULL) || (patches == NULL))
{
fprintf(stderr, "failed to parse JSON input\n");
goto cleanup;
}
print_json("Original document", document);
print_json("Patch", patches);
status = cJSONUtils_ApplyPatches(document, patches);
printf("cJSONUtils_ApplyPatches returned %d\n", status);
print_json("Document after patch", document);
value = cJSON_GetObjectItemCaseSensitive(document, "a/b");
if (value != NULL)
{
printf("a/b = %d\n", value->valueint);
}
else
{
printf("a/b key is missing!\n");
}
value = cJSON_GetObjectItemCaseSensitive(document, "a~/");
if (value != NULL)
{
printf("Corrupted key a~/ = %d\n", value->valueint);
}
cleanup:
if (document != NULL)
{
cJSON_Delete(document);
}
if (patches != NULL)
{
cJSON_Delete(patches);
}
return status;
}
PoC Output
zc@docker:~/cJSON$ ./poc_decode_pointer
Original document: {"a/b":1}
Patch: [{"op":"add","path":"/a~1b","value":2}]
cJSONUtils_ApplyPatches returned 0
Document after patch: {"a/b":1,"a~/":2}
a/b = 1
Corrupted key a~/ = 2
Expected vs. actual results
- Expected: Applying the patch that targets
/a~1bupdates key"a/b"to 2. - Actual:
cJSONUtils_ApplyPatchesreturns success but leaves"a/b"unchanged and inserts a new key"a~/"with value 2, proving the decoded pointer got corrupted.
Suggested fix
In decode_pointer_inplace() (around line 370), write the decoded slash to decoded_string[0] and ensure the output pointer only advances once per decoded character:
diff --git a/cJSON_Utils.c b/cJSON_Utils.c
index 8fa24f8..8a3d881 100644
--- a/cJSON_Utils.c
+++ b/cJSON_Utils.c
@@ -374,7 +374,7 @@ static void decode_pointer_inplace(unsigned char
*string)
}
else if (string[1] == '1')
{
- decoded_string[1] = '/';
+ decoded_string[0] = '/';
}
else
{
@@ -383,7 +383,10 @@ static void decode_pointer_inplace(unsigned char
*string)
}
string++;
+ continue;
}
+
+ decoded_string[0] = string[0];
}
decoded_string[0] = '\0';
This change keeps the decoded pointer aligned with the output buffer so /a~1b resolves to "a/b" during JSON Patch operations.
Output after fix
zc@docker:~/cJSON$ ./poc_decode_pointer
Original document: {"a/b":1}
Patch: [{"op":"add","path":"/a~1b","value":2}]
cJSONUtils_ApplyPatches returned 0
Document after patch: {"a/b":2}
a/b = 2
- 主要语言
- C
- 星标
- 13.1k
- 派生
- 3.6k
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
DaveGamble/cJSON 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 68/100
DaveGamble/cJSON#1106 ·
维护者通常 12 天内回复
-
Undefined-Behavior in function cJSON_SetNumberHelper可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 70/100
DaveGamble/cJSON#1100 · 1 个 reaction ·
维护者通常 12 天内回复
-
CMake config files contain absolute install paths可能已有人在做 @akashdeshmukh-git 于 5 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 86/100
DaveGamble/cJSON#1094 · 9 条评论 · 1 个 reaction ·
维护者通常 12 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
DaveGamble/cJSON#1093 ·
维护者通常 12 天内回复
-
Use-after-free in cJSONUtils_ApplyPatches when a patch removes the patch array可能已有人在做 @iliasabk 于 40 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 82/100
DaveGamble/cJSON#1082 ·
维护者通常 12 天内回复
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
zephyrproject-rtos/zephyr#123881 ·
维护者通常 2 天内回复
-
难度 1/5 1 小时以内 新手友好度 65/100
ly05010419/MacNativeGames#1252 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
维护者通常 2 天内回复
-
Component - Build
难度 2/5 1-3 小时 新手友好度 75/100
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 68/100
HarbourMasters/Lighthouse#655 ·
维护者通常 1 天内回复