CVE-2024-52333
An improper array index validation vulnerability exists in the determineMinMax functionality of OFFIS DCMTK 3.6.8. A specially crafted DICOM file can lead to an out-of-bounds write. An attacker can provide a malicious file to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
OFFIS DCMTK 3.6.8
DCMTK - https://dicom.offis.de/dcmtk.php.en
8.4 - CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-119 - Improper Restriction of Operations within the Bounds of a Memory Buffer
DCMTK is a collection of libraries and applications implementing large parts the DICOM standard.
It includes software …
for examining, constructing and converting DICOM image files
handling storage media
sending and receiving images over a network connection
as well as demonstrative image storage and worklist servers
DCMTK is is written in a mixture of ANSI C and C++. It comes in complete source code and is made available as open source software.
DCMTK has been used at numerous DICOM demonstrations to provide central, vendor-independent image storage and worklist servers (CTNs - Central Test Nodes).
It is used by hospitals and companies all over the world for a wide variety of purposes ranging from being a tool for product testing to being a building block for research projects, prototypes and commercial products.
In order to highlight the reason for the crash, we utilize tools such as ASAN compilation. This helps us gain better insights into the cause of the crash. AddressSanitizer is a runtime memory error detector designed to find various types of bugs in C/C++ programs. It can help you identify issues such as:
Below are more details when ASAN is enabled.
=================================================================
==225005==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50c00000057e at pc 0x6492332d60c1 bp 0x7fffd6db5160 sp 0x7fffd6db5150
WRITE of size 1 at 0x50c00000057e thread T0
#0 0x6492332d60c0 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax() /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:203
#1 0x64923362b3bc in DiMonoModality::Init(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:241
#2 0x649233627bfe in DiMonoModality::DiMonoModality(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:51
#3 0x6492332eaa3b in DiMonoImage::DiMonoImage(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimoimg.cc:88
#4 0x6492332e9702 in DiMono2Image::DiMono2Image(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimo2img.cc:36
#5 0x649233258721 in DicomImage::Init() /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:229
#6 0x64923325707f in DicomImage::DicomImage(DcmObject*, E_TransferSyntax, unsigned long, unsigned long, unsigned long) /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:90
#7 0x64923310c4d0 in DJLSEncoderBase::losslessCookedEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&, unsigned short) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:856
#8 0x649233107471 in DJLSEncoderBase::losslessRawEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:459
#9 0x6492331025fa in DJLSEncoderBase::encode(unsigned short const*, unsigned int, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmCodecParameter const*, DcmStack&, bool&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:182
#10 0x649233661510 in DcmCodecList::encode(E_TransferSyntax, unsigned short const*, unsigned int, E_TransferSyntax, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmStack&, bool&) /home/manu/dcmtk/dcmdata/libsrc/dccodec.cc:591
#11 0x64923371379d in DcmPixelData::encode(DcmXfer const&, DcmRepresentationParameter const*, DcmPixelSequence*, DcmXfer const&, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:497
#12 0x6492337105ba in DcmPixelData::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:292
#13 0x64923366d55e in DcmDataset::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*) /home/manu/dcmtk/dcmdata/libsrc/dcdatset.cc:811
#14 0x6492330fdb8d in main /home/manu/dcmtk/dcmjpls/apps/dcmcjpls.cc:468
#15 0x7cccdfc2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#16 0x7cccdfc2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#17 0x6492330f97b4 in _start (/usr/local/bin/dcmcjpls+0x1b17b4) (BuildId: 27a6d2d97cbf2f6e91e821ed5cb8d5b31f8b6c3e)
0x50c00000057e is located 62 bytes after 128-byte region [0x50c0000004c0,0x50c000000540)
allocated by thread T0 here:
#0 0x7ccce04fe6c8 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:98
#1 0x6492332d5d28 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax() /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:196
#2 0x64923362b3bc in DiMonoModality::Init(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:241
#3 0x649233627bfe in DiMonoModality::DiMonoModality(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:51
#4 0x6492332eaa3b in DiMonoImage::DiMonoImage(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimoimg.cc:88
#5 0x6492332e9702 in DiMono2Image::DiMono2Image(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimo2img.cc:36
#6 0x649233258721 in DicomImage::Init() /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:229
#7 0x64923325707f in DicomImage::DicomImage(DcmObject*, E_TransferSyntax, unsigned long, unsigned long, unsigned long) /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:90
#8 0x64923310c4d0 in DJLSEncoderBase::losslessCookedEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&, unsigned short) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:856
#9 0x649233107471 in DJLSEncoderBase::losslessRawEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:459
#10 0x6492331025fa in DJLSEncoderBase::encode(unsigned short const*, unsigned int, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmCodecParameter const*, DcmStack&, bool&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:182
#11 0x649233661510 in DcmCodecList::encode(E_TransferSyntax, unsigned short const*, unsigned int, E_TransferSyntax, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmStack&, bool&) /home/manu/dcmtk/dcmdata/libsrc/dccodec.cc:591
#12 0x64923371379d in DcmPixelData::encode(DcmXfer const&, DcmRepresentationParameter const*, DcmPixelSequence*, DcmXfer const&, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:497
#13 0x6492337105ba in DcmPixelData::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:292
#14 0x64923366d55e in DcmDataset::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*) /home/manu/dcmtk/dcmdata/libsrc/dcdatset.cc:811
#15 0x6492330fdb8d in main /home/manu/dcmtk/dcmjpls/apps/dcmcjpls.cc:468
#16 0x7cccdfc2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#17 0x7cccdfc2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#18 0x6492330f97b4 in _start (/usr/local/bin/dcmcjpls+0x1b17b4) (BuildId: 27a6d2d97cbf2f6e91e821ed5cb8d5b31f8b6c3e)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:203 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax()
Shadow bytes around the buggy address:
0x50c000000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
0x50c000000300: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x50c000000380: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
0x50c000000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
0x50c000000480: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x50c000000500: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa[fa]
0x50c000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==225005==ABORTING
This indicate clearly the evidence of the heap-buffer-overflow happening into `DiInputPixelTemplate<unsigned char, unsigned char>::determineMinMax()` and is corresponding to the following part:
184 int determineMinMax()
185 {
186 if (Data != NULL)
187 {
188 DCMIMGLE_DEBUG("determining minimum and maximum pixel values for input data");
189 T2 *p = Data; /// pointer to pixel data T2 *Data;
190 unsigned long i;
191 const double absrange = getAbsMaxRange();
192 const unsigned long ocnt = (absrange <= 10000000.0) ? OFstatic_cast(unsigned long, absrange) : 0 /* no LUT */;
193 Uint8 *lut = NULL;
194 if ((sizeof(T2) <= 2) && (ocnt > 0) && (Count > 3 * ocnt)) // optimization criteria
195 {
196 lut = new Uint8[ocnt];
197 if (lut != NULL)
198 {
199 DCMIMGLE_DEBUG("using optimized routine with additional LUT");
200 OFBitmanipTemplate<Uint8>::zeroMem(lut, ocnt);
// #define OFstatic_cast(x,y) (static_cast< x >(y))
201 Uint8 *q = lut - OFstatic_cast(T2, getAbsMinimum());
202 for (i = Count; i != 0; --i) // fill lookup table
203 *(q + *(p++)) = 1;
The vulnerabiity is happening because there is no checking on the value corresponding to *p
against the size allocated for the pointer q
The p
pointer coming from the Data
is a pointer to pixel data somehow controllable from the file. It’s derived from the data contained into the file and processed into the function convert
/** convert pixel data from DICOM dataset to input representation
*
** @param document pointer to DICOM image object
* @param bitsAllocated number of bits allocated for each pixel
* @param bitsStored number of bits stored for each pixel
* @param highBit position of high bit within bits allocated
* @param fileCache pointer to file cache object used for partial read
* @param fragment current pixel item fragment (for encapsulated pixel data)
*/
void convert(const DiDocument *document,
const Uint16 bitsAllocated,
const Uint16 bitsStored,
const Uint16 highBit,
DcmFileCache *fileCache,
Uint32 &fragment)
{
[...]
456 if ((pixel != NULL) && (lengthBytes > 0))
457 {
458 const Uint32 length_T1 = lengthBytes / sizeof(T1);
459 /* need to split 'length' in order to avoid integer overflow for large pixel data */
460 const Uint32 length_B1 = lengthBytes / bitsAllocated;
461 const Uint32 length_B2 = lengthBytes % bitsAllocated;
462 // # old code: Count = ((lengthBytes * 8) + bitsAllocated - 1) / bitsAllocated;
463 Count = 8 * length_B1 + (8 * length_B2 + bitsAllocated - 1) / bitsAllocated;
464 unsigned long i;
465 #ifdef HAVE_STD__NOTHROW
466 /* use a non-throwing new here (if available) because the allocated buffer can be huge */
467 Data = new (std::nothrow) T2[Count];
468 #else
469 /* make sure that the pointer is set to NULL in case of error */
470 try
471 {
472 Data = new T2[Count];
473 }
474 catch (STD_NAMESPACE bad_alloc const &)
475 {
476 Data = NULL;
477 }
478 #endif
The size corresponding to the variable Count
is also under control as it’s correlated from lengthBytes
at 463
which is the value of the Dicom entity Pixel Data size and bitsAllocated
which is also from the file as Bits Allocated Dicom entity
The target table pointed by q
at 203
is derived from lut
line 201
and the size of it is depending of ocnt
as indicated in line 196
. ocnt
is derived from absrange
or null line 192
absrange
is calculated through the call to getAbsMaxRange
which is computing difference between private record AbsMaximum
and AbsMinimum
as indicated below :
/** get absolute pixel value range
*
** @return absolute pixel value range
*/
inline double getAbsMaxRange() const
{
return AbsMaximum - AbsMinimum + 1;
}
AbsMaximum
and AbsMinimum
are init while DiInputPixelTemplate
object is created with the following code :
if (this->isSigned())
{
AbsMinimum = -OFstatic_cast(double, DicomImageClass::maxval(Bits - 1, 0));
AbsMaximum = OFstatic_cast(double, DicomImageClass::maxval(Bits - 1));
} else {
AbsMinimum = 0;
AbsMaximum = OFstatic_cast(double, DicomImageClass::maxval(Bits));
}
Looking at the source code, protected variable are well documented as follow :
/// number of pixels stored
unsigned long Count;
/// bits per pixel/sample
unsigned int Bits;
/// first frame to be processed
unsigned long FirstFrame;
/// number of frames to be processed
unsigned long NumberOfFrames;
/// number of pixels per frame
unsigned long FrameSize;
/// first pixel to be processed
unsigned long PixelStart;
/// number of pixels to be processed
unsigned long PixelCount;
/// number of pixels computed from the image resolution
unsigned long ComputedCount;
/// absolute minimum (possible) pixel value
double AbsMinimum;
/// absolute maximum (possible) pixel value
double AbsMaximum;
This demonstrates that by manipulating the file, we can control the loop size using the Count
variable and modify the value derived from line 203
p
pointer. This manipulation leads to memory corruption or a use-after-free condition, as it allows writing beyond the heap allocation.
=================================================================
==225005==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50c00000057e at pc 0x6492332d60c1 bp 0x7fffd6db5160 sp 0x7fffd6db5150
WRITE of size 1 at 0x50c00000057e thread T0
#0 0x6492332d60c0 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax() /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:203
#1 0x64923362b3bc in DiMonoModality::Init(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:241
#2 0x649233627bfe in DiMonoModality::DiMonoModality(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:51
#3 0x6492332eaa3b in DiMonoImage::DiMonoImage(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimoimg.cc:88
#4 0x6492332e9702 in DiMono2Image::DiMono2Image(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimo2img.cc:36
#5 0x649233258721 in DicomImage::Init() /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:229
#6 0x64923325707f in DicomImage::DicomImage(DcmObject*, E_TransferSyntax, unsigned long, unsigned long, unsigned long) /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:90
#7 0x64923310c4d0 in DJLSEncoderBase::losslessCookedEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&, unsigned short) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:856
#8 0x649233107471 in DJLSEncoderBase::losslessRawEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:459
#9 0x6492331025fa in DJLSEncoderBase::encode(unsigned short const*, unsigned int, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmCodecParameter const*, DcmStack&, bool&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:182
#10 0x649233661510 in DcmCodecList::encode(E_TransferSyntax, unsigned short const*, unsigned int, E_TransferSyntax, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmStack&, bool&) /home/manu/dcmtk/dcmdata/libsrc/dccodec.cc:591
#11 0x64923371379d in DcmPixelData::encode(DcmXfer const&, DcmRepresentationParameter const*, DcmPixelSequence*, DcmXfer const&, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:497
#12 0x6492337105ba in DcmPixelData::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:292
#13 0x64923366d55e in DcmDataset::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*) /home/manu/dcmtk/dcmdata/libsrc/dcdatset.cc:811
#14 0x6492330fdb8d in main /home/manu/dcmtk/dcmjpls/apps/dcmcjpls.cc:468
#15 0x7cccdfc2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#16 0x7cccdfc2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#17 0x6492330f97b4 in _start (/usr/local/bin/dcmcjpls+0x1b17b4) (BuildId: 27a6d2d97cbf2f6e91e821ed5cb8d5b31f8b6c3e)
0x50c00000057e is located 62 bytes after 128-byte region [0x50c0000004c0,0x50c000000540)
allocated by thread T0 here:
#0 0x7ccce04fe6c8 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:98
#1 0x6492332d5d28 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax() /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:196
#2 0x64923362b3bc in DiMonoModality::Init(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:241
#3 0x649233627bfe in DiMonoModality::DiMonoModality(DiDocument const*, DiInputPixel*) /home/manu/dcmtk/dcmimgle/libsrc/dimomod.cc:51
#4 0x6492332eaa3b in DiMonoImage::DiMonoImage(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimoimg.cc:88
#5 0x6492332e9702 in DiMono2Image::DiMono2Image(DiDocument const*, EI_Status) /home/manu/dcmtk/dcmimgle/libsrc/dimo2img.cc:36
#6 0x649233258721 in DicomImage::Init() /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:229
#7 0x64923325707f in DicomImage::DicomImage(DcmObject*, E_TransferSyntax, unsigned long, unsigned long, unsigned long) /home/manu/dcmtk/dcmimgle/libsrc/dcmimage.cc:90
#8 0x64923310c4d0 in DJLSEncoderBase::losslessCookedEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&, unsigned short) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:856
#9 0x649233107471 in DJLSEncoderBase::losslessRawEncode(unsigned short const*, unsigned int, DcmItem*, DJLSRepresentationParameter const*, DcmPixelSequence*&, DJLSCodecParameter const*, double&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:459
#10 0x6492331025fa in DJLSEncoderBase::encode(unsigned short const*, unsigned int, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmCodecParameter const*, DcmStack&, bool&) const /home/manu/dcmtk/dcmjpls/libsrc/djcodece.cc:182
#11 0x649233661510 in DcmCodecList::encode(E_TransferSyntax, unsigned short const*, unsigned int, E_TransferSyntax, DcmRepresentationParameter const*, DcmPixelSequence*&, DcmStack&, bool&) /home/manu/dcmtk/dcmdata/libsrc/dccodec.cc:591
#12 0x64923371379d in DcmPixelData::encode(DcmXfer const&, DcmRepresentationParameter const*, DcmPixelSequence*, DcmXfer const&, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:497
#13 0x6492337105ba in DcmPixelData::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*, DcmStack&) /home/manu/dcmtk/dcmdata/libsrc/dcpixel.cc:292
#14 0x64923366d55e in DcmDataset::chooseRepresentation(E_TransferSyntax, DcmRepresentationParameter const*) /home/manu/dcmtk/dcmdata/libsrc/dcdatset.cc:811
#15 0x6492330fdb8d in main /home/manu/dcmtk/dcmjpls/apps/dcmcjpls.cc:468
#16 0x7cccdfc2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#17 0x7cccdfc2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#18 0x6492330f97b4 in _start (/usr/local/bin/dcmcjpls+0x1b17b4) (BuildId: 27a6d2d97cbf2f6e91e821ed5cb8d5b31f8b6c3e)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/manu/dcmtk/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h:203 in DiInputPixelTemplate<unsigned short, unsigned char>::determineMinMax()
Shadow bytes around the buggy address:
0x50c000000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
0x50c000000300: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x50c000000380: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
0x50c000000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
0x50c000000480: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x50c000000500: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa[fa]
0x50c000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x50c000000780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==225005==ABORTING
https://git.dcmtk.org/?p=dcmtk.git;a=commit;h=03e851b0586d05057c3268988e180ffb426b2e03
2024-12-16 - Vendor Disclosure
2025-01-03 - Vendor Patch Release
2025-01-13 - Public Release
Discovered by Emmanuel Tacheau of Cisco Talos.