cJSON icon indicating copy to clipboard operation
cJSON copied to clipboard

An infinite loop found in cJSON_DeleteItemFromObjectCaseSensitive

Open PromptFuzz opened this issue 1 year ago • 2 comments

Hi, when fuzzing cJSON, there is a timeout reported by ASAN. There might is an infinite loop bug in cJSON_DeleteItemFromObjectCaseSensitive.

==617073== ERROR: libFuzzer: timeout after 241 seconds
    #0 0x5583f5cf2a41 in __sanitizer_print_stack_trace /work/llvm/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
    #1 0x5583f5c0c808 in fuzzer::PrintStackTrace() /work/llvm/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:210:5
    #2 0x5583f5befcd9 in fuzzer::Fuzzer::AlarmCallback() /work/llvm/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:301:5
    #3 0x7fd7e37c041f  (/lib/x86_64-linux-gnu/libpthread.so.0+0x1441f) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
    #4 0x5583f5c7b995 in __interceptor_strcmp /work/llvm/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:527
    #5 0x5583f5d74174 in get_object_item cjson/src/cjson/cJSON.c:1892:83
    #6 0x5583f5d7809c in cJSON_GetObjectItemCaseSensitive /cjson/src/cjson/cJSON.c:1919:12
    #7 0x5583f5d7809c in cJSON_DetachItemFromObjectCaseSensitive /cjson/src/cjson/cJSON.c:2247:24
    #8 0x5583f5d7809c in cJSON_DeleteItemFromObjectCaseSensitive /cjson/src/cjson/cJSON.c:2259:18

My environment: CentOS 5.4

PoC: poc.tar.gz

PromptFuzz avatar Dec 06 '23 06:12 PromptFuzz

Interesting find. Basically, whats causing the infinite loop here is a circular reference after adding the same item twice.

I boiled the POC down a bit:

cJSON* root = cJSON_CreateObject();
cJSON* item = cJSON_CreateNumber(42);

cJSON_AddItemToObject(root, "item1", item);
cJSON_AddItemToObject(root, "item2", item);  // Circular reference is created here

cJSON_Print(root);                           // This will enter an infinite loop

Specifically, the circular reference is created in suffix_object, which is called with prev and item being equal. (https://github.com/DaveGamble/cJSON/blob/cb8693b058ba302f4829ec6d03f609ac6f848546/cJSON.c#L1928C13-L1928C19)

But aside from this analysis, I'm not sure what the best course of action on this would be.

daschfg avatar Dec 06 '23 23:12 daschfg

Adding the same item to object for more than one time is a broken use of cJSON_AddItemToObject. Simply doing same pointer check in suffix_object will not help much. POC to a similar problem:

    cJSON* root = cJSON_CreateObject();
    cJSON* item1 = cJSON_CreateNumber(42);
    cJSON* item2 = cJSON_CreateNumber(42);

    cJSON_AddItemToObject(root, "item1", item1);
    cJSON_AddItemToObject(root, "item2", item2);
    cJSON_AddItemToObject(root, "item3", item1); // circular reference

    cJSON_Print(root);

To prevent this, we need to check all items in a object/array if the added item already exist when adding a item to a object/array. No doubt this will cause performance problems.

I can't find a elegant enough solution. Ideas?

PeterAlfredLee avatar Dec 16 '23 07:12 PeterAlfredLee