SHA256
1
0
forked from pool/dcmtk

11 Commits

Author SHA256 Message Date
7b378e4339 Accepting request 1253699 from KDE:Extra
- Add upstream change (CVE-2025-2357, boo#1239679)
  * CVE-2025-2357.patch

OBS-URL: https://build.opensuse.org/request/show/1253699
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/dcmtk?expand=0&rev=34
2025-03-17 21:18:25 +00:00
Christophe Marin
3fee1869be - Add upstream change (CVE-2025-2357, boo#1239679)
* CVE-2025-2357.patch

OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=102
2025-03-17 10:41:06 +00:00
46d5457a5c Accepting request 1247146 from KDE:Extra
- Add patches:
  * 0001-Fixed-another-issue-with-invalid-mono-images.patch
    (CVE-2025-25472, boo#1237369)
  * 0001-Fixed-another-issue-with-invalid-DICOM-images.patch
    (CVE-2025-25474, boo#1237365)
  * 0001-Fixed-issue-with-invalid-RLE-compressed-DICOM-images.patch
    (CVE-2025-25475, boo#1237355)

OBS-URL: https://build.opensuse.org/request/show/1247146
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/dcmtk?expand=0&rev=33
2025-02-20 15:38:05 +00:00
Christophe Marin
f7094eee3f OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=100 2025-02-19 15:30:34 +00:00
Christophe Marin
1d655fa6db another one...
OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=99
2025-02-19 14:17:06 +00:00
Christophe Marin
f1d25f7a15 CVE-2025-25472 fix
OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=98
2025-02-19 14:10:01 +00:00
44f5842d6f Accepting request 1237553 from KDE:Extra
- Update to 3.6.9. See DOCS/CHANGES.368 for the full list of changes
- Drop patches, merged upstream:
  * 0001-Fixed-buffer-overflow-in-decompression-codecs.patch
  * 0001-Fixed-possible-overflows-when-allocating-memory.patch
  * 0001-Fixed-two-segmentation-faults.patch
  * 0001-Fixed-unchecked-typecasts-of-DcmItem-search-results.patch
  * 0002-Fixed-unchecked-typecasts-and-fixed-LUT-handling.patch
  * 0003-Fixed-wrong-error-handling-previous-commit.patch
  * 0001-Fixed-DcmDecimalString-unit-tests.patch
  * 0001-Fixed-link-instructions-for-libtiff.patch
  * 0001-Fix-find_package-library-variables-for-libtiff.patch
- Add patches:
  * 0001-Added-check-to-make-sure-HighBit-BitsAllocated.patch
    (CVE-2024-52333, boo#1235811)
  * 0001-Replaced-call-of-delete-by-delete.patch
  * 0001-Fixed-issue-rendering-invalid-monochrome-image.patch
    (CVE-2024-47796, boo#1235810)

OBS-URL: https://build.opensuse.org/request/show/1237553
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/dcmtk?expand=0&rev=32
2025-01-14 15:22:31 +00:00
Christophe Marin
eb3b79e18d 3.6.9
OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=96
2025-01-13 19:40:28 +00:00
a229ea85f3 Accepting request 1225358 from KDE:Extra
Fix build after the tiff packaging changes

OBS-URL: https://build.opensuse.org/request/show/1225358
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/dcmtk?expand=0&rev=31
2024-11-21 14:14:14 +00:00
Christophe Marin
d46ae2f526 OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=94 2024-11-20 16:59:34 +00:00
Christophe Marin
a3512f14ef Add bug refs
OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/dcmtk?expand=0&rev=93
2024-08-28 13:14:20 +00:00
19 changed files with 376 additions and 3266 deletions

View File

@@ -0,0 +1,55 @@
From 03e851b0586d05057c3268988e180ffb426b2e03 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Fri, 3 Jan 2025 16:08:44 +0100
Subject: [PATCH] Added check to make sure: HighBit < BitsAllocated.
Added check to the image preprocessing to make sure that the value of
HighBit is always less than the value of BitsAllocated. Before, this
missing check could lead to memory corruption if an invalid combination
of values was retrieved from a malformed DICOM dataset.
Thanks to Emmanuel Tacheau from the Cisco Talos team
<vulndiscovery@external.cisco.com> for the report, sample file (PoC)
and detailed analysis. See TALOS-2024-2121 and CVE-2024-52333.
---
dcmimgle/libsrc/diimage.cc | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/dcmimgle/libsrc/diimage.cc b/dcmimgle/libsrc/diimage.cc
index 480235e3b..1827ac68b 100644
--- a/dcmimgle/libsrc/diimage.cc
+++ b/dcmimgle/libsrc/diimage.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1996-2024, OFFIS e.V.
+ * Copyright (C) 1996-2025, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -549,12 +549,18 @@ void DiImage::convertPixelData()
{
const unsigned long fsize = OFstatic_cast(unsigned long, Rows) * OFstatic_cast(unsigned long, Columns) *
OFstatic_cast(unsigned long, SamplesPerPixel);
- if ((BitsAllocated < 1) || (BitsStored < 1) || (BitsAllocated < BitsStored) ||
- (BitsStored > OFstatic_cast(Uint16, HighBit + 1)))
+ if ((BitsAllocated < 1) || (BitsStored < 1))
{
ImageStatus = EIS_InvalidValue;
- DCMIMGLE_ERROR("invalid values for 'BitsAllocated' (" << BitsAllocated << "), "
- << "'BitsStored' (" << BitsStored << ") and/or 'HighBit' (" << HighBit << ")");
+ DCMIMGLE_ERROR("invalid value(s) for 'BitsAllocated' (" << BitsAllocated << "), "
+ << "and/or 'BitsStored' (" << BitsStored << ")");
+ return;
+ }
+ else if ((BitsAllocated < BitsStored) || (BitsAllocated <= HighBit) || ((BitsStored - 1) > HighBit))
+ {
+ ImageStatus = EIS_InvalidValue;
+ DCMIMGLE_ERROR("invalid combination of values for 'BitsAllocated' (" << BitsAllocated << "), "
+ << "'BitsStored' (" << BitsStored << ") and 'HighBit' (" << HighBit << ")");
return;
}
else if ((evr == EVR_OB) && (BitsStored <= 8))
--
2.47.1

View File

@@ -1,69 +0,0 @@
From 66c317feae446deda1a389226aa24c95a0eeac4c Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <dicom@offis.de>
Date: Wed, 13 Mar 2024 23:03:40 +0100
Subject: [PATCH] Fixed DcmDecimalString unit tests.
---
dcmdata/tests/tvrds.cc | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dcmdata/tests/tvrds.cc b/dcmdata/tests/tvrds.cc
index a9132a341..0e929304d 100644
--- a/dcmdata/tests/tvrds.cc
+++ b/dcmdata/tests/tvrds.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2011-2020, OFFIS e.V.
+ * Copyright (C) 2011-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -30,7 +30,7 @@
OFTEST(dcmdata_decimalString_1)
{
- DcmDecimalString decStr(DCM_ContourData, EVR_DS);
+ DcmDecimalString decStr(DCM_ContourData);
OFVector<Float64> doubleVals;
OFCHECK(decStr.putString("1\\2.0\\3.5\\-4.99\\+500.005\\6.66E-01").good());
OFCHECK(decStr.getFloat64Vector(doubleVals).good());
@@ -45,7 +45,7 @@ OFTEST(dcmdata_decimalString_1)
OFTEST(dcmdata_decimalString_2)
{
- DcmDecimalString decStr(DCM_ContourData, EVR_DS);
+ DcmDecimalString decStr(DCM_ContourData);
OFVector<Float64> doubleVals;
/* insert a NULL byte into the string */
OFCHECK(decStr.putString("1\\2.0\\3.5\\-4.99\0\\+500.005\\6.66E-01", 34).good());
@@ -61,7 +61,7 @@ OFTEST(dcmdata_decimalString_2)
OFTEST(dcmdata_decimalString_3)
{
- DcmDecimalString decStr(DCM_ContourData, EVR_DS);
+ DcmDecimalString decStr(DCM_ContourData);
OFVector<Float64> doubleVals;
/* insert a NULL byte into the string */
OFCHECK(decStr.putOFStringArray(OFString("1\\2.0\\3.5\\-4.99\0\\+500.005\\6.66E-01", 34)).good());
@@ -77,7 +77,7 @@ OFTEST(dcmdata_decimalString_3)
OFTEST(dcmdata_decimalString_4)
{
- DcmDecimalString decStr(DCM_ContourData, EVR_DS);
+ DcmDecimalString decStr(DCM_ContourData);
OFVector<Float64> doubleVals;
OFCHECK(decStr.putString("1\\2.0\\3.5\\-4.99\\+500.005\\6.66E-01\\").good());
OFCHECK_EQUAL(decStr.getVM(), 7);
@@ -96,7 +96,7 @@ OFTEST(dcmdata_decimalString_putFloat64)
{
// Test insertion in the beginning
OFString testStr;
- DcmDecimalString decStr(DCM_ContourData, EVR_DS);
+ DcmDecimalString decStr(DCM_ContourData);
OFCHECK(decStr.putFloat64(0, 0).good());
decStr.getOFStringArray(testStr);
OFCHECK(testStr == "0");
--
2.44.0

View File

@@ -0,0 +1,41 @@
From 8d66178e559e53ce8658ff671a68b6462865b0d5 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Tue, 21 Jan 2025 11:12:28 +0100
Subject: [PATCH] Fixed another issue with invalid DICOM images.
Fixed issue when processing an invalid DICOM image where the number of
pixels stored does not match the expected number of pixels (too less)
and the combination of BitsAllocated and BitsStored is really unusual
(e.g. 1 bit stored, but 52 bits allocated). In cases where the last
pixel (e.g. a single bit) does not fit into the buffer of the input
pixel data, a buffer overflow occurred on the heap. Now, the last entry
of the buffer is filled with the smallest possible value (e.g. 0 in case
of unsigned data).
Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
and the sample file (PoC).
---
dcmimgle/include/dcmtk/dcmimgle/diinpxt.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h b/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
index 6a37c2d..420e73c 100644
--- a/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
+++ b/dcmimgle/include/dcmtk/dcmimgle/diinpxt.h
@@ -643,6 +643,13 @@ class DiInputPixelTemplate
skip -= times * bitsof_T1;
}
}
+ /* fill the remaining entry (if any) with the smallest value that is possible */
+ if (q < Data + Count)
+ {
+ DCMIMGLE_TRACE("not enough data, filling last entry of input buffer with value = " << getAbsMinimum());
+ *q = OFstatic_cast(T2, getAbsMinimum());
+ }
+
}
} else
DCMIMGLE_DEBUG("cannot allocate memory buffer for 'Data' in DiInputPixelTemplate::convert()");
--
2.48.1

View File

@@ -0,0 +1,54 @@
From 410ffe2019b9db6a8f4036daac742a6f5e4d36c2 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Fri, 17 Jan 2025 17:53:50 +0100
Subject: [PATCH] Fixed another issue with invalid mono images.
Fixed issue when rendering an invalid monochrome DICOM image where the
number of pixels stored does not match the expected number of pixels.
In this case, only a single pixel is processed, but the pixel matrix is
much larger. Filling the rest of the pixel matrix with the smallest
possible value for the image is not working because of an optimized
memory usage (value would be out of range). Now, the pixel value to be
used is double-checked before it is actually filled into the "background"
of the image.
Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
and the sample file (PoC).
---
dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h b/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
index 50389a540..f67967310 100644
--- a/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+++ b/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
@@ -28,6 +28,7 @@
#include "dcmtk/ofstd/ofbmanip.h"
#include "dcmtk/ofstd/ofcast.h"
#include "dcmtk/ofstd/ofdiag.h" /* for DCMTK_DIAGNOSTIC macros */
+#include "dcmtk/ofstd/oflimits.h" /* for OFnumeric_limits<> */
#include "dcmtk/dcmimgle/dimopxt.h"
#include "dcmtk/dcmimgle/diinpx.h"
@@ -72,9 +73,16 @@ class DiMonoInputPixelTemplate
rescale(pixel); // "copy" or reference pixel data
this->determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue()));
}
- /* erase empty part of the buffer (= fill the background with the smallest possible value) */
+ /* erase empty part of the buffer */
if ((this->Data != NULL) && (this->InputCount < this->Count))
- OFBitmanipTemplate<T3>::setMem(this->Data + this->InputCount, OFstatic_cast(T3, this->Modality->getAbsMinimum()), this->Count - this->InputCount);
+ {
+ /* that means, fill the background with the smallest value that is possible */
+ const T3 minOut = OFnumeric_limits<T3>::min();
+ const T3 background = (this->Modality->getAbsMinimum() < OFstatic_cast(double, minOut)) ? minOut : OFstatic_cast(T3, this->Modality->getAbsMinimum());
+ const size_t count = (this->Count - this->InputCount);
+ DCMIMGLE_DEBUG("filing empty part of the intermediate pixel data (" << count << " pixels) with value = " << OFstatic_cast(double, background));
+ OFBitmanipTemplate<T3>::setMem(this->Data + this->InputCount, background, count);
+ }
}
}
--
2.48.1

View File

@@ -1,211 +0,0 @@
From 31ff413f97839c61752875569862a94a6cce06dd Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <dicom@offis.de>
Date: Thu, 28 Dec 2023 17:32:42 +0100
Subject: [PATCH] Fixed buffer overflow in decompression codecs.
Fixed the computation of the element size for the decompressed PixelData
element in all decompression codecs. In the case of datasets that cannot
be decoded to an unencapsulated transfer syntax, since the resulting
pixel data would be larger than 4 GByte, an overflow of the size
variable remained undetected and could lead to a segmentation fault due
to a buffer overrun.
This closes DCMTK issue #1099.
---
dcmdata/libsrc/dcrleccd.cc | 39 ++++++++++++++++++++++++++++++--------
dcmjpeg/libsrc/djcodecd.cc | 36 ++++++++++++++++++++++++++++++-----
dcmjpls/libsrc/djcodecd.cc | 17 ++++++++++++++++-
3 files changed, 78 insertions(+), 14 deletions(-)
diff --git a/dcmdata/libsrc/dcrleccd.cc b/dcmdata/libsrc/dcrleccd.cc
index ffdd14116..5ddc8f6be 100644
--- a/dcmdata/libsrc/dcrleccd.cc
+++ b/dcmdata/libsrc/dcrleccd.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2002-2020, OFFIS e.V.
+ * Copyright (C) 2002-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -129,9 +129,25 @@ OFCondition DcmRLECodecDecoder::decode(
if (rledecoder.fail()) result = EC_MemoryExhausted; // RLE decoder failed to initialize
else
{
- const size_t frameSize = OFstatic_cast(size_t, imageBytesAllocated) * OFstatic_cast(size_t, imageRows)
- * OFstatic_cast(size_t, imageColumns) * OFstatic_cast(size_t, imageSamplesPerPixel);
- size_t totalSize = frameSize * imageFrames;
+ // compute size of uncompressed frame, in bytes
+ Uint32 frameSize = imageBytesAllocated * imageRows * imageColumns * imageSamplesPerPixel;
+
+ // check for overflow
+ if (imageRows != 0 && frameSize / imageRows != (imageBytesAllocated * imageColumns * imageSamplesPerPixel))
+ {
+ DCMDATA_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
+ Uint32 totalSize = frameSize * imageFrames;
+
+ // check for overflow
+ if (totalSize == 0xFFFFFFFF || (frameSize != 0 && totalSize / frameSize != OFstatic_cast(Uint32, imageFrames)))
+ {
+ DCMDATA_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
if (totalSize & 1) totalSize++; // align on 16-bit word boundary
Uint16 *imageData16 = NULL;
Sint32 currentFrame = 0;
@@ -139,7 +155,7 @@ OFCondition DcmRLECodecDecoder::decode(
Uint32 numberOfStripes = 0;
Uint32 fragmentLength = 0;
- result = uncompressedPixelData.createUint16Array(OFstatic_cast(Uint32, totalSize/sizeof(Uint16)), imageData16);
+ result = uncompressedPixelData.createUint16Array(totalSize/sizeof(Uint16), imageData16);
if (result.good())
{
Uint8 *imageData8 = OFreinterpret_cast(Uint8 *, imageData16);
@@ -463,7 +479,7 @@ OFCondition DcmRLECodecDecoder::decodeFrame(
Uint16 imageColumns = 0;
Sint32 imageFrames = 1;
Uint16 imageBitsAllocated = 0;
- Uint16 imageBytesAllocated = 0;
+ Uint32 imageBytesAllocated = 0;
Uint16 imagePlanarConfiguration = 0;
Uint32 rleHeader[16];
OFString photometricInterpretation;
@@ -476,7 +492,7 @@ OFCondition DcmRLECodecDecoder::decodeFrame(
if (result.good()) result = dataset->findAndGetOFString(DCM_PhotometricInterpretation, photometricInterpretation);
if (result.good())
{
- imageBytesAllocated = OFstatic_cast(Uint16, imageBitsAllocated / 8);
+ imageBytesAllocated = OFstatic_cast(Uint32, imageBitsAllocated / 8);
if ((imageBitsAllocated < 8)||(imageBitsAllocated % 8 != 0))
{
DCMDATA_ERROR("The RLE decoder only supports images where BitsAllocated is a multiple of 8.");
@@ -500,9 +516,16 @@ OFCondition DcmRLECodecDecoder::decodeFrame(
const size_t bytesPerStripe = OFstatic_cast(size_t, imageColumns) * OFstatic_cast(size_t, imageRows);
Uint32 numberOfStripes = 0;
Uint32 fragmentLength = 0;
- Uint32 frameSize = OFstatic_cast(Uint32, imageBytesAllocated) * OFstatic_cast(Uint32, imageRows)
+ Uint32 frameSize = imageBytesAllocated * OFstatic_cast(Uint32, imageRows)
* OFstatic_cast(Uint32, imageColumns) * OFstatic_cast(Uint32, imageSamplesPerPixel);
+ // check for overflow
+ if (imageRows != 0 && frameSize / imageRows != (imageBytesAllocated * imageColumns * imageSamplesPerPixel))
+ {
+ DCMDATA_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
if (frameSize > bufSize) return EC_IllegalCall;
DcmRLEDecoder rledecoder(bytesPerStripe);
diff --git a/dcmjpeg/libsrc/djcodecd.cc b/dcmjpeg/libsrc/djcodecd.cc
index 364b75533..a93a8104b 100644
--- a/dcmjpeg/libsrc/djcodecd.cc
+++ b/dcmjpeg/libsrc/djcodecd.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2001-2022, OFFIS e.V.
+ * Copyright (C) 2001-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -150,8 +150,25 @@ OFCondition DJCodecDecoder::decode(
if (jpeg == NULL) result = EC_MemoryExhausted;
else
{
- size_t frameSize = ((precision > 8) ? sizeof(Uint16) : sizeof(Uint8)) * imageRows * imageColumns * imageSamplesPerPixel;
- size_t totalSize = frameSize * imageFrames;
+ Uint32 imageBytesAllocated = (precision > 8) ? sizeof(Uint16) : sizeof(Uint8);
+ Uint32 frameSize = imageBytesAllocated * imageRows * imageColumns * imageSamplesPerPixel;
+
+ // check for overflow
+ if (imageRows != 0 && frameSize / imageRows != (imageBytesAllocated * imageColumns * imageSamplesPerPixel))
+ {
+ DCMJPEG_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
+ Uint32 totalSize = frameSize * imageFrames;
+
+ // check for overflow
+ if (totalSize == 0xFFFFFFFF || (frameSize != 0 && totalSize / frameSize != OFstatic_cast(Uint32, imageFrames)))
+ {
+ DCMJPEG_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
if (totalSize & 1) totalSize++; // align on 16-bit word boundary
Uint16 *imageData16 = NULL;
Sint32 currentFrame = 0;
@@ -166,7 +183,7 @@ OFCondition DJCodecDecoder::decode(
}
}
- result = uncompressedPixelData.createUint16Array(OFstatic_cast(Uint32, totalSize / sizeof(Uint16)), imageData16);
+ result = uncompressedPixelData.createUint16Array(totalSize / sizeof(Uint16), imageData16);
if (result.good())
{
Uint8 *imageData8 = OFreinterpret_cast(Uint8*, imageData16);
@@ -492,7 +509,16 @@ OFCondition DJCodecDecoder::decodeFrame(
if (precision == 0) result = EC_CannotChangeRepresentation; // something has gone wrong, bail out
else
{
- size_t frameSize = ((precision > 8) ? sizeof(Uint16) : sizeof(Uint8)) * imageRows * imageColumns * imageSamplesPerPixel;
+ Uint32 imageBytesAllocated = (precision > 8) ? sizeof(Uint16) : sizeof(Uint8);
+ Uint32 frameSize = imageBytesAllocated * imageRows * imageColumns * imageSamplesPerPixel;
+
+ // check for overflow
+ if (imageRows != 0 && frameSize / imageRows != (imageBytesAllocated * imageColumns * imageSamplesPerPixel))
+ {
+ DCMJPEG_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
if (frameSize > bufSize) return EC_IllegalCall;
DJDecoder *jpeg = createDecoderInstance(fromParam, djcp, precision, isYBR);
diff --git a/dcmjpls/libsrc/djcodecd.cc b/dcmjpls/libsrc/djcodecd.cc
index e04a21e0d..45e6fec56 100644
--- a/dcmjpls/libsrc/djcodecd.cc
+++ b/dcmjpls/libsrc/djcodecd.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2007-2022, OFFIS e.V.
+ * Copyright (C) 2007-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -143,8 +143,23 @@ OFCondition DJLSDecoderBase::decode(
// compute size of uncompressed frame, in bytes
Uint32 frameSize = bytesPerSample * imageRows * imageColumns * imageSamplesPerPixel;
+ // check for overflow
+ if (imageRows != 0 && frameSize / imageRows != (bytesPerSample * imageColumns * imageSamplesPerPixel))
+ {
+ DCMJPLS_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
// compute size of pixel data attribute, in bytes
Uint32 totalSize = frameSize * imageFrames;
+
+ // check for overflow
+ if (totalSize == 0xFFFFFFFF || (frameSize != 0 && totalSize / frameSize != OFstatic_cast(Uint32, imageFrames)))
+ {
+ DCMJPLS_WARN("Cannot decompress image because uncompressed representation would exceed maximum possible size of PixelData attribute.");
+ return EC_ElemLengthExceeds32BitField;
+ }
+
if (totalSize & 1) totalSize++; // align on 16-bit word boundary
// assume we can cast the codec parameter to what we need
--
2.44.0

View File

@@ -0,0 +1,39 @@
From 89a6e399f1e17d08a8bc8cdaa05b2ac9a50cd4f6 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Sat, 11 Jan 2025 17:59:39 +0100
Subject: [PATCH] Fixed issue rendering invalid monochrome image.
Fixed issue when rendering an invalid monochrome DICOM image where the
number of pixels stored does not match the expected number of pixels.
If the stored number is less than the expected number, the rest of the
pixel matrix for the intermediate representation was always filled with
the value 0. Under certain, very rare conditions, this could result in
memory problems reported by an Address Sanitizer (ASAN). Now, the rest
of the matrix is filled with the smallest possible value for the image.
Thanks to Emmanuel Tacheau from the Cisco Talos team
<vulndiscovery@external.cisco.com> for the original report, the sample
file (PoC) and further details. See TALOS-2024-2122 and CVE-2024-47796.
---
dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h b/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
index e749a6b16..50389a540 100644
--- a/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
+++ b/dcmimgle/include/dcmtk/dcmimgle/dimoipxt.h
@@ -72,9 +72,9 @@ class DiMonoInputPixelTemplate
rescale(pixel); // "copy" or reference pixel data
this->determineMinMax(OFstatic_cast(T3, this->Modality->getMinValue()), OFstatic_cast(T3, this->Modality->getMaxValue()));
}
- /* erase empty part of the buffer (= blacken the background) */
+ /* erase empty part of the buffer (= fill the background with the smallest possible value) */
if ((this->Data != NULL) && (this->InputCount < this->Count))
- OFBitmanipTemplate<T3>::zeroMem(this->Data + this->InputCount, this->Count - this->InputCount);
+ OFBitmanipTemplate<T3>::setMem(this->Data + this->InputCount, OFstatic_cast(T3, this->Modality->getAbsMinimum()), this->Count - this->InputCount);
}
}
--
2.47.1

View File

@@ -0,0 +1,42 @@
From 9749a73aaf1cbb4a46b730214f559fc8a6891597 Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <eichelberg@offis.de>
Date: Thu, 23 Jan 2025 15:51:21 +0100
Subject: [PATCH] Fixed issue with invalid RLE compressed DICOM images.
Fixed issue when processing an RLE compressed image where the RLE header
contains an invalid stripe size.
Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
and the sample file (PoC).
---
dcmdata/libsrc/dcrleccd.cc | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dcmdata/libsrc/dcrleccd.cc b/dcmdata/libsrc/dcrleccd.cc
index fd01b63..e45ef0c 100644
--- a/dcmdata/libsrc/dcrleccd.cc
+++ b/dcmdata/libsrc/dcrleccd.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2002-2024, OFFIS e.V.
+ * Copyright (C) 2002-2025, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -348,6 +348,12 @@ OFCondition DcmRLECodecDecoder::decode(
} /* while */
// last fragment for this RLE stripe
+ if (inputBytes + byteOffset > fragmentLength)
+ {
+ DCMDATA_ERROR("stream size in RLE header is wrong");
+ inputBytes = fragmentLength-byteOffset;
+ }
+
result = rledecoder.decompress(rleData + byteOffset, OFstatic_cast(size_t, inputBytes));
// special handling for zero pad byte at the end of the RLE stream
--
2.48.1

View File

@@ -1,611 +0,0 @@
From c5d8818f68c991cb580c7d52cc2ed99391259ce9 Mon Sep 17 00:00:00 2001
From: Michael Onken <onken@open-connections.de>
Date: Tue, 20 Feb 2024 10:50:28 +0100
Subject: [PATCH] Fixed possible overflows when allocating memory.
Thanks to GitHub user "bananabr" (Daniel Berredo) for the report and
suggested patch.
---
dcmect/libsrc/enhanced_ct.cc | 14 +-
dcmect/tests/CMakeLists.txt | 1 +
dcmect/tests/Makefile.dep | 151 +++++++++++++++
dcmect/tests/t_overflow.cc | 360 +++++++++++++++++++++++++++++++++++
dcmect/tests/tests.cc | 3 +-
5 files changed, 527 insertions(+), 2 deletions(-)
create mode 100644 dcmect/tests/t_overflow.cc
diff --git a/dcmect/libsrc/enhanced_ct.cc b/dcmect/libsrc/enhanced_ct.cc
index 6193742..47d6335 100644
--- a/dcmect/libsrc/enhanced_ct.cc
+++ b/dcmect/libsrc/enhanced_ct.cc
@@ -24,6 +24,7 @@
#include "dcmtk/dcmect/types.h"
#include "dcmtk/dcmfg/concatenationcreator.h"
#include "dcmtk/dcmfg/concatenationloader.h"
+#include "dcmtk/dcmfg/fgtypes.h"
#include "dcmtk/dcmiod/iodutil.h"
#include "dcmtk/dcmiod/modimagepixel.h"
@@ -100,8 +101,19 @@ struct EctEnhancedCT::WriteVisitor
m_CT.getRows(rows);
m_CT.getColumns(cols);
const size_t numFrames = m_CT.m_Frames.size();
+ if (numFrames > 2147483647)
+ {
+ DCMECT_ERROR("More than 2147483647 frames provided");
+ return FG_EC_PixelDataTooLarge;
+ }
+ const size_t numPixelsFrame = OFstatic_cast(size_t, rows) * OFstatic_cast(size_t, cols);
const size_t numBytesFrame = m_CT.m_Frames[0]->length;
- const size_t numPixelsFrame = rows * cols;
+ if (numBytesFrame != numPixelsFrame * 2)
+ {
+ DCMECT_ERROR("Invalid number of bytes per frame: Expected " << numPixelsFrame * 2 << " but got "
+ << numBytesFrame << " frame pixel data");
+ return ECT_InvalidPixelInfo;
+ }
// Creates the correct pixel data element, based on the image pixel module used.
DcmPixelData* pixData = new DcmPixelData(DCM_PixelData);
OFCondition result;
diff --git a/dcmect/tests/CMakeLists.txt b/dcmect/tests/CMakeLists.txt
index 5d66b11..0325534 100644
--- a/dcmect/tests/CMakeLists.txt
+++ b/dcmect/tests/CMakeLists.txt
@@ -2,6 +2,7 @@
DCMTK_ADD_EXECUTABLE(dcmect_tests
tests.cc
t_huge_concat.cc
+ t_overflow.cc
t_roundtrip.cc
)
diff --git a/dcmect/tests/Makefile.dep b/dcmect/tests/Makefile.dep
index 9d26f58..dfb50b8 100644
--- a/dcmect/tests/Makefile.dep
+++ b/dcmect/tests/Makefile.dep
@@ -192,6 +192,157 @@ t_huge_concat.o: t_huge_concat.cc \
../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \
../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h \
../../dcmfg/include/dcmtk/dcmfg/fgtemporalposition.h
+t_overflow.o: t_overflow.cc ../../config/include/dcmtk/config/osconfig.h \
+ ../include/dcmtk/dcmect/enhanced_ct.h ../include/dcmtk/dcmect/def.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexport.h \
+ ../include/dcmtk/dcmect/types.h ../../oflog/include/dcmtk/oflog/oflog.h \
+ ../../oflog/include/dcmtk/oflog/logger.h \
+ ../../oflog/include/dcmtk/oflog/config.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcast.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \
+ ../../oflog/include/dcmtk/oflog/config/defines.h \
+ ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \
+ ../../oflog/include/dcmtk/oflog/loglevel.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvector.h \
+ ../../ofstd/include/dcmtk/ofstd/oftypes.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstream.h \
+ ../../oflog/include/dcmtk/oflog/tstring.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstring.h \
+ ../../oflog/include/dcmtk/oflog/tchar.h \
+ ../../oflog/include/dcmtk/oflog/spi/apndatch.h \
+ ../../oflog/include/dcmtk/oflog/appender.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmem.h \
+ ../../ofstd/include/dcmtk/ofstd/ofutil.h \
+ ../../ofstd/include/dcmtk/ofstd/oftraits.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \
+ ../../oflog/include/dcmtk/oflog/layout.h \
+ ../../oflog/include/dcmtk/oflog/streams.h \
+ ../../oflog/include/dcmtk/oflog/helpers/pointer.h \
+ ../../oflog/include/dcmtk/oflog/thread/syncprim.h \
+ ../../oflog/include/dcmtk/oflog/spi/filter.h \
+ ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \
+ ../../oflog/include/dcmtk/oflog/spi/logfact.h \
+ ../../oflog/include/dcmtk/oflog/logmacro.h \
+ ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \
+ ../../oflog/include/dcmtk/oflog/tracelog.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcond.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdiag.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/push.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/pop.def \
+ ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fg.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \
+ ../../ofstd/include/dcmtk/ofstd/offile.h \
+ ../../ofstd/include/dcmtk/ofstd/ofstd.h \
+ ../../ofstd/include/dcmtk/ofstd/oflist.h \
+ ../../ofstd/include/dcmtk/ofstd/oflimits.h \
+ ../../config/include/dcmtk/config/arith.h \
+ ../../ofstd/include/dcmtk/ofstd/oferror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \
+ ../../ofstd/include/dcmtk/ofstd/ofglobal.h \
+ ../../ofstd/include/dcmtk/ofstd/ofthread.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \
+ ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dclist.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \
+ ../../ofstd/include/dcmtk/ofstd/ofmap.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \
+ ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modbase.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modfor.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \
+ ../../ofstd/include/dcmtk/ofstd/ofvriant.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/variant.h \
+ ../../ofstd/include/dcmtk/ofstd/variadic/helpers.h \
+ ../../ofstd/include/dcmtk/ofstd/ofalign.h \
+ ../../ofstd/include/dcmtk/ofstd/diag/cnvrsn.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/vsprfw.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/arrybnds.def \
+ ../../ofstd/include/dcmtk/ofstd/diag/unrefprm.def \
+ ../../dcmiod/include/dcmtk/dcmiod/modacquisitioncontext.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \
+ ../../dcmiod/include/dcmtk/dcmiod/modsynchronisation.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdatime.h \
+ ../../ofstd/include/dcmtk/ofstd/ofdate.h \
+ ../../ofstd/include/dcmtk/ofstd/oftime.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \
+ ../../ofstd/include/dcmtk/ofstd/oftempf.h \
+ ../../ofstd/include/dcmtk/ofstd/oftest.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconapp.h \
+ ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexbl.h \
+ ../../ofstd/include/dcmtk/ofstd/ofconsol.h \
+ ../../ofstd/include/dcmtk/ofstd/ofexit.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiondetails.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiontype.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctadditionalxraysource.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrfl.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctexposure.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctgeometry.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctimageframetype.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctposition.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctreconstruction.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgcttabledynamics.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgctxraydetails.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgframeanatomy.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgirradiationeventid.h \
+ ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixeltransform.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \
+ ../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \
+ ../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h
t_roundtrip.o: t_roundtrip.cc \
../../config/include/dcmtk/config/osconfig.h \
../../ofstd/include/dcmtk/ofstd/ofmem.h \
diff --git a/dcmect/tests/t_overflow.cc b/dcmect/tests/t_overflow.cc
new file mode 100644
index 0000000..4e9ac8b
--- /dev/null
+++ b/dcmect/tests/t_overflow.cc
@@ -0,0 +1,360 @@
+/*
+ *
+ * Copyright (C) 2024, OFFIS e.V.
+ * All rights reserved. See COPYRIGHT file for details.
+ *
+ * This software and supporting documentation were developed by
+ *
+ * OFFIS e.V.
+ * R&D Division Health
+ * Escherweg 2
+ * D-26121 Oldenburg, Germany
+ *
+ *
+ * Module: dcmect
+ *
+ * Author: Daniel Berredo / Michael Onken
+ *
+ * Purpose: Tests that check for pixel data overflow conditions
+ *
+ */
+
+
+#include <dcmtk/config/osconfig.h> /* make sure OS specific configuration is included first */
+
+#include <dcmtk/dcmect/enhanced_ct.h>
+
+#include <dcmtk/ofstd/oftempf.h>
+#include <dcmtk/ofstd/oftest.h>
+
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dcfilefo.h>
+
+#include <dcmtk/dcmfg/fgctacquisitiondetails.h>
+#include <dcmtk/dcmfg/fgctacquisitiontype.h>
+#include <dcmtk/dcmfg/fgctadditionalxraysource.h>
+#include <dcmtk/dcmfg/fgctexposure.h>
+#include <dcmtk/dcmfg/fgctgeometry.h>
+#include <dcmtk/dcmfg/fgctimageframetype.h>
+#include <dcmtk/dcmfg/fgctposition.h>
+#include <dcmtk/dcmfg/fgctreconstruction.h>
+#include <dcmtk/dcmfg/fgcttabledynamics.h>
+#include <dcmtk/dcmfg/fgctxraydetails.h>
+#include <dcmtk/dcmfg/fgfracon.h>
+#include <dcmtk/dcmfg/fgframeanatomy.h>
+#include <dcmtk/dcmfg/fgirradiationeventid.h>
+#include <dcmtk/dcmfg/fgpixeltransform.h>
+#include <dcmtk/dcmfg/fgpixmsr.h>
+#include <dcmtk/dcmfg/fgplanor.h>
+#include <dcmtk/dcmfg/fgplanpo.h>
+#include <dcmtk/dcmfg/fgrealworldvaluemapping.h>
+
+static const Uint16 NUM_ROWS = 1024;
+static const Uint16 NUM_COLS = 1;
+static const Uint16 NUM_FRAMES = 2;
+static const size_t NUM_PIXELS_PER_FRAME = 1;
+
+static OFString EXPECTED_DUMP;
+
+static EctEnhancedCT *create();
+static void configureIOD(EctEnhancedCT *ct);
+static void setGenericValues(EctEnhancedCT *ct);
+static void addSharedFGs(EctEnhancedCT *ct);
+static void addFrames(EctEnhancedCT *ct);
+static void addDimensions(EctEnhancedCT *ct);
+
+
+OFTEST(dcmect_overflow)
+{
+ /* make sure data dictionary is loaded */
+ if (!dcmDataDict.isDictionaryLoaded())
+ {
+ OFCHECK(dcmDataDict.isDictionaryLoaded());
+ }
+
+ // Creation
+ EctEnhancedCT *ct = create();
+ configureIOD(ct);
+ setGenericValues(ct);
+ addSharedFGs(ct);
+ addFrames(ct);
+ addDimensions(ct);
+
+ // Write to dataset and compare its dump with expected result
+ DcmFileFormat dcmff;
+
+ OFTempFile tf(O_RDWR, "", "t_overflow", ".dcm");
+ OFCondition result;
+ result = ct->saveFile("output.dcm", EXS_LittleEndianExplicit);
+ OFCHECK_MSG(result == ECT_InvalidPixelInfo, result.text());
+}
+
+static EctEnhancedCT *create()
+{
+ IODEnhGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1");
+ EctEnhancedCT *ct = NULL;
+ OFCondition result;
+ result = EctEnhancedCT::create(ct,
+ NUM_ROWS,
+ NUM_COLS,
+ OFFalse,
+ EctTypes::E_ImageType1_Original,
+ EctTypes::DT_ImageType3_Volume,
+ EctTypes::DT_ImageType4_Maximum,
+ "1" /* instance number */,
+ EctTypes::E_ContQuali_Research,
+ EctTypes::E_PixelPres_Monochrome,
+ EctTypes::E_VolProps_Volume,
+ EctTypes::DT_VolBasedCalcTechnique_VolumeRender,
+ eq,
+ "20190801120000" /* acquisition date */,
+ 2.0 /* acquisition duration */);
+
+ OFCHECK(result.good());
+ OFCHECK(ct != OFnullptr);
+ return ct;
+}
+
+static void configureIOD(EctEnhancedCT *ct)
+{
+ if (!ct)
+ return;
+}
+
+static void setGenericValues(EctEnhancedCT *ct)
+{
+ if (!ct)
+ return;
+ OFCHECK(ct->getPatient().setPatientName("Bond^James").good());
+ OFCHECK(ct->getPatient().setPatientID("007").good());
+ OFCHECK(ct->getPatient().setPatientBirthDate("19771007").good());
+ OFCHECK(ct->getStudy().setStudyDate("20190801").good());
+ OFCHECK(ct->getStudy().setStudyTime("120000").good());
+ OFCHECK(ct->getStudy().setStudyID("1").good());
+ OFCHECK(ct->getPatientStudy().setPatientAge("040Y").good());
+ OFCHECK(ct->getSeries().setSeriesDescription("Test Description").good());
+ OFCHECK(ct->getSeries().setSeriesNumber("1").good());
+ OFCHECK(ct->getSeries().setPatientPosition("HFS").good());
+
+ // Those values are usually computed automatically. UIDS are generated and date/times are set to current values.
+ // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually,
+ // so that they are not overwritten with new, automatically created values later.
+ OFCHECK(ct->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good());
+ OFCHECK(ct->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good());
+ OFCHECK(ct->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good());
+ OFCHECK(ct->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good());
+
+ OFCHECK(ct->getIODMultiFrameFGModule().setContentTime("092557").good());
+ OFCHECK(ct->getIODMultiFrameFGModule().setContentDate("20190816").good());
+}
+
+static void addSharedFGs(EctEnhancedCT *ct)
+{
+ if (!ct)
+ return;
+
+ FGPixelMeasures meas;
+ OFCHECK(meas.setPixelSpacing("0.1\\0.1").good());
+ OFCHECK(meas.setSliceThickness("1.0").good());
+ OFCHECK(meas.setSpacingBetweenSlices("0.05").good());
+
+ FGPlanePosPatient planpo;
+ OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good());
+
+ FGPlaneOrientationPatient planor;
+ OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good());
+
+ FGFrameAnatomy ana;
+ OFCHECK(ana.setLaterality(FGFrameAnatomy::LATERALITY_BOTH).good());
+ OFCHECK(ana.getAnatomy().getAnatomicRegion().set("12738006", "SCT", "Brain").good());
+
+ FGIrradiationEventIdentification irr;
+ OFCHECK(irr.setIrradiationEventUID("2.25.30853892236613436472911970638347155062").good());
+
+ FGCTImageFrameType itype;
+ OFCHECK(itype.setFrameType("ORIGINAL\\PRIMARY\\VOLUME\\MAXIMUM").good());
+ OFCHECK(itype.setPixelPresentation(FGCTImageFrameType::E_PixelPres_Monochrome).good());
+ OFCHECK(itype.setVolumetricProperties(FGCTImageFrameType::E_VolProp_Volume).good());
+ OFCHECK(itype.setVolumeBasedCalculationTechnique(FGCTImageFrameType::DT_VolBasedCalcTechnique_VolumeRender).good());
+
+ FGCTAcquisitionType atype;
+ OFCHECK(atype.setAcquisitionType(FGCTAcquisitionType::DT_AcquisitionType_ConstantAngle).good());
+ OFCHECK(atype.setTubeAngle(0.1).good());
+ OFCHECK(atype.setConstantVolumeFlag(FGCTAcquisitionType::E_ConstVol_Yes).good());
+ OFCHECK(atype.setFluoroscopyFlag(FGCTAcquisitionType::E_Fluoroscopy_No).good());
+
+ FGCTAcquisitionDetails adetails;
+ FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem *item = new FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem();
+ OFCHECK(item->setRotationDirection(FGCTAcquisitionDetails::E_RotationDirection_CW).good());
+ OFCHECK(item->setRevolutionTime(5).good());
+ OFCHECK(item->setSingleCollimationWidth(1).good());
+ OFCHECK(item->setTotalCollimationWidth(10).good());
+ OFCHECK(item->setTableHeight(50).good());
+ OFCHECK(item->setGantryDetectorTilt(5).good());
+ OFCHECK(item->setDataCollectionDiameter(20).good());
+ adetails.getCTAcquisitionDetailsItems().push_back(item);
+
+ FGCTTableDynamics dyn;
+ FGCTTableDynamics::FGCTTableDynamicsItem *dyn_item = new FGCTTableDynamics::FGCTTableDynamicsItem;
+ OFCHECK(dyn_item);
+ if (dyn_item)
+ {
+ OFCHECK(dyn_item->setTableSpeed(1.0).good());
+ OFCHECK(dyn_item->setTableFeedPerRotation(0.1).good());
+ OFCHECK(dyn_item->setSpiralPitchFactor(0.2).good());
+ dyn.getCTTableDynamicsItems().push_back(dyn_item);
+ }
+
+ FGCTPosition pos;
+ OFCHECK(pos.setTablePosition(100.0).good());
+ OFCHECK(pos.setReconstructionTargetCenterPatient(OFVector<Float64>(3, 1.0)).good());
+ OFCHECK(pos.setDataCollectionCenterPatient(OFVector<Float64>(3, 2.0)).good());
+
+ FGCTGeometry geo;
+ FGCTGeometry::FGCTGeometryItem *geo_item = new FGCTGeometry::FGCTGeometryItem;
+ if (geo_item)
+ {
+ OFCHECK(geo_item->setDistanceSourceToDataCollectionCenter(5.0).good());
+ OFCHECK(geo_item->setDistanceSourceToDetector(0.5).good());
+ geo.getCTGeometryItems().push_back(geo_item);
+ }
+
+ FGCTReconstruction rec;
+ OFCHECK(rec.setConvolutionKernel("DUMMY").good());
+ OFCHECK(rec.setConvolutionKernelGroup("DUMMYGROUP").good());
+ OFCHECK(rec.setImageFilter("FILTER").good());
+ OFCHECK(rec.setReconstructionAlgorithm("ALGO").good());
+ OFCHECK(rec.setReconstructionAngle(90.0).good());
+ OFCHECK(rec.setReconstructionDiameter(100.0).good());
+ // Not permitted if Reconstruction Diameter is provided instead
+ // OFCHECK(rec.setReconstructionFieldOfView(100.0, 100.0).good());
+ OFCHECK(rec.setReconstructionPixelSpacing(0.1, 0.1).good());
+
+ FGCTExposure exp;
+ FGCTExposure::FGCTExposureItem *exp_item = new FGCTExposure::FGCTExposureItem;
+ if (exp_item)
+ {
+ OFCHECK(exp_item->setCTDIVol(0.1).good());
+ CodeSequenceMacro *phantom_item = new CodeSequenceMacro("113682", "DCM", "ACR Accreditation Phantom - CT");
+ exp_item->getCTDIPhantomTypeCodeSequence().push_back(phantom_item);
+ OFCHECK(exp_item->setExposureInMas(0.3).good());
+ OFCHECK(exp_item->setExposureModulationType("WEIRD").good());
+ OFCHECK(exp_item->setExposureTimeInMs(0.4).good());
+ OFCHECK(exp_item->setImageAndFluoroscopyAreaDoseProduct(0.5).good());
+ OFCHECK(exp_item->setWaterEquivalentDiameter(0.6).good());
+ CodeSequenceMacro *water_code = new CodeSequenceMacro("113987", "DCM", "AAPM 220");
+ exp_item->getWaterEquivalentDiameterCalculationMethodCodeSequence().push_back(water_code);
+ OFCHECK(exp_item->setXRayTubeCurrentInMa(0.7).good());
+ exp.getCTExposureItems().push_back(exp_item);
+ }
+
+ FGCTXRayDetails det;
+ FGCTXRayDetails::FGCTXRayDetailsItem *det_item = new FGCTXRayDetails::FGCTXRayDetailsItem;
+ if (det_item)
+ {
+ OFCHECK(det_item->setCalciumScoringMassFactorDevice(OFVector<Float32>(3, 1)).good());
+ OFCHECK(det_item->setCalciumScoringMassFactorPatient(2).good());
+ OFCHECK(det_item->setEnergyWeightingFactor(3).good());
+ OFCHECK(det_item->setFilterMaterial("FILTER_MATERIAL").good());
+ OFCHECK(det_item->setFilterType("FILTER_TYPE").good());
+ OFCHECK(det_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
+ OFCHECK(det_item->setKVP(5.0).good());
+ det.getCTXRayDetailsItems().push_back(det_item);
+ }
+
+ FGPixelValueTransformation trans;
+ trans.setFGType(FGPixelValueTransformation::E_PixelValTrans_CT);
+ trans.setRescaleIntercept("0");
+ trans.setRescaleSlope("1");
+ trans.setRescaleType("HU");
+
+ FGCTAdditionalXRaySource asrc;
+ FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem *asrc_item = new FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem;
+ if (asrc_item)
+ {
+ OFCHECK(asrc_item->setDataCollectionDiameter(1.0).good());
+ OFCHECK(asrc_item->setEnergyWeightingFactor(2.0).good());
+ OFCHECK(asrc_item->setExposureInmAs(3.0).good());
+ OFCHECK(asrc_item->setFilterMaterial("FILTER_MATERIAL").good());
+ OFCHECK(asrc_item->setFilterType("FILTER_TYPE").good());
+ OFCHECK(asrc_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good());
+ OFCHECK(asrc_item->setKVP(5).good());
+ OFCHECK(asrc_item->setXRayTubeCurrentInmA(6).good());
+ asrc.getCTAdditionalXRaySourceItems().push_back(asrc_item);
+ }
+
+ OFCHECK(ct->addForAllFrames(meas).good());
+ OFCHECK(ct->addForAllFrames(planpo).good());
+ OFCHECK(ct->addForAllFrames(planor).good());
+ OFCHECK(ct->addForAllFrames(ana).good());
+ OFCHECK(ct->addForAllFrames(irr).good());
+ OFCHECK(ct->addForAllFrames(itype).good());
+ OFCHECK(ct->addForAllFrames(atype).good());
+ OFCHECK(ct->addForAllFrames(adetails).good());
+ OFCHECK(ct->addForAllFrames(dyn).good());
+ OFCHECK(ct->addForAllFrames(pos).good());
+ OFCHECK(ct->addForAllFrames(geo).good());
+ OFCHECK(ct->addForAllFrames(rec).good());
+ OFCHECK(ct->addForAllFrames(exp).good());
+ OFCHECK(ct->addForAllFrames(det).good());
+ OFCHECK(ct->addForAllFrames(trans).good());
+ OFCHECK(ct->addForAllFrames(asrc).good());
+}
+
+static void addFrames(EctEnhancedCT *ct)
+{
+ if (!ct)
+ return;
+
+ FGFrameContent *fg = new FGFrameContent();
+ fg->setStackID("1");
+ OFCHECK(fg);
+ if (fg)
+ {
+ EctEnhancedCT::FramesType frames = ct->getFrames();
+ for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++)
+ {
+ OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good());
+ OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good());
+ OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good());
+ OFCHECK(fg->setFrameAcquisitionDuration(0.001).good());
+ OFCHECK(fg->setInStackPositionNumber(frameNo).good());
+ OFCHECK(fg->setDimensionIndexValues(1, 0).good());
+ OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good());
+ OFVector<FGBase *> groups;
+ groups.push_back(fg);
+
+ Uint16 *data = new Uint16[NUM_PIXELS_PER_FRAME];
+ for (size_t i = 0; i < NUM_PIXELS_PER_FRAME; ++i)
+ {
+ data[i] = 0x4141;
+ }
+ OFCHECK(
+ OFget<EctEnhancedCT::Frames<Uint16>>(&frames)->addFrame(data, NUM_PIXELS_PER_FRAME, groups).good());
+ delete[] data;
+ }
+ }
+ delete fg;
+}
+
+static void addDimensions(EctEnhancedCT *ct)
+{
+ if (!ct)
+ return;
+ IODMultiframeDimensionModule &dims = ct->getDimensions();
+ OFCHECK(dims.addDimensionIndex(
+ DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM")
+ .good());
+ OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber,
+ "2.25.30855560781715986879861690673941231222",
+ DCM_FrameContentSequence,
+ "STACK_DIM")
+ .good());
+ OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org(
+ new IODMultiframeDimensionModule::DimensionOrganizationItem);
+ if (org)
+ {
+ org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222");
+ dims.getDimensionOrganizationSequence().push_back(org.release());
+ }
+}
diff --git a/dcmect/tests/tests.cc b/dcmect/tests/tests.cc
index 54a6ca0..8639dc1 100644
--- a/dcmect/tests/tests.cc
+++ b/dcmect/tests/tests.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 2019, OFFIS e.V.
+ * Copyright (C) 2019-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -23,5 +23,6 @@
#include "dcmtk/ofstd/oftest.h"
OFTEST_REGISTER(dcmect_huge_concat);
+OFTEST_REGISTER(dcmect_overflow);
OFTEST_REGISTER(dcmect_roundtrip);
OFTEST_MAIN("dcmect")
--
2.44.0

View File

@@ -1,98 +0,0 @@
From c78e434c0c5f9d932874f0b17a8b4ce305ca01f5 Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <dicom@offis.de>
Date: Wed, 13 Mar 2024 17:15:58 +0100
Subject: [PATCH] Fixed two segmentation faults.
Fixed two segmentations faults that could occur while processing an
invalid incoming DIMSE message due to insufficient error handling
causing a de-referenced NULL pointer.
Thanks to Nils Bars <nils.bars@rub.de> for the bug report and sample files.
This closes DCMTK issue #1114.
---
dcmdata/libsrc/dcelem.cc | 9 ++++++++-
dcmnet/libsrc/dimcmd.cc | 33 ++++++++++++++++++---------------
2 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/dcmdata/libsrc/dcelem.cc b/dcmdata/libsrc/dcelem.cc
index 1524904be..3b9cc2bf7 100644
--- a/dcmdata/libsrc/dcelem.cc
+++ b/dcmdata/libsrc/dcelem.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1994-2023, OFFIS e.V.
+ * Copyright (C) 1994-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -717,6 +717,13 @@ OFCondition DcmElement::loadValue(DcmInputStream *inStream)
if (isStreamNew)
delete readStream;
}
+ else
+ {
+ errorFlag = EC_InvalidStream; // incomplete dataset read from stream
+ DCMDATA_ERROR("DcmElement: " << getTagName() << " " << getTag()
+ << " larger (" << getLengthField() << ") than remaining bytes ("
+ << getTransferredBytes() << ") in file, premature end of stream");
+ }
}
/* return result value */
return errorFlag;
diff --git a/dcmnet/libsrc/dimcmd.cc b/dcmnet/libsrc/dimcmd.cc
index 6dca39546..ffd225f4b 100644
--- a/dcmnet/libsrc/dimcmd.cc
+++ b/dcmnet/libsrc/dimcmd.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1994-2022, OFFIS e.V.
+ * Copyright (C) 1994-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were partly developed by
@@ -205,22 +205,25 @@ getString(DcmDataset *obj, DcmTagKey t, char *s, int maxlen, OFBool *spacePadded
return parseErrorWithMsg("dimcmd:getString: string too small", t);
} else {
ec = elem->getString(aString);
- strncpy(s, aString, maxlen);
- if (spacePadded)
+ if (ec.good())
{
- /* before we remove leading and tailing spaces we want to know
- * whether the string is actually space padded. Required to communicate
- * with dumb peers which send space padded UIDs and fail if they
- * receive correct UIDs back.
- *
- * This test can only detect space padded strings if
- * dcmEnableAutomaticInputDataCorrection is false; otherwise the padding
- * has already been removed by dcmdata at this stage.
- */
- size_t s_len = strlen(s);
- if ((s_len > 0)&&(s[s_len-1] == ' ')) *spacePadded = OFTrue; else *spacePadded = OFFalse;
+ strncpy(s, aString, maxlen);
+ if (spacePadded)
+ {
+ /* before we remove leading and tailing spaces we want to know
+ * whether the string is actually space padded. Required to communicate
+ * with dumb peers which send space padded UIDs and fail if they
+ * receive correct UIDs back.
+ *
+ * This test can only detect space padded strings if
+ * dcmEnableAutomaticInputDataCorrection is false; otherwise the padding
+ * has already been removed by dcmdata at this stage.
+ */
+ size_t s_len = strlen(s);
+ if ((s_len > 0)&&(s[s_len-1] == ' ')) *spacePadded = OFTrue; else *spacePadded = OFFalse;
+ }
+ DU_stripLeadingAndTrailingSpaces(s);
}
- DU_stripLeadingAndTrailingSpaces(s);
}
}
return (ec.good())? ec : DIMSE_PARSEFAILED;
--
2.44.0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
From f192e0cd43af21021454a69016c565b89bfd8e90 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Sat, 11 Jan 2025 17:47:15 +0100
Subject: [PATCH] Replaced call of delete by delete[].
This issue has been reported by the gcc address sanitizer (using option
-fsanitize=address).
---
dcmimgle/libsrc/diimage.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dcmimgle/libsrc/diimage.cc b/dcmimgle/libsrc/diimage.cc
index 1827ac68b..0f5258758 100644
--- a/dcmimgle/libsrc/diimage.cc
+++ b/dcmimgle/libsrc/diimage.cc
@@ -889,7 +889,7 @@ int DiImage::writeBMP(FILE *stream,
result = 1;
}
/* delete pixel data */
- delete OFstatic_cast(char *, data); // type cast necessary to avoid compiler warnings using gcc >2.95
+ delete[] OFstatic_cast(char *, data);
}
return result;
}
--
2.47.1

View File

@@ -1,506 +0,0 @@
From 601b227eecaab33a3a3a11dc256d84b1a62f63af Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <dicom@offis.de>
Date: Mon, 15 Apr 2024 12:19:33 +0200
Subject: [PATCH 2/3] Fixed unchecked typecasts and fixed LUT handling.
This commit adds further fixes for unchecked typecasts of DcmItem::search()
results (see description of previous commit). Furthermore, this commit
specifically addresses the handling of look-up tables (LUTs) in module
dcmpstat, where attribute (0028,3006) LUTData may use either US or OW
value representation, and (0028,3002) LUTDescriptor may be either US or SS.
The code should now properly handle all permitted value representations.
LUTData is now always written as OW in order to avoid the 64k size limit
for US in explicit VR encoding.
Thanks to Martin Zeiser from the Cisco Talos team
<vulndiscovery@external.cisco.com> for the bug report (TALOS-2024-1957).
Together with the previous commit, this closes DCMTK issue #1120.
---
dcmpstat/libsrc/dcmpstat.cc | 40 ++++++++++++++++-------
dcmpstat/libsrc/dvpspl.cc | 34 +++++++++++++------
dcmpstat/libsrc/dvpssv.cc | 34 +++++++++++++------
dcmpstat/libsrc/dvpssvl.cc | 25 +++++++++-----
dcmpstat/libsrc/dvpstat.cc | 65 +++++++++++++++++--------------------
dcmpstat/libsrc/dvpsvl.cc | 19 +++++++++--
6 files changed, 139 insertions(+), 78 deletions(-)
diff --git a/dcmpstat/libsrc/dcmpstat.cc b/dcmpstat/libsrc/dcmpstat.cc
index 4a8e5af6c..a7d11abac 100644
--- a/dcmpstat/libsrc/dcmpstat.cc
+++ b/dcmpstat/libsrc/dcmpstat.cc
@@ -384,12 +384,16 @@ OFCondition DcmPresentationState::read(DcmItem &dset)
{
item = seq->getItem(0);
stack.clear();
- // LUTDescriptor can be US or SS. For now we only handle US.
+
+ // LUTDescriptor can be US or SS
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTDescriptor.getTag(),
- stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
{
- modalityLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *mLUTDescriptor = &modalityLUTDescriptor;
+ mLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
}
+
stack.clear();
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTExplanation.getTag(),
stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_LO))
@@ -400,9 +404,11 @@ OFCondition DcmPresentationState::read(DcmItem &dset)
// LUTData can be OW, US or SS. For now we only handle US.
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTData.getTag(),
- stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
{
- modalityLUTData = *((DcmUnsignedShort *)(stack.top()));
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *mdata = &modalityLUTData;
+ mdata->operator=(*(DcmElement *)(stack.top()));
}
stack.clear();
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTType.getTag(),
@@ -879,11 +885,13 @@ OFCondition DcmPresentationState::createFromImage(
{
item = seq->getItem(0);
stack.clear();
- // LUTDescriptor can be US or SS. For now we only handle US.
+ // LUTDescriptor can be US or SS
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTDescriptor.getTag(),
- stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
{
- modalityLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *mLUTDescriptor = &modalityLUTDescriptor;
+ mLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
}
stack.clear();
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTExplanation.getTag(),
@@ -895,9 +903,11 @@ OFCondition DcmPresentationState::createFromImage(
// LUTData can be OW, US or SS. For now we only handle US.
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTData.getTag(),
- stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
{
- modalityLUTData = *((DcmUnsignedShort *)(stack.top()));
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *mdata = &modalityLUTData;
+ mdata->operator=(*(DcmElement *)(stack.top()));
}
stack.clear();
if ((EC_Normal == item->search((DcmTagKey &)modalityLUTType.getTag(),
@@ -1247,10 +1257,16 @@ OFCondition DcmPresentationState::write(DcmItem &dset, OFBool replaceSOPInstance
dseq = new DcmSequenceOfItems(DCM_ModalityLUTSequence);
if (dseq)
{
- delem = new DcmUnsignedShort(modalityLUTDescriptor);
+ // we clone modalityLUTDescriptor in order to retain the VR (US or SS)
+ delem = OFstatic_cast(DcmElement *, modalityLUTDescriptor.clone());
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
- delem = new DcmUnsignedShort(modalityLUTData);
+
+ // we write LUTData as OW in order to avoid the 64 kByte limit for US
+ delem = new DcmOtherByteOtherWord(DCM_LUTData);
+ delem->operator=(modalityLUTData);
+ OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
delem = new DcmLongString(modalityLUTType);
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
if (modalityLUTExplanation.getLength() >0)
diff --git a/dcmpstat/libsrc/dvpspl.cc b/dcmpstat/libsrc/dvpspl.cc
index ec4cccf97..f5574ab33 100644
--- a/dcmpstat/libsrc/dvpspl.cc
+++ b/dcmpstat/libsrc/dvpspl.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1999-2018, OFFIS e.V.
+ * Copyright (C) 1999-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -24,6 +24,7 @@
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcsequen.h"
#include "dcmtk/dcmdata/dcvrcs.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
#include "dcmtk/dcmpstat/dvpspl.h"
#include "dcmtk/dcmpstat/dvpsdef.h" /* for constants and macros */
#include "dcmtk/dcmnet/dimse.h"
@@ -79,29 +80,36 @@ OFCondition DVPSPresentationLUT::read(DcmItem &dset, OFBool withSOPInstance)
if (result==EC_Normal)
{
stack.clear();
- if (EC_Normal == dset.search(DCM_PresentationLUTSequence, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dset.search(DCM_PresentationLUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
{
seq=(DcmSequenceOfItems *)stack.top();
if (seq->card() ==1)
{
item = seq->getItem(0);
stack.clear();
- if (EC_Normal == item->search((DcmTagKey &)presentationLUTDescriptor.getTag(),
- stack, ESM_fromHere, OFFalse))
+
+ // LUTDescriptor can be US or SS
+ if ((EC_Normal == item->search((DcmTagKey &)presentationLUTDescriptor.getTag(),
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
{
- presentationLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *pLUTDescriptor = &presentationLUTDescriptor;
+ pLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
}
+
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)presentationLUTExplanation.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
{
presentationLUTExplanation = *((DcmLongString *)(stack.top()));
}
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)presentationLUTData.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
{
- presentationLUTData = *((DcmUnsignedShort *)(stack.top()));
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *pldata = &presentationLUTData;
+ pldata->operator=(*(DcmElement *)(stack.top()));
}
} else {
result=EC_TagNotFound;
@@ -187,10 +195,16 @@ OFCondition DVPSPresentationLUT::write(DcmItem &dset, OFBool withSOPInstance)
dseq = new DcmSequenceOfItems(DCM_PresentationLUTSequence);
if (dseq)
{
- delem = new DcmUnsignedShort(presentationLUTDescriptor);
+ // we clone presentationLUTDescriptor in order to retain the VR (US or SS)
+ delem = OFstatic_cast(DcmElement *, presentationLUTDescriptor.clone());
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
- delem = new DcmUnsignedShort(presentationLUTData);
+
+ // we write LUTData as OW in order to avoid the 64 kByte limit for US
+ delem = new DcmOtherByteOtherWord(DCM_LUTData);
+ delem->operator=(presentationLUTData);
+ OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
if (presentationLUTExplanation.getLength() >0)
{
delem = new DcmLongString(presentationLUTExplanation);
diff --git a/dcmpstat/libsrc/dvpssv.cc b/dcmpstat/libsrc/dvpssv.cc
index 8e3d49bd4..4a7fd0e30 100644
--- a/dcmpstat/libsrc/dvpssv.cc
+++ b/dcmpstat/libsrc/dvpssv.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1998-2018, OFFIS e.V.
+ * Copyright (C) 1998-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -23,6 +23,7 @@
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dcsequen.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
#include "dcmtk/dcmpstat/dvpssv.h"
#include "dcmtk/dcmpstat/dvpsri.h" /* for DVPSReferencedImage */
#include "dcmtk/dcmpstat/dvpsrsl.h" /* DVPSReferencedSeries_PList */
@@ -75,29 +76,36 @@ OFCondition DVPSSoftcopyVOI::read(DcmItem &dset)
if (result==EC_Normal)
{
stack.clear();
- if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
{
seq=(DcmSequenceOfItems *)stack.top();
if (seq->card() ==1)
{
item = seq->getItem(0);
stack.clear();
- if (EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
- stack, ESM_fromHere, OFFalse))
+
+ // LUTDescriptor can be US or SS
+ if ((EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
{
- voiLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+ vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
}
+
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
{
voiLUTExplanation = *((DcmLongString *)(stack.top()));
}
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
{
- voiLUTData = *((DcmUnsignedShort *)(stack.top()));
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *vldata = &voiLUTData;
+ vldata->operator=(*(DcmElement *)(stack.top()));
}
} else {
result=EC_TagNotFound;
@@ -177,10 +185,16 @@ OFCondition DVPSSoftcopyVOI::write(DcmItem &dset)
dseq = new DcmSequenceOfItems(DCM_VOILUTSequence);
if (dseq)
{
- delem = new DcmUnsignedShort(voiLUTDescriptor);
+ // we clone voiLUTDescriptor in order to retain the VR (US or SS)
+ delem = OFstatic_cast(DcmElement *, voiLUTDescriptor.clone());
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
- delem = new DcmUnsignedShort(voiLUTData);
+
+ // we write LUTData as OW in order to avoid the 64 kByte limit for US
+ delem = new DcmOtherByteOtherWord(DCM_LUTData);
+ delem->operator=(voiLUTData);
+ OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
if (voiLUTExplanation.getLength() >0)
{
delem = new DcmLongString(voiLUTExplanation);
diff --git a/dcmpstat/libsrc/dvpssvl.cc b/dcmpstat/libsrc/dvpssvl.cc
index d1532db5c..efcb6a26b 100644
--- a/dcmpstat/libsrc/dvpssvl.cc
+++ b/dcmpstat/libsrc/dvpssvl.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1999-2023, OFFIS e.V.
+ * Copyright (C) 1999-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -72,7 +72,7 @@ OFCondition DVPSSoftcopyVOI_PList::read(DcmItem &dset)
DcmSequenceOfItems *dseq=NULL;
DcmItem *ditem=NULL;
- if (EC_Normal == dset.search(DCM_SoftcopyVOILUTSequence, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dset.search(DCM_SoftcopyVOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
{
dseq=(DcmSequenceOfItems *)stack.top();
if (dseq)
@@ -249,29 +249,36 @@ OFCondition DVPSSoftcopyVOI_PList::createFromImage(
if (result==EC_Normal)
{
stack.clear();
- if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
{
seq=(DcmSequenceOfItems *)stack.top();
if (seq->card() > 0)
{
item = seq->getItem(0);
stack.clear();
- if (EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
- stack, ESM_fromHere, OFFalse))
+
+ // LUTDescriptor can be US or SS
+ if ((EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
{
- voiLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+ vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
}
+
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
{
voiLUTExplanation = *((DcmLongString *)(stack.top()));
}
stack.clear();
if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(),
- stack, ESM_fromHere, OFFalse))
+ stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
{
- voiLUTData = *((DcmUnsignedShort *)(stack.top()));
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *vldata = &voiLUTData;
+ vldata->operator=(*(DcmElement *)(stack.top()));
}
} else result=EC_TagNotFound;
}
diff --git a/dcmpstat/libsrc/dvpstat.cc b/dcmpstat/libsrc/dvpstat.cc
index ce2f5ad5f..4bfe8f9cb 100644
--- a/dcmpstat/libsrc/dvpstat.cc
+++ b/dcmpstat/libsrc/dvpstat.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright (C) 1998-2021, OFFIS e.V.
+ * Copyright (C) 1998-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
@@ -578,14 +578,14 @@ OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transfe
currentImageSelectedFrame = 1; // default: first frame
// get Modality
- if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_CS))
{
currentImageModality = *((DcmCodeString *)(stack.top()));
}
stack.clear();
// determine default Presentation LUT Shape
- if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse))
+ if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_CS))
{
DcmCodeString *photometricInterpretation = (DcmCodeString *)(stack.top());
if (photometricInterpretation->getVM() == 1)
@@ -598,12 +598,12 @@ OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transfe
stack.clear();
// get SOP class UID and SOP instance UID.
- if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)))
+ if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_UI))
{
result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPClassUID);
}
stack.clear();
- if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)))
+ if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_UI))
{
result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPInstanceUID);
}
@@ -1124,40 +1124,36 @@ OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApp
numEntries16 = (Uint16)numberOfEntries;
/* LUT Descriptor */
- DcmElement *lutDescriptor = NULL;
- if (firstMapped < 0)
+ DcmUnsignedShort *lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
+ if (lutDescriptor == NULL) status = EC_MemoryExhausted;
+ else
{
- // LUT Descriptor is SS
- lutDescriptor = new DcmSignedShort(DcmTag(DCM_LUTDescriptor, EVR_SS));
- if (lutDescriptor != NULL)
+ if (firstMapped < 0)
{
- status = lutDescriptor->putSint16((Sint16)numEntries16, 0);
- if (EC_Normal == status)
- status = lutDescriptor->putSint16((Sint16)firstMapped, 1);
- if (EC_Normal == status)
- status = lutDescriptor->putSint16((Sint16)numberOfBits, 2);
- } else
- status = EC_MemoryExhausted;
- } else {
- // LUT Descriptor is US
- lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
- if (lutDescriptor != NULL)
- {
- status = lutDescriptor->putUint16(numEntries16, 0);
- if (EC_Normal == status)
- status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
- if (EC_Normal == status)
- status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
- } else
- status = EC_MemoryExhausted;
+ // LUT Descriptor is SS
+ DcmSignedShort ldesc(DcmTag(DCM_LUTDescriptor, EVR_SS));
+ status = ldesc.putSint16((Sint16)numEntries16, 0);
+ if (EC_Normal == status) status = ldesc.putSint16((Sint16)firstMapped, 1);
+ if (EC_Normal == status) status = ldesc.putSint16((Sint16)numberOfBits, 2);
+ if (EC_Normal == status)
+ {
+ // copy content of SS element into DcmUnsignedShort using DcmElement::operator=
+ DcmElement *ld = lutDescriptor;
+ ld->operator=(ldesc);
+ }
+ } else {
+ // LUT Descriptor is US
+ status = lutDescriptor->putUint16(numEntries16, 0);
+ if (EC_Normal == status) status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
+ if (EC_Normal == status) status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
+ }
}
/* LUT Data */
- DcmElement *lutData = NULL;
+ DcmUnsignedShort *lutData = NULL;
if (status == EC_Normal)
{
- // LUT Data as OW, because of max size = 64K
- lutData = new DcmOtherByteOtherWord(DcmTag(DCM_LUTData, EVR_OW));
+ lutData = new DcmUnsignedShort(DcmTag(DCM_LUTData, EVR_US));
if (lutData != NULL)
status = lutData->putUint16Array(data, numberOfEntries);
else
@@ -1186,15 +1182,14 @@ OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApp
if (status == EC_Normal)
{
if ((lutDescriptor != NULL) && (lutData != NULL) && (lutExplanation != NULL))
- status = setVOILUT(*(DcmUnsignedShort *)lutDescriptor, *(DcmUnsignedShort *)lutData, *lutExplanation, applicability);
+ status = setVOILUT(*lutDescriptor, *lutData, *lutExplanation, applicability);
}
/* delete temporary dcmtk structures */
delete lutDescriptor;
delete lutData;
delete lutExplanation;
- } else
- status = EC_MemoryExhausted;
+ } else status = EC_MemoryExhausted;
delete[] data;
}
return status;
diff --git a/dcmpstat/libsrc/dvpsvl.cc b/dcmpstat/libsrc/dvpsvl.cc
index b10b83f20..fdba0a0e0 100644
--- a/dcmpstat/libsrc/dvpsvl.cc
+++ b/dcmpstat/libsrc/dvpsvl.cc
@@ -59,9 +59,24 @@ OFCondition DVPSVOILUT::read(DcmItem &dset)
OFCondition result = EC_Normal;
DcmStack stack;
- READ_FROM_DATASET(DcmUnsignedShort, EVR_US, voiLUTDescriptor)
+ // LUTDescriptor can be US or SS
+ if ((EC_Normal == dset.search((DcmTagKey &)voiLUTDescriptor.getTag(),
+ stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
+ {
+ // We explicitly use DcmElement::operator=(), which works for US and SS
+ DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+ vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
+ }
+
READ_FROM_DATASET(DcmLongString, EVR_LO, voiLUTExplanation)
- READ_FROM_DATASET(DcmUnsignedShort, EVR_US, voiLUTData)
+
+ stack.clear();
+ if ((EC_Normal == dset.search((DcmTagKey &)voiLUTData.getTag(), stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
+ {
+ // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+ DcmElement *vldata = &voiLUTData;
+ vldata->operator=(*(DcmElement *)(stack.top()));
+ }
if (EC_Normal == result)
{
--
2.44.0

View File

@@ -1,85 +0,0 @@
From 7d54f8efec995e5601d089fa17b0625c2b41af23 Mon Sep 17 00:00:00 2001
From: Joerg Riesmeier <dicom@jriesmeier.com>
Date: Mon, 22 Apr 2024 12:11:11 +0200
Subject: [PATCH 3/3] Fixed wrong error handling (previous commit).
Fixed wrong error handling introduced with the previous commit.
---
dcmrt/libsrc/drttypes.cc | 6 +++---
dcmsr/libsrc/dsrtypes.cc | 32 ++++++++++++++++++++------------
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/dcmrt/libsrc/drttypes.cc b/dcmrt/libsrc/drttypes.cc
index 77ff1674c..097ab9727 100644
--- a/dcmrt/libsrc/drttypes.cc
+++ b/dcmrt/libsrc/drttypes.cc
@@ -210,11 +210,11 @@ OFCondition DRTTypes::getAndCheckStringValueFromDataset(DcmItem &dataset,
{
DcmStack stack;
OFCondition result = dataset.search(tagKey, stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
- if (result.good() && stack.top()->isElement())
+ if (result.good())
{
- DcmElement *element = OFstatic_cast(DcmElement *, stack.top());
- if (element != NULL)
+ if (stack.top()->isElement())
{
+ DcmElement *element = OFstatic_cast(DcmElement *, stack.top());
if (checkElementValue(*element, vm, type, result, moduleName))
result = element->getOFString(stringValue, 0);
else
diff --git a/dcmsr/libsrc/dsrtypes.cc b/dcmsr/libsrc/dsrtypes.cc
index a9d621859..166bfabff 100644
--- a/dcmsr/libsrc/dsrtypes.cc
+++ b/dcmsr/libsrc/dsrtypes.cc
@@ -1178,13 +1178,17 @@ OFCondition DSRTypes::getAndCheckElementFromDataset(DcmItem &dataset,
DcmStack stack;
const DcmTagKey tagKey = delem.getTag();
OFCondition result = dataset.search(tagKey, stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
- if (result.good() && stack.top()->isElement())
+ if (result.good())
{
- /* copy object from search stack */
- result = delem.copyFrom(*stack.top());
- /* we need a reference to the original element in order to determine the SpecificCharacterSet */
- if (!checkElementValue(OFstatic_cast(DcmElement *, stack.top()), tagKey, vm, type, result, moduleName, acceptViolation))
- result = SR_EC_InvalidValue;
+ if (stack.top()->isElement())
+ {
+ /* copy object from search stack */
+ result = delem.copyFrom(*stack.top());
+ /* we need a reference to the original element in order to determine the SpecificCharacterSet */
+ if (!checkElementValue(OFstatic_cast(DcmElement *, stack.top()), tagKey, vm, type, result, moduleName, acceptViolation))
+ result = SR_EC_InvalidValue;
+ } else
+ result = EC_CorruptedData;
}
/* the element could not be found in the dataset */
else if (!checkElementValue(delem, vm, type, result, moduleName, acceptViolation))
@@ -1203,13 +1207,17 @@ OFCondition DSRTypes::getAndCheckStringValueFromDataset(DcmItem &dataset,
{
DcmStack stack;
OFCondition result = dataset.search(tagKey, stack, ESM_fromHere, OFFalse /*searchIntoSub*/);
- if (result.good() && stack.top()->isElement())
+ if (result.good())
{
- DcmElement *delem = OFstatic_cast(DcmElement *, stack.top());
- /* we need a reference to the original element in order to determine the SpecificCharacterSet */
- if (!checkElementValue(delem, tagKey, vm, type, result, moduleName, acceptViolation))
- result = SR_EC_InvalidValue;
- delem->getOFString(stringValue, 0);
+ if (stack.top()->isElement())
+ {
+ DcmElement *delem = OFstatic_cast(DcmElement *, stack.top());
+ /* we need a reference to the original element in order to determine the SpecificCharacterSet */
+ if (!checkElementValue(delem, tagKey, vm, type, result, moduleName, acceptViolation))
+ result = SR_EC_InvalidValue;
+ delem->getOFString(stringValue, 0);
+ } else
+ result = EC_CorruptedData;
} else {
if ((type == "1") || (type == "2"))
{
--
2.44.0

49
CVE-2025-2357.patch Normal file
View File

@@ -0,0 +1,49 @@
From 69a6690db71927e02a6fb6ee655cb449f0431466 Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <eichelberg@offis.de>
Date: Mon, 3 Mar 2025 12:33:18 +0100
Subject: [PATCH] Fixed segfault in JPEG-LS decoder.
Fixed a bug in the JPEG-LS decoder that led to a segmentation fault if invalid
input data was processed, due to insufficient validation of input data.
Thanks to Ding zhengzheng <xiaozheng.ding399@gmail.com> for the report
and the sample file (PoC).
This closes DCMTK issue #1155.
---
dcmjpls/libcharls/scan.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dcmjpls/libcharls/scan.h b/dcmjpls/libcharls/scan.h
index b4dea20..d6dfa5a 100644
--- a/dcmjpls/libcharls/scan.h
+++ b/dcmjpls/libcharls/scan.h
@@ -629,14 +629,24 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*)
LONG index = 0;
LONG Rb = _previousLine[index-1];
LONG Rd = _previousLine[index];
+ LONG RANGE_UPPER = 1 << traits.bpp;
+ LONG RANGE_LOWER = - RANGE_UPPER;
while(index < _width)
- {
+ {
LONG Ra = _currentLine[index -1];
LONG Rc = Rb;
Rb = Rd;
Rd = _previousLine[index + 1];
+ // make sure that values are not out of range
+ if ( (Rd - Rb < RANGE_LOWER) || (Rd - Rb > RANGE_UPPER)
+ || (Rb - Rc < RANGE_LOWER) || (Rb - Rc > RANGE_UPPER)
+ || (Rc - Ra < RANGE_LOWER) || (Rc - Ra > RANGE_UPPER))
+ {
+ throw JlsException(InvalidCompressedData);
+ }
+
LONG Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra));
if (Qs != 0)
--
2.48.1

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:232076655503138debf2f624109f1799e539354f186ce4e04b27cf82a9d8720f
size 9628364

3
dcmtk-3.6.9.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b93ff5561244916a6e1e7e3ecccf2e26e6932c4edb5961268401cea7d4ab9c16
size 9628334

View File

@@ -10,7 +10,7 @@ This prevents installing the devel package without requiring the dcmtk utilities
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/CMake/GenerateCMakeExports.cmake b/CMake/GenerateCMakeExports.cmake
index 4512624..11205e3 100644
index b4f44e4..0e3cc3c 100644
--- a/CMake/GenerateCMakeExports.cmake
+++ b/CMake/GenerateCMakeExports.cmake
@@ -18,8 +18,8 @@
@@ -25,10 +25,10 @@ index 4512624..11205e3 100644
# Get and store libraries to DCMTKTargets.cmake within the build's main dir
get_property(DCMTK_LIBRARY_TARGETS GLOBAL PROPERTY DCMTK_LIBRARY_TARGETS)
diff --git a/CMake/dcmtkMacros.cmake b/CMake/dcmtkMacros.cmake
index 6cbce0a..0844e58 100644
index bd35469..b318a56 100644
--- a/CMake/dcmtkMacros.cmake
+++ b/CMake/dcmtkMacros.cmake
@@ -64,7 +64,7 @@ macro(DCMTK_ADD_EXECUTABLE PROGRAM)
@@ -63,7 +63,7 @@ macro(DCMTK_ADD_EXECUTABLE PROGRAM)
# declare installation files, also export DCMTKTargets.cmake
install(TARGETS ${PROGRAM}
@@ -37,6 +37,3 @@ index 6cbce0a..0844e58 100644
COMPONENT bin
DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
--
2.37.1

View File

@@ -1,10 +1,57 @@
-------------------------------------------------------------------
Mon Mar 17 10:31:13 UTC 2025 - Christophe Marin <christophe@krop.fr>
- Add upstream change (CVE-2025-2357, boo#1239679)
* CVE-2025-2357.patch
-------------------------------------------------------------------
Wed Feb 19 14:09:24 UTC 2025 - Christophe Marin <christophe@krop.fr>
- Add patches:
* 0001-Fixed-another-issue-with-invalid-mono-images.patch
(CVE-2025-25472, boo#1237369)
* 0001-Fixed-another-issue-with-invalid-DICOM-images.patch
(CVE-2025-25474, boo#1237365)
* 0001-Fixed-issue-with-invalid-RLE-compressed-DICOM-images.patch
(CVE-2025-25475, boo#1237355)
-------------------------------------------------------------------
Mon Jan 13 18:43:39 UTC 2025 - Christophe Marin <christophe@krop.fr>
- Update to 3.6.9. See DOCS/CHANGES.368 for the full list of changes
- Drop patches, merged upstream:
* 0001-Fixed-buffer-overflow-in-decompression-codecs.patch
* 0001-Fixed-possible-overflows-when-allocating-memory.patch
* 0001-Fixed-two-segmentation-faults.patch
* 0001-Fixed-unchecked-typecasts-of-DcmItem-search-results.patch
* 0002-Fixed-unchecked-typecasts-and-fixed-LUT-handling.patch
* 0003-Fixed-wrong-error-handling-previous-commit.patch
* 0001-Fixed-DcmDecimalString-unit-tests.patch
* 0001-Fixed-link-instructions-for-libtiff.patch
* 0001-Fix-find_package-library-variables-for-libtiff.patch
- Add patches:
* 0001-Added-check-to-make-sure-HighBit-BitsAllocated.patch
(CVE-2024-52333, boo#1235811)
* 0001-Replaced-call-of-delete-by-delete.patch
* 0001-Fixed-issue-rendering-invalid-monochrome-image.patch
(CVE-2024-47796, boo#1235810)
-------------------------------------------------------------------
Wed Nov 20 16:59:26 UTC 2024 - Christophe Marin <christophe@krop.fr>
- Add patches:
* 0001-Fixed-link-instructions-for-libtiff.patch
* 0001-Fix-find_package-library-variables-for-libtiff.patch
-------------------------------------------------------------------
Wed Apr 24 07:45:23 UTC 2024 - Christophe Marin <christophe@krop.fr>
- Add upstream changes:
* 0001-Fixed-buffer-overflow-in-decompression-codecs.patch
* 0001-Fixed-possible-overflows-when-allocating-memory.patch
(boo#1227235, CVE-2024-27628)
* 0001-Fixed-two-segmentation-faults.patch
(boo#1223949, CVE-2024-34509, boo#1223925, CVE-2024-34508)
* 0001-Fixed-unchecked-typecasts-of-DcmItem-search-results.patch
* 0002-Fixed-unchecked-typecasts-and-fixed-LUT-handling.patch
(boo#1223324, CVE-2024-28130)

View File

@@ -16,24 +16,28 @@
#
%define abiversion 18
%define abiversion 19
Name: dcmtk
Version: 3.6.8
Version: 3.6.9
Release: 0
Summary: DICOM Toolkit
License: Apache-2.0 AND BSD-3-Clause
URL: https://dicom.offis.de/dcmtk.php.en
Source0: ftp://dicom.offis.de/pub/dicom/offis/software/dcmtk/release/%{name}-%{version}.tar.gz
Source0: https://dicom.offis.de/download/dcmtk/dcmtk369/%{name}-%{version}.tar.gz
# PATCH-FIX-OPENSUSE dcmtk-fix-DCMTKTargets.cmake.patch -- Do not track executables to be able to use dcmtk-devel without dcmtk package
Patch0: dcmtk-fix-DCMTKTargets.cmake.patch
# PATCH-FIX-UPSTREAM
Patch1: 0001-Fixed-buffer-overflow-in-decompression-codecs.patch
Patch2: 0001-Fixed-possible-overflows-when-allocating-memory.patch
Patch3: 0001-Fixed-two-segmentation-faults.patch
Patch4: 0001-Fixed-unchecked-typecasts-of-DcmItem-search-results.patch
Patch5: 0002-Fixed-unchecked-typecasts-and-fixed-LUT-handling.patch
Patch6: 0003-Fixed-wrong-error-handling-previous-commit.patch
Patch7: 0001-Fixed-DcmDecimalString-unit-tests.patch
Patch1: 0001-Added-check-to-make-sure-HighBit-BitsAllocated.patch
Patch2: 0001-Replaced-call-of-delete-by-delete.patch
Patch3: 0001-Fixed-issue-rendering-invalid-monochrome-image.patch
# CVE-2025-25472
Patch4: 0001-Fixed-another-issue-with-invalid-mono-images.patch
# CVE-2025-25474
Patch5: 0001-Fixed-another-issue-with-invalid-DICOM-images.patch
# CVE-2025-25475
Patch6: 0001-Fixed-issue-with-invalid-RLE-compressed-DICOM-images.patch
# CVE-2025-2357
Patch7: CVE-2025-2357.patch
BuildRequires: cmake
BuildRequires: doxygen
BuildRequires: fdupes
@@ -86,7 +90,8 @@ parts the DICOM standard.
-DDCMTK_WITH_XML=ON \
-DDCMTK_WITH_OPENSSL=ON \
-DDCMTK_WITH_SNDFILE=ON \
-DDCMTK_WITH_ZLIB=ON}
-DDCMTK_WITH_ZLIB=ON \
-DCMAKE_INSTALL_SYSCONFDIR=%{_sysconfdir}}
%cmake_build
@@ -121,7 +126,6 @@ install -pm 0644 README %{buildroot}%{_docdir}/dcmtk/
%{_mandir}/man1/*
%files devel
%license COPYRIGHT
%{_includedir}/dcmtk/
%{_libdir}/*.so
%{_libdir}/cmake/dcmtk/