Project

General

Profile

Bug #1197 » IC-DCMTK-0009_REPORT.md

Jörg Riesmeier, 2026-03-25 10:09

 

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));
(3-3/3)