Hi SRMs, Since the opening of the present request, a new issue cropped up in dcmtk, also affecting bookworm. For reference, the change is the bookworm equivalent of the trixie-proposed-updates #1140693, except the present upload never occurred, hence no version bump. You will find below my revised form, including the new change.
> [ 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. * CVE-2026-12805, described in #1140562. > 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. I stand by the assessment. CVE-2026-12805 is marked no-dsa. > [ Impact ] > If the update is not approved, then dcmtk will continue being > affected by the above items. I have nothing to change here. > [ 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. I carried similar testing for this revision. > [ 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. The last minute patch consists in an effective single line in a patch straight from upstream commit. > [ 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 [*] attach updated debdiff > [ 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. 0020-CVE-2026-12805.patch fixes the buffer overflow referenced under CVE-2026-12805 by properly checking for ftell(3) error codes. > [ 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. I have not much to add regarding other information. I just hope the form is readable and not too confusing this way. Have a nice day, :) -- .''`. Étienne Mollier <[email protected]> : :' : pgp: 8f91 b227 c7d6 f2b1 948c 8236 793c f67e 8f0d 11da `. `' sent from /dev/pts/2, 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-24 21:16:40.000000000 +0200 @@ -1,3 +1,23 @@ +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) + * 0020-CVE-2026-12805.patch: new: fix CVE-2026-12805. + This patch fixes a risk of buffer overflow by ensuring negative error + codes in XMLNode::parseFile are properly handled, as well a NULL + values. (Closes: #1140562) + + -- Étienne Mollier <[email protected]> Wed, 24 Jun 2026 21:16:40 +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-24 21:12:59.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-24 21:12:59.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-24 21:12:59.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-24 21:12:59.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-24 21:12:59.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-23 21:27: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-24 21:12:59.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-24 21:12:59.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/0020-CVE-2026-12805.patch dcmtk-3.6.7/debian/patches/0020-CVE-2026-12805.patch --- dcmtk-3.6.7/debian/patches/0020-CVE-2026-12805.patch 1970-01-01 01:00:00.000000000 +0100 +++ dcmtk-3.6.7/debian/patches/0020-CVE-2026-12805.patch 2026-06-24 21:14:39.000000000 +0200 @@ -0,0 +1,34 @@ +commit 1d4b3815c0987840a983160bfc671fef63a3105b +Author: Marco Eichelberg <[email protected]> +Date: Sat May 23 17:07:58 2026 +0200 + + Fixed buffer overflow in XMLNode::parseFile(). + + Fixed a heap buffer overflow that could occur in the XML parser + when reading from a named pipe. + + Thanks to Cristhian Daniel Rivas Zúñiga and Sebastian Andres Muñoz Morera + (Insituto Tecnológico de Costa Rica) for the bug report and fix. + + This closes DCMTK issue #1208. + +--- dcmtk.orig/ofstd/libsrc/ofxml.cc ++++ dcmtk/ofstd/libsrc/ofxml.cc +@@ -1,6 +1,6 @@ + /* + * +- * Copyright (C) 2011-2021, OFFIS e.V. ++ * Copyright (C) 2011-2026, OFFIS e.V. + * All rights reserved. See COPYRIGHT file for details. + * + * This software and supporting documentation were slightly modified by +@@ -1962,7 +1962,8 @@ + if (f==NULL) { if (pResults) pResults->error=eXMLErrorFileNotFound; return emptyXMLNode; } + fseek(f,0,SEEK_END); + int l=OFstatic_cast(int, ftell(f)),headerSz=0; +- if (!l) { if (pResults) pResults->error=eXMLErrorEmpty; fclose(f); return emptyXMLNode; } ++ // DCMTK: handle situation where ftell() returns -1 ++ if (l <= 0) { if (pResults) pResults->error=eXMLErrorEmpty; fclose(f); return emptyXMLNode; } + fseek(f,0,SEEK_SET); + unsigned char *buf=OFreinterpret_cast(unsigned char*, malloc(l+4)); + l=OFstatic_cast(int, fread(buf,1,l,f)); 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-24 21:14:45.000000000 +0200 @@ -21,3 +21,12 @@ 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 +0020-CVE-2026-12805.patch
signature.asc
Description: PGP signature

