[med-svn] [Git][med-team/gdcm][debian/bullseye] 2 commits: d/patches/CVE-2025-11266: refresh patch

Emmanuel Arias (@eamanu) gitlab at salsa.debian.org
Fri Jun 19 14:04:52 BST 2026



Emmanuel Arias pushed to branch debian/bullseye at Debian Med / gdcm


Commits:
73d6c350 by Emmanuel Arias at 2026-06-18T08:29:46-03:00
d/patches/CVE-2025-11266: refresh patch

- - - - -
5c0fdae8 by Emmanuel Arias at 2026-06-19T10:04:03-03:00
Non-maintainer upload by the LTS Team.

* Non-maintainer upload by the LTS Team.
* CVE-2025-11266: Avoid out-of-bounds vulnerability. The issue
  unsigned integer underflow in buffer indexing (Closes: #1122862).
* CVE-2025-52582: Add patch to prevent overlay extraction in case of
  malformed overlay or image information (Closes: #1123576).
* CVE-2025-48429: Add patch to refactor the RLE header to ensure it
  conforms to the DICOM standard (Closes: #1123589).
* CVE-2025-53618 and CVE-2025-53619: Add patch to add a frame size
  check to ensure that the provided data corresponds to the buffer
  size (Closes: #1123587).
* CVE-2026-3650: Add patch to reject Value Length exceeding stream
  size (Closes: #1132042).

- - - - -


7 changed files:

- debian/changelog
- debian/patches/CVE-2025-11266.patch
- + debian/patches/CVE-2025-48429.patch
- + debian/patches/CVE-2025-52582.patch
- + debian/patches/CVE-2025-53618_CVE-2025-53619.patch
- + debian/patches/CVE-2026-3650.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,6 +1,6 @@
 gdcm (3.0.8-2+deb11u1) bullseye-security; urgency=medium
 
-  * Non-maintainer upload by the LTS Security Team.
+  * Non-maintainer upload by the LTS Team.
 
   [ Étienne Mollier ]
   * CVE-2024-*.patch: new: fix multiple security issues.
@@ -8,11 +8,20 @@ gdcm (3.0.8-2+deb11u1) bullseye-security; urgency=medium
     CVE-2024-25569. (Closes: #1070387)
 
   [ Emmanuel Arias ]
-  * CVE-2025-11266.patch: Avoid out-of-bounds vulnerability. The issue
+  * CVE-2025-11266: Avoid out-of-bounds vulnerability. The issue
     was triggered during parsing of a malformed DICOM file containing
     encapsulated PixelData fragments. This vulnerability leads to a
     segmentation fault caused by an out-of-bounds memory access due to
-    unsigned integer underflow in buffer indexing.
+    unsigned integer underflow in buffer indexing (Closes: #1122862).
+  * CVE-2025-52582: Add patch to prevent overlay extraction in case of
+    malformed overlay or image information (Closes: #1123576).
+  * CVE-2025-48429: Add patch to refactor the RLE header to ensure it
+    conforms to the DICOM standard (Closes: #1123589).
+  * CVE-2025-53618 and CVE-2025-53619: Add patch to add a frame size
+    check to ensure that the provided data corresponds to the buffer
+    size (Closes: #1123587).
+  * CVE-2026-3650: Add patch to reject Value Length exceeding stream
+    size (Closes: #1132042).
 
  -- Emmanuel Arias <eamanu at debian.org>  Sat, 20 Dec 2025 14:11:38 -0300
 
@@ -30,7 +39,7 @@ gdcm (3.0.8-1) unstable; urgency=medium
   [ Gert Wollny ]
   * New upstream version 3.0.8
 
-  [ Alexander Volkov ] 
+  [ Alexander Volkov ]
   * debian/{rules, control}: Don't build CLI bindings when the "nocil" build
     profile is enabled
 


=====================================
debian/patches/CVE-2025-11266.patch
=====================================
@@ -16,11 +16,9 @@ Bug-Debian: htts://bugs.debian.org/1122862
  .../gdcmSequenceOfFragments.h                                   | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h
-index 269b2ae75..5ee35f2ff 100644
 --- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h
 +++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h
-@@ -237,7 +237,7 @@ std::istream& ReadValue(std::istream &is, bool /*readvalues*/)
+@@ -237,7 +237,7 @@
        const size_t lastf = Fragments.size() - 1;
        const ByteValue *bv = Fragments[ lastf ].GetByteValue();
        const char *a = bv->GetPointer();
@@ -28,4 +26,4 @@ index 269b2ae75..5ee35f2ff 100644
 +      gdcmAssertAlwaysMacro( bv->GetLength() >= 3 && (unsigned char)a[ bv->GetLength() - 3 ] == 0xfe );
        Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 3 );
        is.seekg( -11, std::ios::cur );
-       gdcm_assert( is.good() );
+       assert( is.good() );


=====================================
debian/patches/CVE-2025-48429.patch
=====================================
@@ -0,0 +1,189 @@
+From: pierre <pierre at intradys.com>
+Date: Thu, 8 Jan 2026 10:36:10 +0100
+Subject: [PATCH] Refactor the RLE header to ensure it conforms to the DICOM
+ standard.
+
+Origin: https://github.com/malaterre/GDCM/commit/0393310f8bb27c3bec8b67c6bfb18f71f6a15bb8
+Bug-Debian: https://bugs.debian.org/1123589
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-48429
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-48429
+---
+ .../gdcmRLECodec.cxx                          | 105 +++++++++++++-----
+ 1 file changed, 76 insertions(+), 29 deletions(-)
+
+--- a/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx
++++ b/Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx
+@@ -24,6 +24,7 @@
+ #include <algorithm> // req C++11
+ #include <stddef.h> // ptrdiff_t fix
+ #include <cstring>
++#include <array>
+ 
+ #include <gdcmrle/rle.h>
+ 
+@@ -33,37 +34,73 @@
+ // TODO ideally this code should be in utilities for ease of reuse
+ class RLEHeader
+ {
+-public:
++private:
+   uint32_t NumSegments;
+   uint32_t Offset[15];
++public:
++  uint32_t GetNumSegments() const { return NumSegments; }
++  bool SetNumSegments(uint32_t num) 
++    { 
++      if (num > 15) 
++        {
++          gdcmErrorMacro("Number of segments cannot be bigger than 15");
++          return false;
++        }
++      NumSegments = num;
++      return true;
++    };
++  bool SetOffset(const std::array<uint32_t, 15> &offset) 
++    {
++      std::copy(offset.begin(), offset.end(), Offset);
++      return true;
++    };
++  uint32_t GetOffset(size_t index) const 
++    {
++      if (index < 15) return Offset[index];
++      return 0;
++    };
++  bool SetOffset(size_t index, uint32_t value) {
++    if (index >= 15) return false;
++    Offset[index] = value;
++    return true;
++  }
+ 
+-  void Print(std::ostream &os)
++  bool Read(std::istream &is) 
+     {
+-    os << "NumSegments:" << NumSegments << "\n";
+-    for(int i=0; i<15; ++i)
+-      {
+-      os << i << ":" << Offset[i] << "\n";
++      // read Header (64 bytes)
++      uint32_t buffer[16] = {0};
++      is.read(reinterpret_cast<char *>(buffer), 64);
++      if (static_cast<size_t>(is.gcount()) != 64) 
++        {
++          gdcmErrorMacro("RLE Header truncated: expected 64 bytes, got " << is.gcount());
++          return false;
++        }
++      assert(sizeof(uint32_t) * 16 == 64);
++      SwapperNoOp::SwapArray(reinterpret_cast<uint32_t *>(buffer), 16);
++      if (!SetNumSegments(buffer[0])) return false;
++      memcpy(Offset, &buffer[1], sizeof(uint32_t) * 15);
++      if (NumSegments >= 1) {
++        if (Offset[0] != 64) return false;
++      }
++      // We just check that we are indeed at the proper position start+64
++      return true;
++    }
++  void Print(std::ostream &os) 
++    {
++      os << "NumSegments:" << NumSegments << "\n";
++      for (int i = 0; i < 15; ++i) {
++        os << i << ":" << Offset[i] << "\n";
+       }
+     }
+ };
+ 
++static_assert(sizeof(RLEHeader) == 64, "RLEHeader size must be 64 bits to comply with dicom standard");
+ class RLEFrame
+ {
+ public:
+   bool Read(std::istream &is)
+     {
+-    // read Header (64 bytes)
+-    is.read((char*)(&Header), sizeof(uint32_t)*16);
+-    assert( sizeof(uint32_t)*16 == 64 );
+-    assert( sizeof(RLEHeader) == 64 );
+-    SwapperNoOp::SwapArray((uint32_t*)&Header,16);
+-    uint32_t numSegments = Header.NumSegments;
+-    if( numSegments >= 1 )
+-      {
+-      if( Header.Offset[0] != 64 ) return false;
+-      }
+-    // We just check that we are indeed at the proper position start+64
+-    return true;
++      return Header.Read(is);
+     }
+   void Print(std::ostream &os)
+     {
+@@ -379,7 +416,9 @@
+     assert( MaxNumSegments % 3 == 0 );
+     }
+ 
+-  RLEHeader header = { static_cast<uint32_t> ( MaxNumSegments ), { 64 } };
++  RLEHeader header;
++  header.SetNumSegments(static_cast<uint32_t>(MaxNumSegments));
++  header.SetOffset({64});
+   // there cannot be any space in between the end of the RLE header and the start
+   // of the first RLE segment
+   //
+@@ -514,12 +553,12 @@
+         length += llength;
+         }
+       // update header
+-      header.Offset[1+seg] = (uint32_t)(header.Offset[seg] + length);
++      header.SetOffset(1 + seg, (uint32_t)(header.GetOffset(seg) + length));
+ 
+       assert( data.str().size() == length );
+       datastr += data.str();
+       }
+-    header.Offset[MaxNumSegments] = 0;
++    header.SetOffset(MaxNumSegments, 0);
+     std::stringstream os;
+     //header.Print( std::cout );
+     os.write((char*)&header,sizeof(header));
+@@ -762,7 +801,7 @@
+   RLEFrame &frame = Internals->Frame;
+   if( !frame.Read(is) )
+      return false;
+-  unsigned long numSegments = frame.Header.NumSegments;
++  unsigned long numSegments = frame.Header.GetNumSegments();
+ 
+   unsigned long numberOfReadBytes = 0;
+ 
+@@ -796,7 +835,13 @@
+     {
+     numberOfReadBytes = 0;
+     std::streampos pos = is.tellg() - start;
+-    if ( frame.Header.Offset[i] - pos != 0 )
++    if (frame.Header.GetOffset(i) > BufferLength) 
++      {
++        gdcmErrorMacro("Offset is bigger then buffer Length");
++        return false;
++      }
++
++    if ( frame.Header.GetOffset(i) - pos != 0 )
+       {
+       // ACUSON-24-YBR_FULL-RLE.dcm
+       // D_CLUNIE_CT1_RLE.dcm
+@@ -804,10 +849,10 @@
+       //gdcmWarningMacro( "RLE Header says: " << frame.Header.Offset[i] <<
+       //   " when it should says: " << pos << std::endl );
+-      std::streamoff check = frame.Header.Offset[i] - pos;//should it be a streampos or a uint32? mmr
++      std::streamoff check = frame.Header.GetOffset(i) - pos;//should it be a streampos or a uint32? mmr
+       // check == 2 for gdcmDataExtra/gdcmSampleData/US_DataSet/GE_US/2929J686-breaker
+       //assert( check == 1 || check == 2);
+       (void)check; //warning removal
+-      is.seekg( frame.Header.Offset[i] + start, std::ios::beg );
++      is.seekg(frame.Header.GetOffset(i) + start, std::ios::beg);
+       }
+ 
+     unsigned long numOutBytes = 0;
+@@ -860,8 +906,8 @@
+      return false;
+   // numsegments = num_comp * bpp / 8;
+   // numsegments >0 && numsegments <= 12
+-  uint32_t bytespercomp = frame.Header.NumSegments;
+-  if( frame.Header.NumSegments % 3 == 0 )
++  uint32_t bytespercomp = frame.Header.GetNumSegments();
++  if (frame.Header.GetNumSegments() % 3 == 0)
+   {
+     PI = PhotometricInterpretation::RGB;
+     PlanarConfiguration = 1;


=====================================
debian/patches/CVE-2025-52582.patch
=====================================
@@ -0,0 +1,93 @@
+Author: pleduff <pierre.ldff at gmail.com>
+Date: Mon, 9 Nov 2020 12:29:45 +0100
+
+    Fix bug #512: Crash when reading corrupted Jpeg2000 files
+
+    Prevent overlay extraction in case of malformed overlay or image information.
+
+    Add warning to prevent user
+
+Origin: https://github.com/malaterre/GDCM/commit/14825ceb1cb6855f32e726ee5cd2968e3051da2a
+Bug-Debian: https://bugs.debian.org/1123576
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-52582
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-52582
+
+---
+ Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx
++++ b/Source/MediaStorageAndFileFormat/gdcmJPEG2000Codec.cxx
+@@ -1406,6 +1406,8 @@
+   opj_stream_t *cio = nullptr;
+   opj_image_t *image = nullptr;
+   const unsigned char *src = (const unsigned char*)dummy_buffer;
++  if(!src)
++	  return false ;
+   size_t file_length = buf_size;
+ 
+   /* set decoding parameters to default values */
+--- a/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx
++++ b/Source/MediaStorageAndFileFormat/gdcmPixmapReader.cxx
+@@ -546,7 +546,44 @@
+           {
+           gdcmWarningMacro( "Bits Allocated are wrong. Correcting." );
+           ov.SetBitsAllocated( pixeldata.GetPixelFormat().GetBitsAllocated() );
+-          }
++        }
++        const DataElement &pixeldataDe = ds.GetDataElement(Tag(0x7fe0, 0x0010));
++        const ByteValue *bv = pixeldataDe.GetByteValue();
++        if (!bv) {
++          gdcmWarningMacro(
++              "Could not extract overlay from encapsulated stream.");
++          continue;
++        }
++        unsigned long computedFramePixelsNb =
++            pixeldata.GetDimension(0) * pixeldata.GetDimension(1);
++
++        if (pixeldata.GetPixelFormat().GetPixelSize() == 0 ||
++            computedFramePixelsNb >
++                bv->GetLength() / pixeldata.GetPixelFormat().GetPixelSize()) {
++          gdcmWarningMacro("Image information is not persistent. Can't extract overlay #"
++              << idxoverlays);
++          continue;
++        }
++        signed short ovOriginY = ov.GetOrigin()[0];
++        signed short ovOriginX = ov.GetOrigin()[1];
++        long startPixel =
++            (ovOriginX - 1) + (ovOriginY - 1) * pixeldata.GetDimension(0);
++        if (startPixel < 0 ||
++            (unsigned long)startPixel >= computedFramePixelsNb) {
++          gdcmWarningMacro(
++              "Origin is not in image buffer. Can't extract overlay #"
++              << idxoverlays);
++          continue;
++        }
++        unsigned long lastPixelAccessed =
++            (unsigned long)startPixel +
++            (ov.GetRows() - 1) * pixeldata.GetDimension(0) +
++            (ov.GetColumns() - 1);
++        if (lastPixelAccessed >= computedFramePixelsNb) {
++          gdcmWarningMacro("Overlay not fit image buffer. Can't extract overlay "
++                           << idxoverlays);
++          continue;
++        }
+ 
+         if( !ov.GrabOverlayFromPixelData(ds) )
+           {
+--- a/Source/MediaStorageAndFileFormat/gdcmOverlay.h
++++ b/Source/MediaStorageAndFileFormat/gdcmOverlay.h
+@@ -93,7 +93,12 @@
+ 
+   /// set overlay from byte array + length
+   void SetOverlay(const char *array, size_t length);
+-  ///
++
++  /// \warning Before calling this method, you must verify the consistency
++  /// between the image metadata (Image PixelFormat, Rows, Columns) and the
++  /// overlay parameters. This pre-verification is required to ensure that the
++  /// bit-depth is compatible and that the overlay data fits within the
++  /// allocated pixel storage.
+   bool GrabOverlayFromPixelData(DataSet const &ds);
+ 
+   /// Return the Overlay Data as ByteValue:


=====================================
debian/patches/CVE-2025-53618_CVE-2025-53619.patch
=====================================
@@ -0,0 +1,31 @@
+From: pierre <pierre at intradys.com>
+Date: Thu, 8 Jan 2026 15:58:32 +0100
+Subject: [PATCH] Add a frame size check to ensure that the provided data
+ corresponds to the buffer size
+
+Origin: https://github.com/malaterre/GDCM/commit/f0e359c87947326c7fb2f7b91ecbe351e9d8c683
+Bug-Debian: https://bugs.debian.org/1123587
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-53618
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-53619
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-53618
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2025-53619
+---
+ Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.hxx | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.hxx
++++ b/Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.hxx
+@@ -1166,6 +1166,13 @@
+   int image_height = dims[1];  /* Number of rows in image */
+   int image_width = dims[0];    /* Number of columns in image */
+ 
++  // Check if provided buffer correspond to image parameters for current frame
++  size_t expected_frame_size = (size_t)image_width * image_height *
++                               this->GetPixelFormat().GetPixelSize();
++  if (len != expected_frame_size) {
++    gdcmErrorMacro("Frame size don't match");
++    return false;
++  }
+   /* This struct contains the JPEG compression parameters and pointers to
+    * working space (which is allocated as needed by the JPEG library).
+    * It is possible to have several such structures, representing multiple


=====================================
debian/patches/CVE-2026-3650.patch
=====================================
@@ -0,0 +1,319 @@
+From: Matt McCormick <matt at fideus.io>
+Date: Wed, 15 Apr 2026 16:24:50 -0400
+Subject: [PATCH] Fix CVE-2026-3650: reject Value Length exceeding stream size
+
+A crafted DICOM file could specify an arbitrarily large Value Length
+field (up to ~4 GB), causing ByteValue::SetLength() to attempt a
+massive memory allocation before any stream data is read. This enables
+denial-of-service via memory exhaustion.
+
+Add stream-size validation in ExplicitDataElement::ReadValue(),
+ImplicitDataElement::ReadValue(), Fragment::ReadValue(), and
+Fragment::ReadBacktrack(). Before allocating a ByteValue, the code
+now compares the declared VL against the remaining bytes in the
+stream via tellg()/seekg(). Non-seekable streams skip the check
+gracefully.
+
+Also fix out-of-bounds array accesses in SequenceOfFragments where
+bv->GetLength() - N was used without verifying minimum length,
+affecting lines that use gdcmAssertAlwaysMacro (active in release).
+
+Add TestCVE20263650 covering Explicit VR, Implicit VR, and Fragment
+code paths with a 1 GB VL on a ~20-byte stream.
+
+Session: 42647aea-99e9-4b17-8b8a-c2f0fffd5eb4
+
+Co-Authored-By: Claude Opus 4.6 <noreply at anthropic.com>
+
+Origin: backport, https://github.com/malaterre/GDCM/commit/9d65a217c958968a74c14b10388d03ca61953a74
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-3650
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-3650
+Bug-Debian: htts://bugs.debian.org/1132042
+---
+ .../gdcmExplicitDataElement.txx               |  17 +++
+ .../gdcmFragment.h                            |  24 +++
+ .../gdcmImplicitDataElement.txx               |  17 +++
+ .../gdcmSequenceOfFragments.h                 |   6 +-
+ .../Cxx/CMakeLists.txt                        |   1 +
+ .../Cxx/TestCVE20263650.cxx                   | 144 ++++++++++++++++++
+ 6 files changed, 206 insertions(+), 3 deletions(-)
+ create mode 100644 Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCVE20263650.cxx
+
+--- a/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx
++++ b/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx
+@@ -237,6 +237,23 @@
+     {
+     //assert( TagField != Tag(0x7fe0,0x0010) );
+     ValueField = new ByteValue;
++    if( readvalues )
++      {
++      const std::streampos cur = is.tellg();
++      if( cur != std::streampos(-1) )
++        {
++        is.seekg(0, std::ios::end);
++        const std::streampos end = is.tellg();
++        is.seekg(cur);
++        if( end != std::streampos(-1) && is.good()
++          && static_cast<uint64_t>(end - cur) < static_cast<uint32_t>(ValueLengthField) )
++          {
++          gdcmWarningMacro( "Value Length " << ValueLengthField
++            << " exceeds remaining stream size for tag " << TagField );
++          throw Exception( "Value Length exceeds remaining stream size" );
++          }
++        }
++      }
+     }
+   // We have the length we should be able to read the value
+   this->SetValueFieldLength( ValueLengthField, readvalues );
+--- a/Source/DataStructureAndEncodingDefinition/gdcmFragment.h
++++ b/Source/DataStructureAndEncodingDefinition/gdcmFragment.h
+@@ -97,6 +97,18 @@
+     const Tag seqDelItem(0xfffe,0xe0dd);
+     // Self
+     SmartPointer<ByteValue> bv = new ByteValue;
++    const std::streampos cur = is.tellg();
++    if( cur != std::streampos(-1) )
++      {
++      is.seekg(0, std::ios::end);
++      const std::streampos end = is.tellg();
++      is.seekg(cur);
++      if( end != std::streampos(-1) && is.good()
++        && static_cast<uint64_t>(end - cur) < static_cast<uint32_t>(ValueLengthField) )
++        {
++        throw Exception( "Fragment Value Length exceeds remaining stream size" );
++        }
++      }
+     bv->SetLength(ValueLengthField);
+     if( !bv->Read<TSwap>(is) )
+       {
+@@ -152,6 +164,18 @@
+ 
+     // Self
+     SmartPointer<ByteValue> bv = new ByteValue;
++    const std::streampos cur2 = is.tellg();
++    if( cur2 != std::streampos(-1) )
++      {
++      is.seekg(0, std::ios::end);
++      const std::streampos end2 = is.tellg();
++      is.seekg(cur2);
++      if( end2 != std::streampos(-1) && is.good()
++        && static_cast<uint64_t>(end2 - cur2) < static_cast<uint32_t>(ValueLengthField) )
++        {
++        throw Exception( "Fragment Value Length exceeds remaining stream size" );
++        }
++      }
+     bv->SetLength(ValueLengthField);
+     if( !bv->Read<TSwap>(is) )
+       {
+--- a/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx
++++ b/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx
+@@ -215,6 +215,23 @@
+     ValueLengthField = 202; // 0xca
+     }
+ #endif
++  if( !ValueLengthField.IsUndefined() && readvalues )
++    {
++    const std::streampos cur = is.tellg();
++    if( cur != std::streampos(-1) )
++      {
++      is.seekg(0, std::ios::end);
++      const std::streampos end = is.tellg();
++      is.seekg(cur);
++      if( end != std::streampos(-1) && is.good()
++        && static_cast<uint64_t>(end - cur) < static_cast<uint32_t>(ValueLengthField) )
++        {
++        gdcmWarningMacro( "Value Length " << ValueLengthField
++          << " exceeds remaining stream size for tag " << TagField );
++        throw Exception( "Value Length exceeds remaining stream size" );
++        }
++      }
++    }
+   // We have the length we should be able to read the value
+   this->SetValueFieldLength( ValueLengthField, readvalues );
+   bool failed;
+--- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h
++++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h
+@@ -167,7 +167,7 @@
+       {
+       assert( Fragments.size() == 1 );
+       const ByteValue *bv = Fragments[0].GetByteValue();
+-      assert( (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe );
++      assert( bv->GetLength() >= 1 && (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe );
+       // Yes this is an extra copy, this is a bug anyway, go fix YOUR code
+       Fragments[0].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 );
+       gdcmWarningMacro( "JPEG Fragment length was declared with an extra byte"
+@@ -188,7 +188,7 @@
+       const size_t lastf = Fragments.size() - 1;
+       const ByteValue *bv = Fragments[ lastf ].GetByteValue();
+       const char *a = bv->GetPointer();
+-      gdcmAssertAlwaysMacro( (unsigned char)a[ bv->GetLength() - 1 ] == 0xfe );
++      gdcmAssertAlwaysMacro( bv->GetLength() >= 1 && (unsigned char)a[ bv->GetLength() - 1 ] == 0xfe );
+       Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 );
+       is.seekg( -9, std::ios::cur );
+       assert( is.good() );
+@@ -212,7 +212,7 @@
+       const size_t lastf = Fragments.size() - 1;
+       const ByteValue *bv = Fragments[ lastf ].GetByteValue();
+       const char *a = bv->GetPointer();
+-      gdcmAssertAlwaysMacro( (unsigned char)a[ bv->GetLength() - 2 ] == 0xfe );
++      gdcmAssertAlwaysMacro( bv->GetLength() >= 2 && (unsigned char)a[ bv->GetLength() - 2 ] == 0xfe );
+       Fragments[ lastf ].SetByteValue( bv->GetPointer(), bv->GetLength() - 2 );
+       is.seekg( -10, std::ios::cur );
+       assert( is.good() );
+--- a/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt
++++ b/Testing/Source/DataStructureAndEncodingDefinition/Cxx/CMakeLists.txt
+@@ -47,6 +47,7 @@ set(DSED_TEST_SRCS
+   TestVL
+   TestVM
+   TestVR
++  TestCVE20263650
+   #TestValue
+   #TestTorture
+   TestElement2
+--- /dev/null
++++ b/Testing/Source/DataStructureAndEncodingDefinition/Cxx/TestCVE20263650.cxx
+@@ -0,0 +1,144 @@
++/*=========================================================================
++
++  Program: GDCM (Grassroots DICOM). A DICOM library
++
++  Copyright (c) 2006-2011 Mathieu Malaterre
++  All rights reserved.
++  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
++
++     This software is distributed WITHOUT ANY WARRANTY; without even
++     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
++     PURPOSE.  See the above copyright notice for more information.
++
++=========================================================================*/
++#include "gdcmExplicitDataElement.h"
++#include "gdcmImplicitDataElement.h"
++#include "gdcmFragment.h"
++#include "gdcmSwapper.h"
++
++#include <sstream>
++#include <new>
++
++// CVE-2026-3650: Verify that crafted DICOM data elements with a Value Length
++// exceeding the remaining stream size are rejected without attempting the
++// allocation.
++
++static int TestExplicitVR()
++{
++  // Explicit VR data element: Tag (0008,0060), VR = OB, VL = 1 GB, 10 bytes data
++  std::stringstream ss;
++  const uint16_t group = 0x0008;
++  const uint16_t element = 0x0060;
++  ss.write(reinterpret_cast<const char*>(&group), 2);
++  ss.write(reinterpret_cast<const char*>(&element), 2);
++  ss.write("OB", 2);
++  const uint16_t reserved = 0;
++  ss.write(reinterpret_cast<const char*>(&reserved), 2);
++  const uint32_t vl = 0x40000000;
++  ss.write(reinterpret_cast<const char*>(&vl), 4);
++  const char data[10] = {};
++  ss.write(data, sizeof(data));
++
++  gdcm::ExplicitDataElement de;
++  try
++    {
++    de.Read<gdcm::SwapperNoOp>(ss);
++    std::cerr << "ERROR: ExplicitDataElement::Read should have thrown" << std::endl;
++    return 1;
++    }
++  catch(const gdcm::Exception &)
++    {
++    return 0;
++    }
++  catch(const std::bad_alloc &)
++    {
++    std::cerr << "ERROR: ExplicitDataElement allocated memory for oversized VL" << std::endl;
++    return 1;
++    }
++  catch(...)
++    {
++    std::cerr << "ERROR: ExplicitDataElement::Read threw unexpected exception" << std::endl;
++    return 1;
++    }
++}
++
++static int TestImplicitVR()
++{
++  // Implicit VR data element: Tag (0008,0060), VL = 1 GB, 10 bytes data
++  std::stringstream ss;
++  const uint16_t group = 0x0008;
++  const uint16_t element = 0x0060;
++  ss.write(reinterpret_cast<const char*>(&group), 2);
++  ss.write(reinterpret_cast<const char*>(&element), 2);
++  const uint32_t vl = 0x40000000;
++  ss.write(reinterpret_cast<const char*>(&vl), 4);
++  const char data[10] = {};
++  ss.write(data, sizeof(data));
++
++  gdcm::ImplicitDataElement de;
++  try
++    {
++    de.Read<gdcm::SwapperNoOp>(ss);
++    std::cerr << "ERROR: ImplicitDataElement::Read should have thrown" << std::endl;
++    return 1;
++    }
++  catch(const gdcm::Exception &)
++    {
++    return 0;
++    }
++  catch(const std::bad_alloc &)
++    {
++    std::cerr << "ERROR: ImplicitDataElement allocated memory for oversized VL" << std::endl;
++    return 1;
++    }
++  catch(...)
++    {
++    std::cerr << "ERROR: ImplicitDataElement::Read threw unexpected exception" << std::endl;
++    return 1;
++    }
++}
++
++static int TestFragment()
++{
++  // Fragment: Item tag (fffe,e000), VL = 1 GB, 10 bytes data
++  std::stringstream ss;
++  const uint16_t group = 0xfffe;
++  const uint16_t element = 0xe000;
++  ss.write(reinterpret_cast<const char*>(&group), 2);
++  ss.write(reinterpret_cast<const char*>(&element), 2);
++  const uint32_t vl = 0x40000000;
++  ss.write(reinterpret_cast<const char*>(&vl), 4);
++  const char data[10] = {};
++  ss.write(data, sizeof(data));
++
++  gdcm::Fragment frag;
++  try
++    {
++    frag.Read<gdcm::SwapperNoOp>(ss);
++    std::cerr << "ERROR: Fragment::Read should have thrown" << std::endl;
++    return 1;
++    }
++  catch(const gdcm::Exception &)
++    {
++    return 0;
++    }
++  catch(const std::bad_alloc &)
++    {
++    std::cerr << "ERROR: Fragment allocated memory for oversized VL" << std::endl;
++    return 1;
++    }
++  catch(...)
++    {
++    std::cerr << "ERROR: Fragment::Read threw unexpected exception" << std::endl;
++    return 1;
++    }
++}
++
++int TestCVE20263650(int, char *[])
++{
++  int ret = 0;
++  ret += TestExplicitVR();
++  ret += TestImplicitVR();
++  ret += TestFragment();
++  return ret;
++}


=====================================
debian/patches/series
=====================================
@@ -11,3 +11,7 @@ CVE-2024-22373.patch
 CVE-2024-22391.patch
 CVE-2024-25569.patch
 CVE-2025-11266.patch
+CVE-2025-52582.patch
+CVE-2025-53618_CVE-2025-53619.patch
+CVE-2025-48429.patch
+CVE-2026-3650.patch



View it on GitLab: https://salsa.debian.org/med-team/gdcm/-/compare/64e00639d65c729243c99f21b38f1b0ed590c3a4...5c0fdae82049734a2c1cf099a2d6d97732f48b5a

-- 
View it on GitLab: https://salsa.debian.org/med-team/gdcm/-/compare/64e00639d65c729243c99f21b38f1b0ed590c3a4...5c0fdae82049734a2c1cf099a2d6d97732f48b5a
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260619/4d273417/attachment-0001.htm>


More information about the debian-med-commit mailing list