[cJSON_Utils] decode_pointer_inplace off-by-one causes incorrect decoding of "~1" (JSON Pointer)
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 55/100
Hướng nghiên cứu
Bắt đầu trong cJSON_Utils.c, tại decode_pointer_inplace(), khoảng dòng 370, và so sánh cách xử lý 1 của nó với bản tái hiện được cung cấp. Biên dịch và chạy poc_decode_pointer.c bằng lệnh gcc được ghi trong tài liệu, sau đó xác minh rằng việc áp dụng /a1b cập nhật khóa "a/b" hiện có thành 2 mà không tạo "a~/".
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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
- Ngôn ngữ chính
- C
- Star
- 13k
- Fork
- 3.5k
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của DaveGamble/cJSON
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
DaveGamble/cJSON#1094 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
DaveGamble/cJSON#1093 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
DaveGamble/cJSON#1082 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
DaveGamble/cJSON#1081 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
DaveGamble/cJSON#1074 ·
Tất cả issue của DaveGamble/cJSON
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
darktable-org/darktable#22455 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:ci kind:gate-defect
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
InauguralSystems/EigenScript#1448 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
BasedHardware/omi#20084 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
raspberrypi/pico-sdk#3225 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100