Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:dcmtk
User: [email protected]
Usertags: pu

Greetings Stable Release Managers,

This is the bookworm equivalent of proposed dcmtk upgrade for
trixie #1139722, with two extra CVE being addressed.

[ Reason ]
dcmtk in bookworm is currently affected by several security
issues, namely:

  * CVE-2022-4981,
  * CVE-2025-2357, described in #1100724,
  * CVE-2025-9732, described in #1113993,
  * CVE-2025-14607, described in #1122926,
  * CVE-2025-14841, described in #1123584,
  * CVE-2026-5663, described in #1133001,
  * CVE-2026-10194, described in #1139181.

They are all sorted as low-priority security issues, hence not
coordinating directly with the Security Team.  Yet having them
fixed in the next oldstable release might be welcome.

[ Impact ]
If the update is not approved, then dcmtk will continue being
affected by the above items.

[ Tests ]
I have ensured that the patches have caused no regressions in
bookworm using tests like piuparts and the embedded autopkgtest.
I have also ensured that the reverse dependencies were not being
affected by a regression in their autopkgtest if I introduce the
patched library.

[ Risks ]
Changes brought to the code are not trivial to me, but I'm
neither imaging specialist nor security specialist (or at least
don't consider myself as such).  Mitigation of CVE-2025-9732
required an amendment upstream (see upstream commit 3de96da6c),
which materializes here as patches 0013-CVE-2025-9732.patch and
0014-CVE-2025-9732b.patch.  That being written, all the changes
are part of the current dcmtk 3.7.0+really3.7.0-5 available in
unstable and forky.

I have also been mindful to make sure that the changes minimize
alterations to the ABI.  This time, mitigating CVE-2026-5663
also required introducing missing definition of sanitizeAETitle
from the dcmtk library, so had to implement it directly in
dcmnet/apps/storescp.cc.  The function is inline.  Otherwise,
apart perhaps from the introduction of two constant static
variables for listing admissible characters in sanitized file
names, there should not be any breakage.

[ Checklist ]
  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in (old)stable
  [*] the issue is verified as fixed in unstable

[ Changes ]
0012-CVE-2022-4981.patch is sligtly annoying to read due to the
corresponding upstream patch also having redone the indentation.
If I understood correctly, the change will initialize the
noOfPeers to 0, add an extra check on a SymbolicName pointer
deep within the CNF_HETable structure, and make sure that the
noOfPeers cannot drop below 0 when returning the function
result.  This corresponds to upstream commit 957fb31.

0013-CVE-2025-2357.patch is also annoying to read, this time
because of the amount of white space at end of lines being
trimmed in the corresponding upstream commit, along the
mitigation.  The actual change occurs at:

        void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*)

where the extra code consists in introducing a check on the
range, which will throw a JlsException if values are incoherent.
This corresponds to upstram commit 3239a7915.

0014-CVE-2025-9732.patch imports upstream commit 7ad81d69b,
initially fixing CVE-2025-9732.

0015-CVE-2025-9732b.patch imports upstream commit 3de96da6c,
which amends the previous patch with a fix needed for proper
operation of the library.

0016-CVE-2025-14607.patch imports upstream commit 4c0e5c100,
fixing CVE-2025-14607 by ensuring zero termination beyond the
end of the string, necessary under certain conditions.

0017-CVE-2025-14841.patch imports upstream commit ffb1a4a37,
fixing CVE-2025-14841 by applying proper checks to ensure the
pointer causing potential crashes is not NULL, or proceed
appropriately.

0018-CVE-2026-5663.patch
This is the same as for trixie, but I also had to introduce a
static const char sanitized_aetitle_charset[] and a function
inline void sanitizeAETitle(OFString& aetitle) because it was
not implemented in dcmtk 3.6.7, but the corresponding upstream
patch relied on them.

0019-CVE-2026-10194.patch imports upstream commit 0f78a4ef6,
fixing CVE-2026-10194 about a heap buffer overflow.

[ Other info ]
The main differences with the proposed dcmtk upgrade for trixie
are the two extra CVE: CVE-2022-4981 and CVE-2025-2357.  There
is also the need to define sanitizeAETitle function to fix
CVE-2026-5663, which did not exist in dcmtk 3.6.7; I used an
inline to avoid polluting the ABI.

Have a nice day,  :)
-- 
  .''`.  Étienne Mollier <[email protected]>
 : :' :  pgp: 8f91 b227 c7d6 f2b1 948c  8236 793c f67e 8f0d 11da
 `. `'   sent from /dev/pts/3, please excuse my verbosity
   `-
diff -Nru dcmtk-3.6.7/debian/changelog dcmtk-3.6.7/debian/changelog
--- dcmtk-3.6.7/debian/changelog        2025-02-20 21:59:03.000000000 +0100
+++ dcmtk-3.6.7/debian/changelog        2026-06-12 20:59:14.000000000 +0200
@@ -1,3 +1,19 @@
+dcmtk (3.6.7-9~deb12u4) bookworm; urgency=medium
+
+  * Team upload.
+  * 0012-CVE-2022-4981.patch: new: fix CVE-2022-4981.
+  * 0013-CVE-2025-2357.patch: new: fix CVE-2025-2357. (Closes: #1100724)
+  * *CVE-2025-9732*.patch: new.
+    These two patches fix CVE-2025-9732. (Closes: #1113993)
+  * 0016-CVE-2025-14607.patch: new: fix CVE-2025-14607. (Closes: #1122926)
+  * 0017-CVE-2025-14841.patch: new: fix CVE-2025-14841. (Closes: #1123584)
+  * 0018-CVE-2026-5663.patch: new: fix CVE-2026-5663.
+    This patch required some rework from upstream due to little changes in
+    the logic and the coding style. (Closes: #1133001)
+  * 0019-CVE-2026-10194.patch: new: fix CVE-2026-10194. (Closes: #1139181)
+
+ -- Étienne Mollier <[email protected]>  Fri, 12 Jun 2026 20:59:14 +0200
+
 dcmtk (3.6.7-9~deb12u3) bookworm; urgency=medium
 
   * Team upload.
diff -Nru dcmtk-3.6.7/debian/patches/0012-CVE-2022-4981.patch 
dcmtk-3.6.7/debian/patches/0012-CVE-2022-4981.patch
--- dcmtk-3.6.7/debian/patches/0012-CVE-2022-4981.patch 1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0012-CVE-2022-4981.patch 2026-06-12 
20:23:43.000000000 +0200
@@ -0,0 +1,90 @@
+commit 957fb31e5d96f51ecf5cb3422c7dc2227f8e0423
+Author: Marco Eichelberg <[email protected]>
+Date:   Tue May 24 11:22:35 2022 +0200
+
+    Fixed dcmqrscp crash caused by malformed config file.
+    
+    Fixed various issues in the dcmqrscp configuration file parser
+    that could cause application crashes when reading a malformed configuration
+    file, due to insufficient checks of the input data.
+    
+    This closes DCMTK issue #1026.
+    
+    Thanks to Zahra Mirzamomen <[email protected]> and
+    Marcel Böhme <[email protected]> for the bug report and sample 
files.
+
+diff --git a/dcmqrdb/libsrc/dcmqrcnf.cc b/dcmqrdb/libsrc/dcmqrcnf.cc
+index 686c9df2a..36a295fa2 100644
+--- a/dcmqrdb/libsrc/dcmqrcnf.cc
++++ b/dcmqrdb/libsrc/dcmqrcnf.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1993-2021, OFFIS e.V.
++ *  Copyright (C) 1993-2022, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -447,7 +447,7 @@ int DcmQueryRetrieveConfig::readHostTable(FILE *cnffp, int 
*lineno)
+ {
+    int  error = 0,        /* error flag */
+         end = 0,          /* end flag */
+-        noOfPeers;        /* number of peers for entry */
++        noOfPeers=0;      /* number of peers for entry */
+    char rcline[512],      /* line in configuration file */
+         mnemonic[512],    /* mnemonic in line */
+         value[512],       /* parameter value */
+@@ -676,26 +676,34 @@ DcmQueryRetrieveConfigPeer 
*DcmQueryRetrieveConfig::readPeerList(char **valuehan
+    while((helpvalue = parsevalues(valuehandle)) != NULL) {
+       found = 0;
+       if (strchr(helpvalue, ',') == NULL) {   /* symbolic name */
+-         if (!CNF_HETable.noOfHostEntries) {
+-            panic("No symbolic names defined");
+-            *peers = 0;
+-            free(helpvalue);
+-            return((DcmQueryRetrieveConfigPeer *) 0);
+-         }
+-         for(i = 0; i < CNF_HETable.noOfHostEntries; i++) {
+-            if (!strcmp(CNF_HETable.HostEntries[i].SymbolicName, helpvalue)) {
+-               found = 1;
+-               break;
+-            }
+-         }
+-         if (!found) {
+-            panic("Symbolic name \"%s\" not defined", helpvalue);
+-            *peers = 0;
+-            free(helpvalue);
+-            return((DcmQueryRetrieveConfigPeer *) 0);
+-         }
++        if (!CNF_HETable.noOfHostEntries) {
++           panic("No symbolic names defined");
++           *peers = 0;
++           free(helpvalue);
++           return((DcmQueryRetrieveConfigPeer *) 0);
++        }
++        for(i = 0; i < CNF_HETable.noOfHostEntries; i++) {
++           if ((CNF_HETable.HostEntries[i].SymbolicName != NULL) && (0 == 
strcmp(CNF_HETable.HostEntries[i].SymbolicName, helpvalue))) {
++              found = 1;
++              break;
++           }
++        }
++        if (!found) {
++           panic("Symbolic name \"%s\" not defined", helpvalue);
++           *peers = 0;
++           free(helpvalue);
++           return((DcmQueryRetrieveConfigPeer *) 0);
++        }
++
++        if (CNF_HETable.HostEntries[i].noOfPeers <= 0) {
++           panic("No peers for symbolic name \"%s\" defined", helpvalue);
++           *peers = 0;
++           free(helpvalue);
++           return((DcmQueryRetrieveConfigPeer *) 0);
++        }
++
++        noOfPeers += CNF_HETable.HostEntries[i].noOfPeers;
+ 
+-         noOfPeers += CNF_HETable.HostEntries[i].noOfPeers;
+         if ((helppeer = (DcmQueryRetrieveConfigPeer *)malloc(noOfPeers * 
sizeof(DcmQueryRetrieveConfigPeer))) == NULL)
+             panic("Memory allocation 5 (%d)", noOfPeers);
+         if (noOfPeers - CNF_HETable.HostEntries[i].noOfPeers) {
diff -Nru dcmtk-3.6.7/debian/patches/0013-CVE-2025-2357.patch 
dcmtk-3.6.7/debian/patches/0013-CVE-2025-2357.patch
--- dcmtk-3.6.7/debian/patches/0013-CVE-2025-2357.patch 1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0013-CVE-2025-2357.patch 2026-06-12 
20:28:26.000000000 +0200
@@ -0,0 +1,510 @@
+commit 3239a791542e1ea433d23aaa9e0a05a532ffabff
+Author: Marco Eichelberg <[email protected]>
+Date:   Mon Mar 3 12:33:18 2025 +0100
+
+    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 <[email protected]> for the report
+    and the sample file (PoC).
+    
+    This closes DCMTK issue #1155.
+
+diff --git a/dcmjpls/libcharls/scan.h b/dcmjpls/libcharls/scan.h
+index b4dea20d8..f13098104 100644
+--- a/dcmjpls/libcharls/scan.h
++++ b/dcmjpls/libcharls/scan.h
+@@ -1,6 +1,6 @@
+-// 
+-// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying 
"License.txt" for licensed use. 
+-// 
++//
++// (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying 
"License.txt" for licensed use.
++//
+ 
+ #ifndef CHARLS_SCAN
+ #define CHARLS_SCAN
+@@ -11,7 +11,7 @@
+ 
+ #include "lokuptbl.h"
+ 
+-// This file contains the code for handling a "scan". Usually an image is 
encoded as a single scan. 
++// This file contains the code for handling a "scan". Usually an image is 
encoded as a single scan.
+ 
+ #include DCMTK_DIAGNOSTIC_IGNORE_CONST_EXPRESSION_WARNING
+ 
+@@ -21,10 +21,10 @@ extern OFVector<signed char> rgquant10Ll;
+ extern OFVector<signed char> rgquant12Ll;
+ extern OFVector<signed char> rgquant16Ll;
+ //
+-// Apply 
++// Apply
+ //
+ inlinehint LONG ApplySign(LONG i, LONG sign)
+-{ return (sign ^ i) - sign; }                                                 
                
++{ return (sign ^ i) - sign; }
+ 
+ 
+ 
+@@ -58,20 +58,20 @@ inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG 
Rc)
+ 
+ inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc)
+ {
+-      // sign trick reduces the number of if statements (branches) 
++      // sign trick reduces the number of if statements (branches)
+       LONG sgn = BitWiseSign(Rb - Ra);
+ 
+-      // is Ra between Rc and Rb? 
++      // is Ra between Rc and Rb?
+       if ((sgn ^ (Rc - Ra)) < 0)
+       {
+               return Rb;
+-      } 
++      }
+       else if ((sgn ^ (Rb - Rc)) < 0)
+       {
+               return Ra;
+       }
+ 
+-      // default case, valid if Rc element of [Ra,Rb] 
++      // default case, valid if Rc element of [Ra,Rb]
+       return Ra + Rb - Rc;
+ }
+ 
+@@ -110,7 +110,7 @@ public:
+ 
+ public:
+ 
+-        JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : 
STRATEGY(info), 
++        JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : 
STRATEGY(info),
+         traits(inTraits),
+                 _rect(),
+                 _width(0),
+@@ -120,13 +120,13 @@ public:
+                 _RUNindex(0),
+                 _pquant(0),
+                 _bCompare(0)
+-                
++
+         {
+                 if (Info().ilv == ILV_NONE)
+                 {
+                         Info().components = 1;
+                 }
+-        }     
++        }
+ 
+ 
+         void SetPresets(const JlsCustomParameters& presets)
+@@ -135,9 +135,9 @@ public:
+ 
+                 InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1,
+                         presets.T2 != 0 ? presets.T2 : presetDefault.T2,
+-                        presets.T3 != 0 ? presets.T3 : presetDefault.T3, 
++                        presets.T3 != 0 ? presets.T3 : presetDefault.T3,
+                         presets.RESET != 0 ? presets.RESET : 
presetDefault.RESET);
+-        }     
++        }
+ 
+ 
+         bool IsInterleaved()
+@@ -155,13 +155,13 @@ public:
+ 
+         signed char QuantizeGratientOrg(LONG Di);
+         inlinehint LONG QuantizeGratient(LONG Di)
+-        { 
++        {
+                 ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di));
+-                return *(_pquant + Di); 
++                return *(_pquant + Di);
+         }
+ 
+         void InitQuantizationLUT();
+-      
++
+         LONG DecodeValue(LONG k, LONG limit, LONG qbpp);
+         inlinehint void EncodeMappedValue(LONG k, LONG mappedError, LONG 
limit);
+ 
+@@ -216,27 +216,27 @@ public:
+         {
+               LONG sign               = BitWiseSign(Qs);
+               JlsContext& ctx = _contexts[ApplySign(Qs, sign)];
+-              LONG k                  = ctx.GetGolomb();      
+-              LONG Px                 = traits.CorrectPrediction(pred + 
ApplySign(ctx.C, sign));    
++              LONG k                  = ctx.GetGolomb();
++              LONG Px                 = traits.CorrectPrediction(pred + 
ApplySign(ctx.C, sign));
+ 
+               LONG ErrVal;
+               const Code& code                = 
decodingTables[k].Get(STRATEGY::PeekByte());
+               if (code.GetLength() != 0)
+               {
+                       STRATEGY::Skip(code.GetLength());
+-                      ErrVal = code.GetValue(); 
++                      ErrVal = code.GetValue();
+                       ASSERT(ABS(ErrVal) < 65535);
+               }
+               else
+               {
+-                      ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, 
traits.qbpp)); 
++                      ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, 
traits.qbpp));
+                       if (ABS(ErrVal) > 65535)
+                               throw JlsException(InvalidCompressedData);
+-              }       
++              }
+               ErrVal = ErrVal ^ ((traits.NEAR == 0) ? 
ctx.GetErrorCorrection(k) : 0);
+-              ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); 
++              ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET);
+               ErrVal = ApplySign(ErrVal, sign);
+-              return traits.ComputeReconstructedSample(Px, ErrVal); 
++              return traits.ComputeReconstructedSample(Px, ErrVal);
+         }
+ 
+ 
+@@ -245,7 +245,7 @@ public:
+               LONG sign               = BitWiseSign(Qs);
+               JlsContext& ctx = _contexts[ApplySign(Qs, sign)];
+               LONG k                  = ctx.GetGolomb();
+-              LONG Px                 = traits.CorrectPrediction(pred + 
ApplySign(ctx.C, sign));      
++              LONG Px                 = traits.CorrectPrediction(pred + 
ApplySign(ctx.C, sign));
+ 
+               LONG ErrVal             = traits.ComputeErrVal(ApplySign(x - 
Px, sign));
+ 
+@@ -270,16 +270,16 @@ public:
+       size_t  DecodeScan(void* rawData, const JlsRect& size, BYTE **buf, 
size_t *buf_size, size_t offset, bool bCompare);
+ 
+ protected:
+-      // codec parameters 
++      // codec parameters
+       TRAITS traits;
+       JlsRect _rect;
+       int _width;
+-      LONG T1;        
++      LONG T1;
+       LONG T2;
+-      LONG T3; 
++      LONG T3;
+ 
+       // compression context
+-      JlsContext _contexts[365];      
++      JlsContext _contexts[365];
+       CContextRunMode _contextRunmode[2];
+       LONG _RUNindex;
+       PIXEL* _previousLine; // previous line ptr
+@@ -309,7 +309,7 @@ CTable InitTable(LONG k)
+       CTable table;
+       short nerr;
+       for (nerr = 0; ; nerr++)
+-      {               
++      {
+               // Q is not used when k != 0
+               LONG merrval = GetMappedErrVal(nerr);//, k, -1);
+               OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval);
+@@ -321,7 +321,7 @@ CTable InitTable(LONG k)
+       }
+ 
+       for (nerr = -1; ; nerr--)
+-      {               
++      {
+               // Q is not used when k != 0
+               LONG merrval = GetMappedErrVal(nerr);//, k, -1);
+               OFPair<LONG, LONG> paircode = CreateEncodedValue(k, merrval);
+@@ -364,7 +364,7 @@ inlinehint void 
JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
+               if (highbits + 1 > 31)
+               {
+                       STRATEGY::AppendToBitStream(0, highbits / 2);
+-                      highbits = highbits - highbits / 2;                     
                                                                                
++                      highbits = highbits - highbits / 2;
+               }
+               STRATEGY::AppendToBitStream(1, highbits + 1);
+               STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k);
+@@ -374,11 +374,11 @@ inlinehint void 
JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
+       if (limit - traits.qbpp > 31)
+       {
+               STRATEGY::AppendToBitStream(0, 31);
+-              STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31);       
                
++              STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31);
+       }
+       else
+       {
+-              STRATEGY::AppendToBitStream(1, limit - traits.qbpp);            
        
++              STRATEGY::AppendToBitStream(1, limit - traits.qbpp);
+       }
+       STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 
1), traits.qbpp);
+ }
+@@ -389,33 +389,33 @@ inlinehint void 
JlsCodec<TRAITS,STRATEGY>::EncodeMappedValue(LONG k, LONG mapped
+ template<class TRAITS, class STRATEGY>
+ void JlsCodec<TRAITS,STRATEGY>::InitQuantizationLUT()
+ {
+-      // for lossless mode with default parameters, we have precomputed te 
luts for bitcounts 8,10,12 and 16 
++      // for lossless mode with default parameters, we have precomputed te 
luts for bitcounts 8,10,12 and 16
+       if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1)
+       {
+               JlsCustomParameters presets = ComputeDefault(traits.MAXVAL, 
traits.NEAR);
+               if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3)
+               {
+-                      if (traits.bpp == 8) 
++                      if (traits.bpp == 8)
+                       {
+-                              _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ]; 
++                              _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ];
+                               return;
+                       }
+-                      if (traits.bpp == 10) 
++                      if (traits.bpp == 10)
+                       {
+-                              _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 
]; 
++                              _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ];
+                               return;
+-                      }                       
+-                      if (traits.bpp == 12) 
++                      }
++                      if (traits.bpp == 12)
+                       {
+-                              _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 
]; 
++                              _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ];
+                               return;
+-                      }                       
+-                      if (traits.bpp == 16) 
++                      }
++                      if (traits.bpp == 16)
+                       {
+-                              _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 
]; 
++                              _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ];
+                               return;
+-                      }                       
+-              }       
++                      }
++              }
+       }
+ 
+       LONG RANGE = 1 << traits.bpp;
+@@ -453,7 +453,7 @@ template<class TRAITS, class STRATEGY>
+ LONG JlsCodec<TRAITS,STRATEGY>::DecodeRIError(CContextRunMode& ctx)
+ {
+       LONG k = ctx.GetGolomb();
+-      LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, 
traits.qbpp);     
++      LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, 
traits.qbpp);
+       LONG Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k);
+       ctx.UpdateVariables(Errval, EMErrval);
+       return Errval;
+@@ -466,7 +466,7 @@ void 
JlsCodec<TRAITS,STRATEGY>::EncodeRIError(CContextRunMode& ctx, LONG Errval)
+ {
+       LONG k                  = ctx.GetGolomb();
+       bool map                = ctx.ComputeMap(Errval, k);
+-      LONG EMErrval   = 2 * ABS(Errval) - ctx._nRItype - map; 
++      LONG EMErrval   = 2 * ABS(Errval) - ctx._nRItype - map;
+ 
+       ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k));
+       EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1);
+@@ -476,7 +476,7 @@ void 
JlsCodec<TRAITS,STRATEGY>::EncodeRIError(CContextRunMode& ctx, LONG Errval)
+ 
+ template<class TRAITS, class STRATEGY>
+ Triplet<OFTypename TRAITS::SAMPLE> 
JlsCodec<TRAITS,STRATEGY>::DecodeRIPixel(Triplet<SAMPLE> Ra, Triplet<SAMPLE> Rb)
+-{ 
++{
+       LONG Errval1 = DecodeRIError(_contextRunmode[0]);
+       LONG Errval2 = DecodeRIError(_contextRunmode[0]);
+       LONG Errval3 = DecodeRIError(_contextRunmode[0]);
+@@ -513,18 +513,18 @@ Triplet<OFTypename TRAITS::SAMPLE> 
JlsCodec<TRAITS,STRATEGY>::EncodeRIPixel(Trip
+ template<class TRAITS, class STRATEGY>
+ void JlsCodec<TRAITS,STRATEGY>::EncodeRunPixels(LONG runLength, bool 
endOfLine)
+ {
+-      while (runLength >= LONG(1 << J[_RUNindex])) 
++      while (runLength >= LONG(1 << J[_RUNindex]))
+       {
+               STRATEGY::AppendOnesToBitStream(1);
+               runLength = runLength - LONG(1 << J[_RUNindex]);
+               IncrementRunIndex();
+       }
+ 
+-      if (endOfLine) 
++      if (endOfLine)
+       {
+-              if (runLength != 0) 
++              if (runLength != 0)
+               {
+-                      STRATEGY::AppendOnesToBitStream(1);     
++                      STRATEGY::AppendOnesToBitStream(1);
+               }
+       }
+       else
+@@ -556,7 +556,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DecodeRunPixels(PIXEL Ra, 
PIXEL* startPos, LONG
+ 
+       if (index != cpixelMac)
+       {
+-              // incomplete run       
++              // incomplete run
+               index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) 
: 0;
+       }
+ 
+@@ -566,7 +566,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DecodeRunPixels(PIXEL Ra, 
PIXEL* startPos, LONG
+       for (LONG i = 0; i < index; ++i)
+       {
+               startPos[i] = Ra;
+-      }       
++      }
+ 
+       return index;
+ }
+@@ -582,7 +582,7 @@ LONG JlsCodec<TRAITS,STRATEGY>::DoRunMode(LONG index, 
EncoderStrategy*)
+ 
+       LONG runLength = 0;
+ 
+-      while (traits.IsNear(ptypeCurX[runLength],Ra)) 
++      while (traits.IsNear(ptypeCurX[runLength],Ra))
+       {
+               ptypeCurX[runLength] = Ra;
+               runLength++;
+@@ -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)
+@@ -648,8 +658,8 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(SAMPLE*)
+               {
+                       index += DoRunMode(index, (STRATEGY*)(NULL));
+                       Rb = _previousLine[index-1];
+-                      Rd = _previousLine[index];      
+-              }                               
++                      Rd = _previousLine[index];
++              }
+       }
+ }
+ 
+@@ -661,7 +671,7 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
+ {
+       LONG index = 0;
+       while(index < _width)
+-      {               
++      {
+               Triplet<SAMPLE> Ra = _currentLine[index -1];
+               Triplet<SAMPLE> Rc = _previousLine[index-1];
+               Triplet<SAMPLE> Rb = _previousLine[index];
+@@ -671,7 +681,7 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
+               LONG Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), 
QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2));
+               LONG Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), 
QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3));
+ 
+-              
++
+               if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0)
+               {
+                       index += DoRunMode(index, (STRATEGY*)(NULL));
+@@ -684,19 +694,19 @@ void JlsCodec<TRAITS,STRATEGY>::DoLine(Triplet<SAMPLE>*)
+                       Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, 
GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), (STRATEGY*)(NULL));
+                       _currentLine[index] = Rx;
+                       index++;
+-              }       
++              }
+       }
+ }
+ 
+ 
+-// DoScan: Encodes or decodes a scan. 
++// DoScan: Encodes or decodes a scan.
+ // In ILV_SAMPLE mode, multiple components are handled in DoLine
+ // In ILV_LINE mode, a call do DoLine is made for every component
+-// In ILV_NONE mode, DoScan is called for each component 
++// In ILV_NONE mode, DoScan is called for each component
+ 
+ template<class TRAITS, class STRATEGY>
+ void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, size_t *size, size_t 
offset)
+-{             
++{
+       _width = Info().width;
+ 
+       STRATEGY::Init(ptr, size, offset);
+@@ -706,11 +716,11 @@ void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, 
size_t *size, size_t offset)
+ 
+       OFVector<PIXEL> vectmp(2 * components * pixelstride);
+       OFVector<LONG> rgRUNindex(components);
+-      
++
+       for (LONG line = 0; line < Info().height; ++line)
+       {
+-              _previousLine                   = &vectmp[1];   
+-              _currentLine                    = &vectmp[1 + components * 
pixelstride];        
++              _previousLine                   = &vectmp[1];
++              _currentLine                    = &vectmp[1 + components * 
pixelstride];
+               if ((line & 1) == 1)
+               {
+                       PIXEL *tmp = _previousLine;
+@@ -724,17 +734,17 @@ void JlsCodec<TRAITS,STRATEGY>::DoScan(BYTE **ptr, 
size_t *size, size_t offset)
+               for (int component = 0; component < components; ++component)
+               {
+                       _RUNindex = rgRUNindex[component];
+-              
++
+                       // initialize edge pixels used for prediction
+                       _previousLine[_width]   = _previousLine[_width - 1];
+                       _currentLine[-1]                = _previousLine[0];
+                       DoLine((PIXEL*) NULL); // dummy arg for overload 
resolution
+-      
++
+                       rgRUNindex[component] = _RUNindex;
+                       _previousLine += pixelstride;
+                       _currentLine += pixelstride;
+               }
+-              
++
+               if (_rect.Y <= line && line < _rect.Y + _rect.Height)
+               {
+                       STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X 
- (components * pixelstride), pixelstride);
+@@ -754,7 +764,7 @@ ProcessLine* 
JlsCodec<TRAITS,STRATEGY>::CreateProcess(void* pvoidOut)
+               return new PostProcesSingleComponent(pvoidOut, Info(), 
sizeof(typename TRAITS::PIXEL));
+ 
+       if (Info().colorTransform == 0)
+-              return new ProcessTransformed<TransformNone<OFTypename 
TRAITS::SAMPLE> >(pvoidOut, Info(), TransformNone<SAMPLE>()); 
++              return new ProcessTransformed<TransformNone<OFTypename 
TRAITS::SAMPLE> >(pvoidOut, Info(), TransformNone<SAMPLE>());
+ 
+       if (Info().bitspersample == sizeof(SAMPLE)*8)
+       {
+@@ -765,7 +775,7 @@ ProcessLine* 
JlsCodec<TRAITS,STRATEGY>::CreateProcess(void* pvoidOut)
+                       case COLORXFORM_HP3 : return new 
ProcessTransformed<TransformHp3<SAMPLE> >(pvoidOut, Info(), 
TransformHp3<SAMPLE>()); break;
+                       default: throw JlsException(UnsupportedColorTransform);
+               }
+-      } 
++      }
+       else if (Info().bitspersample > 8)
+       {
+               int shift = 16 - Info().bitspersample;
+@@ -796,7 +806,7 @@ size_t JlsCodec<TRAITS,STRATEGY>::EncodeScan(const void* 
rawData, BYTE **ptr, si
+       }
+ 
+       DoScan(ptr, size, offset);
+-      
++
+       return  STRATEGY::GetLength();
+ 
+ }
+@@ -827,7 +837,7 @@ size_t JlsCodec<TRAITS,STRATEGY>::DecodeScan(void* 
rawData, const JlsRect& rect,
+       _rect = rect;
+ 
+       DoScan(ptr, size, offset + readBytes);
+-      
++
+       return STRATEGY::GetCurBytePos() - (*ptr + offset);
+ }
+ 
diff -Nru dcmtk-3.6.7/debian/patches/0014-CVE-2025-9732.patch 
dcmtk-3.6.7/debian/patches/0014-CVE-2025-9732.patch
--- dcmtk-3.6.7/debian/patches/0014-CVE-2025-9732.patch 1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0014-CVE-2025-9732.patch 2026-06-12 
20:32:30.000000000 +0200
@@ -0,0 +1,398 @@
+commit 7ad81d69b19714936e18ea5fc74edaeb9f021ce7
+Author: Joerg Riesmeier <[email protected]>
+Date:   Fri Aug 15 13:35:40 2025 +0200
+
+    Fixed issue with invalid "YBR_FULL" DICOM images.
+    
+    Fixed an issue when processing an invalid DICOM image with a Photometric
+    Interpretation of "YBR_FULL" and a Planar Configuration of "1" where
+    the number of pixels stored does not match the expected number of pixels
+    (much too less). Now, the pixel data of such an image is not processed
+    at all, but an empty image (black pixels) is created instead. The user
+    is warned about this by an appropriate log message.
+    
+    Thanks to Ding zhengzheng <[email protected]> for the report
+    and the sample file (PoC).
+
+--- dcmtk.orig/dcmimage/include/dcmtk/dcmimage/dicopxt.h
++++ dcmtk/dcmimage/include/dcmtk/dcmimage/dicopxt.h
+@@ -574,7 +574,11 @@
+                 {
+                     /* erase empty part of the buffer (=blacken the 
background) */
+                     if (InputCount < Count)
+-                        OFBitmanipTemplate<T>::zeroMem(Data[j] + InputCount, 
Count - InputCount);
++                    {
++                        const size_t count = (Count - InputCount);
++                        DCMIMAGE_TRACE("filing empty part of the intermediate 
pixel data (" << count << " pixels) of plane " << j << " with value = 0");
++                        OFBitmanipTemplate<T>::zeroMem(Data[j] + InputCount, 
count);
++                    }
+                 } else {
+                     DCMIMAGE_DEBUG("cannot allocate memory buffer for 'Data[" 
<< j << "]' in DiColorPixelTemplate::Init()");
+                     result = 0;     // at least one buffer could not be 
allocated!
+--- dcmtk.orig/dcmimage/include/dcmtk/dcmimage/diybrpxt.h
++++ dcmtk/dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1998-2016, OFFIS e.V.
++ *  Copyright (C) 1998-2025, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -24,6 +24,7 @@
+ #define DIYBRPXT_H
+ 
+ #include "dcmtk/config/osconfig.h"
++#include "dcmtk/ofstd/ofbmanip.h"
+ 
+ #include "dcmtk/dcmimage/dicopxt.h"
+ #include "dcmtk/dcmimgle/diinpx.h"  /* gcc 3.4 needs this */
+@@ -90,179 +91,189 @@
+             // use the number of input pixels derived from the length of the 
'PixelData'
+             // attribute), but not more than the size of the intermediate 
buffer
+             const unsigned long count = (this->InputCount < this->Count) ? 
this->InputCount : this->Count;
+-            if (rgb)    /* convert to RGB model */
++            // make sure that there is sufficient input data (for planar 
pixel data)
++            if (!this->PlanarConfiguration || (count >= planeSize * 3 /* 
number of planes */))
+             {
+-                T2 *r = this->Data[0];
+-                T2 *g = this->Data[1];
+-                T2 *b = this->Data[2];
+-                const T2 maxvalue = OFstatic_cast(T2, 
DicomImageClass::maxval(bits));
+-                DiPixelRepresentationTemplate<T1> rep;
+-                if (bits == 8 && !rep.isSigned())          // only for 
unsigned 8 bit
++                if (rgb)    /* convert to RGB model */
+                 {
+-                    Sint16 rcr_tab[256];
+-                    Sint16 gcb_tab[256];
+-                    Sint16 gcr_tab[256];
+-                    Sint16 bcb_tab[256];
+-                    const double r_const = 0.7010 * OFstatic_cast(double, 
maxvalue);
+-                    const double g_const = 0.5291 * OFstatic_cast(double, 
maxvalue);
+-                    const double b_const = 0.8859 * OFstatic_cast(double, 
maxvalue);
+-                    unsigned long l;
+-                    for (l = 0; l < 256; ++l)
++                    T2 *r = this->Data[0];
++                    T2 *g = this->Data[1];
++                    T2 *b = this->Data[2];
++                    const T2 maxvalue = OFstatic_cast(T2, 
DicomImageClass::maxval(bits));
++                    DiPixelRepresentationTemplate<T1> rep;
++                    if (bits == 8 && !rep.isSigned())          // only for 
unsigned 8 bit
+                     {
+-                        rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * 
OFstatic_cast(double, l) - r_const);
+-                        gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * 
OFstatic_cast(double, l));
+-                        gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * 
OFstatic_cast(double, l) - g_const);
+-                        bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * 
OFstatic_cast(double, l) - b_const);
+-                    }
+-                    Sint32 sr;
+-                    Sint32 sg;
+-                    Sint32 sb;
+-                    if (this->PlanarConfiguration)
+-                    {
+-/*
+-                        const T1 *y = pixel;
+-                        const T1 *cb = y + this->InputCount;
+-                        const T1 *cr = cb + this->InputCount;
+-                        for (i = count; i != 0; --i, ++y, ++cb, ++cr)
++                        Sint16 rcr_tab[256];
++                        Sint16 gcb_tab[256];
++                        Sint16 gcr_tab[256];
++                        Sint16 bcb_tab[256];
++                        const double r_const = 0.7010 * OFstatic_cast(double, 
maxvalue);
++                        const double g_const = 0.5291 * OFstatic_cast(double, 
maxvalue);
++                        const double b_const = 0.8859 * OFstatic_cast(double, 
maxvalue);
++                        unsigned long l;
++                        for (l = 0; l < 256; ++l)
+                         {
+-                            sr = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, rcr_tab[*cr]);
+-                            sg = OFstatic_cast(Sint32, *y) - 
OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]);
+-                            sb = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, bcb_tab[*cb]);
+-                            *(r++) = (sr < 0) ? 0 : (sr > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
+-                            *(g++) = (sg < 0) ? 0 : (sg > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
+-                            *(b++) = (sb < 0) ? 0 : (sb > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
++                            rcr_tab[l] = OFstatic_cast(Sint16, 1.4020 * 
OFstatic_cast(double, l) - r_const);
++                            gcb_tab[l] = OFstatic_cast(Sint16, 0.3441 * 
OFstatic_cast(double, l));
++                            gcr_tab[l] = OFstatic_cast(Sint16, 0.7141 * 
OFstatic_cast(double, l) - g_const);
++                            bcb_tab[l] = OFstatic_cast(Sint16, 1.7720 * 
OFstatic_cast(double, l) - b_const);
+                         }
++                        Sint32 sr;
++                        Sint32 sg;
++                        Sint32 sb;
++                        if (this->PlanarConfiguration)
++                        {
++/*
++                            const T1 *y = pixel;
++                            const T1 *cb = y + this->InputCount;
++                            const T1 *cr = cb + this->InputCount;
++                            for (i = count; i != 0; --i, ++y, ++cb, ++cr)
++                            {
++                                sr = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, rcr_tab[*cr]);
++                                sg = OFstatic_cast(Sint32, *y) - 
OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]);
++                                sb = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, bcb_tab[*cb]);
++                                *(r++) = (sr < 0) ? 0 : (sr > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
++                                *(g++) = (sg < 0) ? 0 : (sg > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
++                                *(b++) = (sb < 0) ? 0 : (sb > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
++                            }
+ */
+-                        const T1 *y = pixel;
+-                        const T1 *cb = y + planeSize;
+-                        const T1 *cr = cb + planeSize;
+-                        unsigned long i = count;
+-                        while (i != 0)
++                            const T1 *y = pixel;
++                            const T1 *cb = y + planeSize;
++                            const T1 *cr = cb + planeSize;
++                            unsigned long i = count;
++                            while (i != 0)
++                            {
++                                /* convert a single frame */
++                                for (l = planeSize; (l != 0) && (i != 0); 
--l, --i, ++y, ++cb, ++cr)
++                                {
++                                    sr = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, rcr_tab[*cr]);
++                                    sg = OFstatic_cast(Sint32, *y) - 
OFstatic_cast(Sint32, gcb_tab[*cb]) - OFstatic_cast(Sint32, gcr_tab[*cr]);
++                                    sb = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, bcb_tab[*cb]);
++                                    *(r++) = (sr < 0) ? 0 : (sr > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
++                                    *(g++) = (sg < 0) ? 0 : (sg > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
++                                    *(b++) = (sb < 0) ? 0 : (sb > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
++                                }
++                                /* jump to next frame start (skip 2 planes) */
++                                y += 2 * planeSize;
++                                cb += 2 * planeSize;
++                                cr += 2 * planeSize;
++                            }
++                        }
++                        else
+                         {
+-                            /* convert a single frame */
+-                            for (l = planeSize; (l != 0) && (i != 0); --l, 
--i, ++y, ++cb, ++cr)
++                            const T1 *p = pixel;
++                            T1 y;
++                            T1 cb;
++                            T1 cr;
++                            unsigned long i;
++                            for (i = count; i != 0; --i)
+                             {
+-                                sr = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, *cr)]);
+-                                sg = OFstatic_cast(Sint32, *y) - 
OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, *cb)]) - 
OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, *cr)]);
+-                                sb = OFstatic_cast(Sint32, *y) + 
OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, *cb)]);
++                                y  = *(p++);
++                                cb = *(p++);
++                                cr = *(p++);
++                                sr = OFstatic_cast(Sint32, y) + 
OFstatic_cast(Sint32, rcr_tab[cr]);
++                                sg = OFstatic_cast(Sint32, y) - 
OFstatic_cast(Sint32, gcb_tab[cb]) - OFstatic_cast(Sint32, gcr_tab[cr]);
++                                sb = OFstatic_cast(Sint32, y) + 
OFstatic_cast(Sint32, bcb_tab[cb]);
+                                 *(r++) = (sr < 0) ? 0 : (sr > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
+                                 *(g++) = (sg < 0) ? 0 : (sg > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
+                                 *(b++) = (sb < 0) ? 0 : (sb > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
+                             }
+-                            /* jump to next frame start (skip 2 planes) */
+-                            y += 2 * planeSize;
+-                            cb += 2 * planeSize;
+-                            cr += 2 * planeSize;
+                         }
+                     }
+                     else
+                     {
+-                        const T1 *p = pixel;
+-                        T1 y;
+-                        T1 cb;
+-                        T1 cr;
+-                        unsigned long i;
+-                        for (i = count; i != 0; --i)
++                        if (this->PlanarConfiguration)
++                        {
++/*
++                            const T1 *y = pixel;
++                            const T1 *cb = y + this->InputCount;
++                            const T1 *cr = cb + this->InputCount;
++                            for (i = count; i != 0; --i)
++                                convertValue(*(r++), *(g++), *(b++), 
removeSign(*(y++), offset), removeSign(*(cb++), offset),
++                                    removeSign(*(cr++), offset), maxvalue);
++*/
++                            unsigned long l;
++                            unsigned long i = count;
++                            const T1 *y = pixel;
++                            const T1 *cb = y + planeSize;
++                            const T1 *cr = cb + planeSize;
++                            while (i != 0)
++                            {
++                                /* convert a single frame */
++                                for (l = planeSize; (l != 0) && (i != 0); 
--l, --i)
++                                {
++                                    convertValue(*(r++), *(g++), *(b++), 
removeSign(*(y++), offset), removeSign(*(cb++), offset),
++                                        removeSign(*(cr++), offset), 
maxvalue);
++                                }
++                                /* jump to next frame start (skip 2 planes) */
++                                y += 2 * planeSize;
++                                cb += 2 * planeSize;
++                                cr += 2 * planeSize;
++                            }
++                        }
++                        else
+                         {
+-                            y  = *(p++);
+-                            cb = *(p++);
+-                            cr = *(p++);
+-                            sr = OFstatic_cast(Sint32, y) + 
OFstatic_cast(Sint32, rcr_tab[OFstatic_cast(Uint32, cr)]);
+-                            sg = OFstatic_cast(Sint32, y) - 
OFstatic_cast(Sint32, gcb_tab[OFstatic_cast(Uint32, cb)]) - 
OFstatic_cast(Sint32, gcr_tab[OFstatic_cast(Uint32, cr)]);
+-                            sb = OFstatic_cast(Sint32, y) + 
OFstatic_cast(Sint32, bcb_tab[OFstatic_cast(Uint32, cb)]);
+-                            *(r++) = (sr < 0) ? 0 : (sr > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sr);
+-                            *(g++) = (sg < 0) ? 0 : (sg > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sg);
+-                            *(b++) = (sb < 0) ? 0 : (sb > 
OFstatic_cast(Sint32, maxvalue)) ? maxvalue : OFstatic_cast(T2, sb);
++                            const T1 *p = pixel;
++                            T2 y;
++                            T2 cb;
++                            T2 cr;
++                            unsigned long i;
++                            for (i = count; i != 0; --i)
++                            {
++                                y = removeSign(*(p++), offset);
++                                cb = removeSign(*(p++), offset);
++                                cr = removeSign(*(p++), offset);
++                                convertValue(*(r++), *(g++), *(b++), y, cb, 
cr, maxvalue);
++                            }
+                         }
+                     }
+-                }
+-                else
+-                {
++                } else {    /* retain YCbCr model */
++                    const T1 *p = pixel;
+                     if (this->PlanarConfiguration)
+                     {
+-/*
+-                        const T1 *y = pixel;
+-                        const T1 *cb = y + this->InputCount;
+-                        const T1 *cr = cb + this->InputCount;
+-                        for (i = count; i != 0; --i)
+-                            convertValue(*(r++), *(g++), *(b++), 
removeSign(*(y++), offset), removeSign(*(cb++), offset),
+-                                removeSign(*(cr++), offset), maxvalue);
+-*/
++    /*
++                        T2 *q;
++                        // number of pixels to be skipped (only applicable if 
'PixelData' contains more
++                        // pixels than expected)
++                        const unsigned long skip = (this->InputCount > 
this->Count) ? (this->InputCount - this->Count) : 0;
++                        for (int j = 0; j < 3; ++j)
++                        {
++                            q = this->Data[j];
++                            for (i = count; i != 0; --i)
++                                *(q++) = removeSign(*(p++), offset);
++                            // skip to beginning of next plane
++                            p += skip;
++                        }
++    */
+                         unsigned long l;
+-                        unsigned long i = count;
+-                        const T1 *y = pixel;
+-                        const T1 *cb = y + planeSize;
+-                        const T1 *cr = cb + planeSize;
+-                        while (i != 0)
++                        unsigned long i = 0;
++                        while (i < count)
+                         {
+-                            /* convert a single frame */
+-                            for (l = planeSize; (l != 0) && (i != 0); --l, 
--i)
++                            /* store current pixel index */
++                            const unsigned long iStart = i;
++                            for (int j = 0; j < 3; ++j)
+                             {
+-                                convertValue(*(r++), *(g++), *(b++), 
removeSign(*(y++), offset), removeSign(*(cb++), offset),
+-                                    removeSign(*(cr++), offset), maxvalue);
++                                /* convert a single plane */
++                                for (l = planeSize, i = iStart; (l != 0) && 
(i < count); --l, ++i)
++                                    this->Data[j][i] = removeSign(*(p++), 
offset);
+                             }
+-                            /* jump to next frame start (skip 2 planes) */
+-                            y += 2 * planeSize;
+-                            cb += 2 * planeSize;
+-                            cr += 2 * planeSize;
+                         }
+                     }
+                     else
+                     {
+-                        const T1 *p = pixel;
+-                        T2 y;
+-                        T2 cb;
+-                        T2 cr;
++                        int j;
+                         unsigned long i;
+-                        for (i = count; i != 0; --i)
+-                        {
+-                            y = removeSign(*(p++), offset);
+-                            cb = removeSign(*(p++), offset);
+-                            cr = removeSign(*(p++), offset);
+-                            convertValue(*(r++), *(g++), *(b++), y, cb, cr, 
maxvalue);
+-                        }
++                        for (i = 0; i < count; ++i)                           
  /* for all pixel ... */
++                            for (j = 0; j < 3; ++j)
++                                this->Data[j][i] = removeSign(*(p++), 
offset);  /* ... copy planes */
+                     }
+                 }
+-            } else {    /* retain YCbCr model */
+-                const T1 *p = pixel;
+-                if (this->PlanarConfiguration)
+-                {
+-/*
+-                    T2 *q;
+-                    // number of pixels to be skipped (only applicable if 
'PixelData' contains more
+-                    // pixels than expected)
+-                    const unsigned long skip = (this->InputCount > 
this->Count) ? (this->InputCount - this->Count) : 0;
+-                    for (int j = 0; j < 3; ++j)
+-                    {
+-                        q = this->Data[j];
+-                        for (i = count; i != 0; --i)
+-                            *(q++) = removeSign(*(p++), offset);
+-                        // skip to beginning of next plane
+-                        p += skip;
+-                    }
+-*/
+-                    unsigned long l;
+-                    unsigned long i = 0;
+-                    while (i < count)
+-                    {
+-                        /* store current pixel index */
+-                        const unsigned long iStart = i;
+-                        for (int j = 0; j < 3; ++j)
+-                        {
+-                            /* convert a single plane */
+-                            for (l = planeSize, i = iStart; (l != 0) && (i < 
count); --l, ++i)
+-                                this->Data[j][i] = removeSign(*(p++), offset);
+-                        }
+-                    }
+-                }
+-                else
+-                {
+-                    int j;
+-                    unsigned long i;
+-                    for (i = 0; i < count; ++i)                             
/* for all pixel ... */
+-                        for (j = 0; j < 3; ++j)
+-                            this->Data[j][i] = removeSign(*(p++), offset);  
/* ... copy planes */
+-                }
++            } else {
++                // do not process the input data, as it is too short
++                DCMIMAGE_WARN("input data is too short, filling the complete 
image with black pixels");
++                // erase empty part of the buffer (that has not been 
"blackened" yet)
++                for (int j = 0; j < 3; ++j)
++                    OFBitmanipTemplate<T2>::zeroMem(this->Data[j], count);
+             }
+         }
+     }
+--- dcmtk.orig/dcmimgle/libsrc/dcmimage.cc
++++ dcmtk/dcmimgle/libsrc/dcmimage.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1996-2021, 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
+@@ -210,6 +210,7 @@
+                         *(q++) = c;
+                 }
+                 *q = '\0';                                          // end of 
C string
++                DCMIMGLE_DEBUG("filtered version of 
'PhotometricInterpretation' = " << OFSTRING_GUARD(cstr));
+                 while ((pin->Name != NULL) && (strcmp(pin->Name, cstr) != 0))
+                     ++pin;
+                 delete[] cstr;
diff -Nru dcmtk-3.6.7/debian/patches/0015-CVE-2025-9732b.patch 
dcmtk-3.6.7/debian/patches/0015-CVE-2025-9732b.patch
--- dcmtk-3.6.7/debian/patches/0015-CVE-2025-9732b.patch        1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0015-CVE-2025-9732b.patch        2026-06-12 
20:33:06.000000000 +0200
@@ -0,0 +1,40 @@
+commit 3de96da6cd66b1af7224561c568bc3de50cd1398
+Author: Joerg Riesmeier <[email protected]>
+Date:   Mon Aug 18 17:58:56 2025 +0200
+
+    Fixed issue with commit 7ad81d69b.
+    
+    Fixed an issue with recently committed changes that fix a problem with
+    invalid YBR_FULL images
+
+diff --git a/dcmimage/include/dcmtk/dcmimage/diybrpxt.h 
b/dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+index c5415c149..fdaaafc2d 100644
+--- a/dcmimage/include/dcmtk/dcmimage/diybrpxt.h
++++ b/dcmimage/include/dcmtk/dcmimage/diybrpxt.h
+@@ -92,7 +92,7 @@ class DiYBRPixelTemplate
+             // attribute), but not more than the size of the intermediate 
buffer
+             const unsigned long count = (this->InputCount < this->Count) ? 
this->InputCount : this->Count;
+             // make sure that there is sufficient input data (for planar 
pixel data)
+-            if (!this->PlanarConfiguration || (count >= planeSize * 3 /* 
number of planes */))
++            if (!this->PlanarConfiguration || (count >= planeSize))
+             {
+                 if (rgb)    /* convert to RGB model */
+                 {
+@@ -231,7 +231,7 @@ class DiYBRPixelTemplate
+                     const T1 *p = pixel;
+                     if (this->PlanarConfiguration)
+                     {
+-    /*
++/*
+                         T2 *q;
+                         // number of pixels to be skipped (only applicable if 
'PixelData' contains more
+                         // pixels than expected)
+@@ -244,7 +244,7 @@ class DiYBRPixelTemplate
+                             // skip to beginning of next plane
+                             p += skip;
+                         }
+-    */
++*/
+                         unsigned long l;
+                         unsigned long i = 0;
+                         while (i < count)
diff -Nru dcmtk-3.6.7/debian/patches/0016-CVE-2025-14607.patch 
dcmtk-3.6.7/debian/patches/0016-CVE-2025-14607.patch
--- dcmtk-3.6.7/debian/patches/0016-CVE-2025-14607.patch        1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0016-CVE-2025-14607.patch        2026-06-12 
20:35:47.000000000 +0200
@@ -0,0 +1,31 @@
+commit 4c0e5c10079392c594d6a7abd95dd78ac0aa556a
+Author: Marco Eichelberg <[email protected]>
+Date:   Tue Dec 2 09:06:30 2025 +0100
+
+    Fixed bug in handling of odd-length data elements.
+    
+    When a dataset containing an illegal odd-length attribute with a text VR
+    was read from file or received over a network connection, then accessing
+    the value of that attribute with DcmElement::getString() may return a
+    pointer to a string that was not properly null terminated. Using C string
+    functions such as strlen() or strcpy() on that string then lead to a read
+    beyond the end of a string, causing a segmentation fault.
+    
+    Thanks to Zou Dikai <[email protected]> for the bug report and POC.
+    
+    This closes DCMTK issue #1184.
+
+--- dcmtk.orig/dcmdata/libsrc/dcbytstr.cc
++++ dcmtk/dcmdata/libsrc/dcbytstr.cc
+@@ -658,7 +658,11 @@
+ 
+         /* terminate string after real length */
+         if (value != NULL)
++        {
+             value[lengthField] = 0;
++            value[lengthField+1] = 0;
++        }
++
+         /* enforce old (pre DCMTK 3.5.2) behaviour? */
+         if (!dcmAcceptOddAttributeLength.get())
+         {
diff -Nru dcmtk-3.6.7/debian/patches/0017-CVE-2025-14841.patch 
dcmtk-3.6.7/debian/patches/0017-CVE-2025-14841.patch
--- dcmtk-3.6.7/debian/patches/0017-CVE-2025-14841.patch        1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0017-CVE-2025-14841.patch        2026-06-12 
20:37:59.000000000 +0200
@@ -0,0 +1,37 @@
+commit ffb1a4a37d2c876e3feeb31df4930f2aed7fa030
+Author: Marco Eichelberg <[email protected]>
+Date:   Fri Nov 28 12:24:07 2025 +0100
+
+    Fixed two possible segfaults in dcmqrscp.
+    
+    Fixed two places where invalid messages may trigger a segmentation fault
+    due to a NULL pointer being de-referenced.
+    
+    Thanks to 邹 迪凯 <[email protected]> for the bug report and 
proof-of-concept.
+
+--- dcmtk.orig/dcmqrdb/libsrc/dcmqrdbi.cc
++++ dcmtk/dcmqrdb/libsrc/dcmqrdbi.cc
+@@ -1381,8 +1381,10 @@
+                 /* only char string type tags are supported at the moment */
+                 char *s = NULL;
+                 dcelem->getString(s);
++
+                 /* the available space is always elem.ValueLength+1 */
+-                OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
++                if (s) OFStandard::strlcpy(elem.PValueField, s, 
elem.ValueLength+1);
++                    else elem.PValueField[0]='\0';
+             }
+             /** If element is the Query Level, store it in handle
+              */
+@@ -2066,8 +2068,10 @@
+                 /* only char string type tags are supported at the moment */
+                 char *s = NULL;
+                 dcelem->getString(s);
++
+                 /* the available space is always elem.ValueLength+1 */
+-                OFStandard::strlcpy(elem.PValueField, s, elem.ValueLength+1);
++                if (s) OFStandard::strlcpy(elem.PValueField, s, 
elem.ValueLength+1);
++                    else elem.PValueField[0]='\0';
+             }
+ 
+             /** If element is the Query Level, store it in handle
diff -Nru dcmtk-3.6.7/debian/patches/0018-CVE-2026-5663.patch 
dcmtk-3.6.7/debian/patches/0018-CVE-2026-5663.patch
--- dcmtk-3.6.7/debian/patches/0018-CVE-2026-5663.patch 1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0018-CVE-2026-5663.patch 2026-06-12 
20:59:14.000000000 +0200
@@ -0,0 +1,274 @@
+commit edbb085e45788dccaf0e64d71534cfca925784b8
+Author: Marco Eichelberg <[email protected]>
+Date:   Sat Mar 21 18:35:14 2026 +0100
+
+    Sanitize all strings passed to the exec options.
+    
+    Sanitize the text fields from incoming DICOM associations and DICOM objects
+    (such as Study Instance UID, SOP Instance UID, Patient's Name) and the
+    calling SCU's network presentation address by removing special characters
+    that may be interpreted as shell escape characters when one of the
+    execution options (e.g. --exec-on-reception) is in use.
+    
+    Thanks to Machine Spirits UG (haftungsbeschränkt) for the bug report,
+    detailed analysis and proof of concept.
+    
+    This closes DCMTK issue #1194.
+
+--- dcmtk.orig/dcmnet/apps/storescp.cc
++++ dcmtk/dcmnet/apps/storescp.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1994-2021, OFFIS e.V.
++ *  Copyright (C) 1994-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -201,6 +201,41 @@
+ #define SHORTCOL 4
+ #define LONGCOL 21
+ 
++// Allow list used by sanitizeAETitle(). Index is (byte - 32), so the
++// table covers the printable ASCII range 0x20..0x7E. Every entry either
++// repeats the input byte (kept) or is '_' (replaced). Kept characters:
++// space, '-', '.', ':', '@', '_' and ASCII letters/digits. All shell
++// metacharacters and path separators map to '_'.
++static const char sanitized_aetitle_charset[] =
++{
++  ' ', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '-', '.', 
'_',
++  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '_', '_', '_', '_', 
'_',
++  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 
'O',
++  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '_', '_', '_', 
'_',
++  '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
'o',
++  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '_', '_', '_', 
'_'
++};
++
++
++inline void sanitizeAETitle(OFString& aetitle)
++{
++    // Preserve a surrounding pair of quotation marks (used by callers
++    // that substitute the AE title into an already quoted shell argument).
++    size_t len = aetitle.length();
++    size_t start = 0;
++    if (len >= 2 && aetitle[0] == '"' && aetitle[len - 1] == '"')
++    {
++        start = 1;
++        --len;
++    }
++    for (size_t i = start; i < len; ++i)
++    {
++        unsigned char c = OFstatic_cast(unsigned char, aetitle[i]);
++        if (c < 32 || c >= 127) aetitle[i] = '_';
++        else aetitle[i] = sanitized_aetitle_charset[c - 32];
++    }
++}
++
+ int main(int argc, char *argv[])
+ {
+   T_ASC_Network *net;
+@@ -1474,7 +1509,9 @@
+     calledAETitle.clear();
+   }
+   // store calling presentation address (i.e. remote hostname)
+-  callingPresentationAddress = 
OFSTRING_GUARD(assoc->params->DULparams.callingPresentationAddress);
++  callingPresentationAddress = "\"";
++  callingPresentationAddress += 
OFSTRING_GUARD(assoc->params->DULparams.callingPresentationAddress);
++  callingPresentationAddress += "\"";
+ 
+   /* now do the real work, i.e. receive DIMSE commands over the network 
connection */
+   /* which was established and handle these commands correspondingly. In case 
of */
+@@ -1838,6 +1875,7 @@
+             dateTime.getTime().getHour(), dateTime.getTime().getMinute(), 
dateTime.getTime().getIntSecond(), dateTime.getTime().getMilliSecond());
+ 
+           OFString subdirectoryName;
++          OFString s;
+           switch (opt_sortStudyMode)
+           {
+             case ESM_Timestamp:
+@@ -1852,15 +1890,27 @@
+               subdirectoryName = opt_sortStudyDirPrefix;
+               if (!subdirectoryName.empty())
+                 subdirectoryName += '_';
+-              subdirectoryName += currentStudyInstanceUID;
+-              OFStandard::sanitizeFilename(subdirectoryName);
++              s = currentStudyInstanceUID;
++              OFStandard::sanitizeFilename(s);
++              if (s != currentStudyInstanceUID)
++              {
++                OFLOG_WARN(storescpLogger, "Sanitized unusual characters in 
Study Instance UID, converted from \"" << currentStudyInstanceUID << "\" to \"" 
<< s << "\".");
++              }
++              subdirectoryName += s;
+               break;
+             case ESM_PatientName:
+               // pattern: "[Patient's Name]_[YYYYMMDD]_[HHMMSSMMM]"
+               subdirectoryName = currentPatientName;
++              OFStandard::sanitizeFilename(subdirectoryName);
++              if (subdirectoryName != currentPatientName)
++              {
++                // It is quite normal that we need to sanitize characters in 
PatientName.
++                // Therefore, this is only a debug message and not a warning, 
unlike the other
++                // messages about sanitized fields, which are normally not 
expected.
++                OFLOG_DEBUG(storescpLogger, "Sanitized characters in Patient 
Name, converted from \"" << currentPatientName << "\" to \"" << 
subdirectoryName << "\".");
++              }
+               subdirectoryName += '_';
+               subdirectoryName += timestamp;
+-              OFStandard::sanitizeFilename(subdirectoryName);
+               break;
+             case ESM_None:
+               break;
+@@ -2068,8 +2118,13 @@
+     else
+     {
+       // Use the SOP instance UID as found in the C-STORE request message as 
part of the filename
+-      OFString uid = req->AffectedSOPInstanceUID;
++      OFString s(OFSTRING_GUARD(req->AffectedSOPInstanceUID));
++      OFString uid = s;
+       OFStandard::sanitizeFilename(uid);
++      if (uid != s)
++      {
++        OFLOG_WARN(storescpLogger, "Sanitized unusual characters in SOP 
Instance UID, converted from \"" << s << "\" to \"" << uid << "\".");
++      }
+       sprintf(imageFileName, "%s%c%s.%s%s", opt_outputDirectory.c_str(), 
PATH_SEPARATOR, dcmSOPClassUIDToModality(req->AffectedSOPClassUID, "UNKNOWN"),
+         uid.c_str(), opt_fileNameExtension.c_str());
+     }
+@@ -2202,28 +2257,40 @@
+      */
+ {
+   OFString cmd = opt_execOnReception;
++  OFString s;
+ 
+   // in case a file was actually written
+   if( !opt_ignore )
+   {
+     // perform substitution for placeholder #p (depending on presence of any 
--sort-xxx option)
++    // Note: We do not enclose this in quotes because it may be used as part 
of a path expression.
+     OFString dir = (opt_sortStudyMode == ESM_None) ? opt_outputDirectory : 
subdirectoryPathAndName;
+     cmd = replaceChars( cmd, OFString(PATH_PLACEHOLDER), dir );
+ 
+     // perform substitution for placeholder #f; note that 
outputFileNameArray.back()
+     // always contains the name of the file (without path) which was written 
last.
++    // Note: We do not enclose this in quotes because it may be used as part 
of a path expression.
+     OFString outputFileName = outputFileNameArray.back();
+     cmd = replaceChars( cmd, OFString(FILENAME_PLACEHOLDER), outputFileName );
+   }
+ 
+-  // perform substitution for placeholder #a
++  // perform substitution for placeholder #a.
++  // Note that this string is already enclosed in double quotes at this point
+   cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), 
callingAETitle );
+ 
+-  // perform substitution for placeholder #c
++  // perform substitution for placeholder #c.
++  // Note that this string is already enclosed in double quotes at this point
+   cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), 
calledAETitle );
+ 
+-  // perform substitution for placeholder #r
+-  cmd = replaceChars( cmd, 
OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), callingPresentationAddress 
);
++  // perform substitution for placeholder #r.
++  // Note that this string is already enclosed in double quotes at this point
++  s = callingPresentationAddress;
++  sanitizeAETitle(s);
++  if (s != callingPresentationAddress)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling 
presentation address, converted from " << callingPresentationAddress << " to " 
<< s << ".");
++  }
++  cmd = replaceChars( cmd, 
OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), s );
+ 
+   // Execute command in a new process
+   executeCommand( cmd );
+@@ -2325,18 +2392,41 @@
+      */
+ {
+   OFString cmd = opt_execOnEndOfStudy;
++  OFString s;
+ 
+   // perform substitution for placeholder #p; #p will be substituted by 
lastStudySubdirectoryPathAndName
++  // Note: We do not enclose this in quotes because it may be used as part of 
a path expression.
+   cmd = replaceChars( cmd, OFString(PATH_PLACEHOLDER), 
lastStudySubdirectoryPathAndName );
+ 
+-  // perform substitution for placeholder #a
+-  cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), 
callingAETitle );
++  // perform substitution for placeholder #a.
++  // Note that this string is already enclosed in double quotes at this point
++  s = callingAETitle;
++  sanitizeAETitle(s);
++  if (s != callingAETitle)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling 
aetitle, converted from " << callingAETitle << " to " << s << ".");
++  }
++  cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #c
+-  cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), 
calledAETitle );
++  // perform substitution for placeholder #c.
++  // Note that this string is already enclosed in double quotes at this point
++  s = calledAETitle;
++  sanitizeAETitle(s);
++  if (s != calledAETitle)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in called 
aetitle, converted from " << calledAETitle << " to " << s << ".");
++  }
++  cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), s );
+ 
+-  // perform substitution for placeholder #r
+-  cmd = replaceChars( cmd, 
OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), callingPresentationAddress 
);
++  // perform substitution for placeholder #r.
++  // Note that this string is already enclosed in double quotes at this point
++  s = callingPresentationAddress;
++  sanitizeAETitle(s);
++  if (s != callingPresentationAddress)
++  {
++    OFLOG_WARN(storescpLogger, "Sanitized unusual characters in calling 
presentation address, converted from " << callingPresentationAddress << " to " 
<< s << ".");
++  }
++  cmd = replaceChars( cmd, 
OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), s );
+ 
+   // Execute command in a new process
+   executeCommand( cmd );
+--- dcmtk.orig/ofstd/libsrc/ofstd.cc
++++ dcmtk/ofstd/libsrc/ofstd.cc
+@@ -3246,16 +3246,26 @@
+ }
+ 
+ 
++static const char sanitized_filename_charset[] =
++{
++  ' ', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '-', '.', 
'_',
++  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '_', '_', '_', '_', 
'_',
++  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 
'O',
++  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '_', '_', '_', 
'_',
++  '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
'o',
++  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '_', '_', '_', 
'_'
++};
++
++
+ void OFStandard::sanitizeFilename(OFString& fname)
+ {
+   size_t len = fname.length();
++  char c;
+   for (size_t i=0; i<len; ++i)
+   {
+-#ifdef _WIN32
+-        if ((fname[i] == PATH_SEPARATOR)||(fname[i] == '/')) fname[i] = '_';
+-#else
+-        if (fname[i] == PATH_SEPARATOR) fname[i] = '_';
+-#endif
++        c = fname[i];
++        if (c != 0 && (c < 32 || c >= 127)) c = '_'; else c = 
sanitized_filename_charset[c-32];
++        fname[i] = c;
+   }
+ }
+ 
+@@ -3267,11 +3277,7 @@
+     char *c = fname;
+     while (*c)
+     {
+-#ifdef _WIN32
+-      if ((*c == PATH_SEPARATOR)||(*c == '/')) *c = '_';
+-#else
+-      if (*c == PATH_SEPARATOR) *c = '_';
+-#endif
++      if (*c < 32 || *c >= 127) *c = '_'; else *c = 
sanitized_filename_charset[*c-32];
+       ++c;
+     }
+   }
diff -Nru dcmtk-3.6.7/debian/patches/0019-CVE-2026-10194.patch 
dcmtk-3.6.7/debian/patches/0019-CVE-2026-10194.patch
--- dcmtk-3.6.7/debian/patches/0019-CVE-2026-10194.patch        1970-01-01 
01:00:00.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/0019-CVE-2026-10194.patch        2026-06-12 
20:57:41.000000000 +0200
@@ -0,0 +1,66 @@
+commit 0f78a4ef6f645ea5530166e445e5436a5de58e75
+Author: Marco Eichelberg <[email protected]>
+Date:   Mon May 4 17:48:30 2026 +0200
+
+    Fixed remote heap buffer overflow in dcmqrscp.
+    
+    Thanks to 'elp3pinill0' for the bug report, detailed
+    analysis, proof of concept and proposed fix.
+    
+    This closes DCMTK issue #1206.
+
+--- dcmtk.orig/dcmqrdb/libsrc/dcmqrdbi.cc
++++ dcmtk/dcmqrdb/libsrc/dcmqrdbi.cc
+@@ -1,6 +1,6 @@
+ /*
+  *
+- *  Copyright (C) 1993-2022, OFFIS e.V.
++ *  Copyright (C) 1993-2026, OFFIS e.V.
+  *  All rights reserved.  See COPYRIGHT file for details.
+  *
+  *  This software and supporting documentation were developed by
+@@ -2475,12 +2475,16 @@
+ 
+     DB_IdxInitLoop (&(handle_ -> idxCounter)) ;
+     while ( DB_IdxGetNext(&(handle_ -> idxCounter), &idxRec) == EC_Normal ) {
+-    if ( ! ( strncmp(idxRec. StudyInstanceUID, StudyUID, n) ) ) {
+-
+-        StudyArray[nbimages]. idxCounter = handle_ -> idxCounter ;
+-        StudyArray[nbimages]. RecordedDate = idxRec. RecordedDate ;
+-        StudyArray[nbimages++]. ImageSize = idxRec. ImageSize ;
+-    }
++        if ( ! ( strncmp(idxRec. StudyInstanceUID, StudyUID, n) ) ) {
++            StudyArray[nbimages]. idxCounter = handle_ -> idxCounter ;
++            StudyArray[nbimages]. RecordedDate = idxRec. RecordedDate ;
++            StudyArray[nbimages++]. ImageSize = idxRec. ImageSize ;
++            if (nbimages == MAX_NUMBER_OF_IMAGES) {
++                // too many images in this study, bail out
++                DCMQRDB_ERROR("maximum number of images per study (" << 
MAX_NUMBER_OF_IMAGES << ") exceeded");
++                return QR_EC_IndexDatabaseError;
++            }
++        }
+     }
+ 
+     /** Sort the StudyArray in order to have the oldest images first
+@@ -2567,6 +2571,8 @@
+     s = matchStudyUIDInStudyDesc (pStudyDesc, StudyUID,
+                      (int)(handle_ -> maxStudiesAllowed)) ;
+ 
++    OFCondition cond;
++
+     /** If Study already exists
+      */
+ 
+@@ -2587,10 +2593,10 @@
+ 
+         RequiredSize = imageSize -
+             ( handle_ -> maxBytesPerStudy - pStudyDesc[s]. StudySize ) ;
+-        deleteOldestImages(pStudyDesc, s, StudyUID, RequiredSize) ;
++        cond = deleteOldestImages(pStudyDesc, s, StudyUID, RequiredSize) ;
++        if (cond.bad()) return cond;
+     }
+ 
+-
+     }
+     else {
+ #ifdef DEBUG
diff -Nru dcmtk-3.6.7/debian/patches/series dcmtk-3.6.7/debian/patches/series
--- dcmtk-3.6.7/debian/patches/series   2025-02-20 21:57:29.000000000 +0100
+++ dcmtk-3.6.7/debian/patches/series   2026-06-12 20:57:47.000000000 +0200
@@ -21,3 +21,11 @@
 0009-CVE-2025-25475.patch
 0010-CVE-2025-25474.patch
 0011-CVE-2025-25472.patch
+0012-CVE-2022-4981.patch
+0013-CVE-2025-2357.patch
+0014-CVE-2025-9732.patch
+0015-CVE-2025-9732b.patch
+0016-CVE-2025-14607.patch
+0017-CVE-2025-14841.patch
+0018-CVE-2026-5663.patch
+0019-CVE-2026-10194.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to