Bug #1197 » IC-DCMTK-0009_REPORT.md
IC-DCMTK-0009: Uninitialized Memory Read in JSMN Token Array
Version: DCMTK master 418274445 (DCMTK-3.7.0+64)
CWE: CWE-908 (Use of Uninitialized Resource)
Description
The reserveTokens() function in dcmdata/libsrc/dcjsonrd.cc:192-206 allocates tokenNum+1 JSMN tokens (the extra one as a sentinel) but only memset-initializes the first tokenNum elements. The sentinel token at position tokenNum has its start, end, and size fields explicitly set, but its type field is left containing heap garbage. A 40-byte malformed JSON input triggers the read.
When malformed JSON (e.g., a missing colon between a DICOM tag key and its value object) causes JSMN to produce fewer valid tokens than expected, the token pointer in parseElement() advances past valid tokens into the sentinel. At dcjsonrd.cc:571, a switch (t->type) reads the uninitialized type field, which is undefined behavior -- UBSan reports "load of value 3200171710, which is not a valid value for type 'jsmntype_t'".
// dcjsonrd.cc:192-206 (reserveTokens)
tokenArray_ = new (std::nothrow) OFJsmnToken[tokenNum+1];
memset(tokenArray_, 0, tokenNum * sizeof(OFJsmnToken));
// ^^^^^^^^ should be (tokenNum+1)
tokenArray_[tokenNum].start = INT_MAX;
tokenArray_[tokenNum].end = INT_MAX;
tokenArray_[tokenNum].size = 0;
// tokenArray_[tokenNum].type is UNINITIALIZED heap garbage!
Reproduction
echo -n '{"00100010"{"vr":"LO","value":["test"]}}' > poc.json
export DCMDICTPATH=/path/to/dcmtk/dcmdata/data/dicom.dic
./bin/json2dcm poc.json /dev/null
Actual output:
$ json2dcm poc.json /dev/null
W: element (0010,0010) has wrong VR (LO), correct is 'PN'
dcjsonrd.cc:571:18: runtime error: load of value 3200171710,
which is not a valid value for type 'jsmntype_t'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
dcjsonrd.cc:571:18
E: not a valid DICOM JSON dataset: element tag must be a JSON string
The UBSan error confirms that at dcjsonrd.cc:571, the code loads a value (3200171710 = 0xBEBDBEBE, an ASan poison pattern) from the token's type field. This is heap garbage from an uninitialized sentinel token. Note: this bug requires UBSan (-fsanitize=undefined) to detect — ASan alone does not flag it because the read is within the allocated token array's memory (the sentinel slot), not out of bounds. The --ignore-errors flag is not required.
Fix
Zero-initialize all token array elements including the sentinel to prevent reads of uninitialized memory:
// dcjsonrd.cc:200 -- initialize ALL tokenNum+1 elements
memset(tokenArray_, 0, (tokenNum + 1) * sizeof(OFJsmnToken));
- « Previous
- 1
- 2
- 3
- Next »