From 72fdf1f684565cf968b18834a0c80dab8531831a Mon Sep 17 00:00:00 2001 From: yangjinlin01 Date: Wed, 8 Apr 2026 10:52:29 +0800 Subject: [PATCH] [CVE] [upstream] FIX CVE-2026-5663 to #32926 add patch to fix CVE-2026-5663 commit edbb085e45788dccaf0e64d71534cfca925784b8 upstream. Project: TC2024080204 Signed-off-by: yangjinlin01 --- ...l-strings-passed-to-the-exec-options.patch | 241 ++++++++++++++++++ dcmtk.spec | 7 +- 2 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 0019-Sanitize-all-strings-passed-to-the-exec-options.patch diff --git a/0019-Sanitize-all-strings-passed-to-the-exec-options.patch b/0019-Sanitize-all-strings-passed-to-the-exec-options.patch new file mode 100644 index 0000000..750c101 --- /dev/null +++ b/0019-Sanitize-all-strings-passed-to-the-exec-options.patch @@ -0,0 +1,241 @@ +From edbb085e45788dccaf0e64d71534cfca925784b8 Mon Sep 17 00:00:00 2001 +From: Marco Eichelberg +Date: Sat, 21 Mar 2026 18:35:14 +0100 +Subject: [PATCH] Sanitize all strings passed to the exec options. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +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. +--- + dcmnet/apps/storescp.cc | 77 +++++++++++++++++++++++++++++++++-------- + ofstd/libsrc/ofstd.cc | 26 ++++++++------ + 2 files changed, 79 insertions(+), 24 deletions(-) + +diff --git a/dcmnet/apps/storescp.cc b/dcmnet/apps/storescp.cc +index 7a69a16144..183c92f1e0 100644 +--- a/dcmnet/apps/storescp.cc ++++ b/dcmnet/apps/storescp.cc +@@ -1,6 +1,6 @@ + /* + * +- * Copyright (C) 1994-2025, 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 +@@ -1601,7 +1601,9 @@ static OFCondition acceptAssociation(T_ASC_Network *net, DcmAssociationConfigura + 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 */ +@@ -1965,6 +1967,7 @@ storeSCPCallback( + dateTime.getTime().getHour(), dateTime.getTime().getMinute(), dateTime.getTime().getIntSecond(), dateTime.getTime().getMilliSecond()); + + OFString subdirectoryName; ++ OFString s; + switch (opt_sortStudyMode) + { + case ESM_Timestamp: +@@ -1979,15 +1982,27 @@ storeSCPCallback( + 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; +@@ -2196,8 +2211,13 @@ static OFCondition storeSCP( + else + { + // Use the SOP instance UID as found in the C-STORE request message as part of the filename +- OFString uid(OFSTRING_GUARD(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 << "\"."); ++ } + OFStandard::snprintf(imageFileName, sizeof(imageFileName), "%s%c%s.%s%s", opt_outputDirectory.c_str(), PATH_SEPARATOR, dcmSOPClassUIDToModality(req->AffectedSOPClassUID, "UNKNOWN"), + uid.c_str(), opt_fileNameExtension.c_str()); + } +@@ -2367,16 +2387,19 @@ static void executeOnReception() + 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 + s = callingAETitle; + sanitizeAETitle(s); + if (s != callingAETitle) +@@ -2385,7 +2408,8 @@ static void executeOnReception() + } + cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), s ); + +- // perform substitution for placeholder #c ++ // 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) +@@ -2394,8 +2418,15 @@ static void executeOnReception() + } + 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 ); +@@ -2500,20 +2531,38 @@ static void executeOnEndOfStudy() + 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 ++ // 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 ++ // 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 ); +diff --git a/ofstd/libsrc/ofstd.cc b/ofstd/libsrc/ofstd.cc +index c2742a540d..bee606d69d 100644 +--- a/ofstd/libsrc/ofstd.cc ++++ b/ofstd/libsrc/ofstd.cc +@@ -3405,16 +3405,26 @@ void OFStandard::forceSleep(Uint32 seconds) + } + + ++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) + { + const 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; + } + } + +@@ -3426,11 +3436,7 @@ void OFStandard::sanitizeFilename(char *fname) + 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 --git a/dcmtk.spec b/dcmtk.spec index 08e5bba..31f6ae3 100644 --- a/dcmtk.spec +++ b/dcmtk.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %global abi_version 20 %bcond_with charls2 @@ -34,6 +34,8 @@ Patch: 0016-Update-JpegLsEncode-for-CharLS-2.patch %endif Patch: 0017-Increase-sleep-for-tests.patch Patch: 0018-chore-undo-changes-to-standard-dirs.patch +# https://github.com/DCMTK/dcmtk/commit/edbb085e45788dccaf0e64d71534cfca925784b8 +Patch: 0019-Sanitize-all-strings-passed-to-the-exec-options.patch BuildRequires: gcc BuildRequires: gcc-c++ @@ -235,6 +237,9 @@ rm -f $RPM_BUILD_ROOT%{_datadir}/%{name}/wlistdb/OFFIS/lockfile %{_libdir}/libofstd.so %changelog +* Wed Apr 08 2026 yangjinlin01 - 3.7.0-2 +- fix CVE-2026-5663 + * Fri Dec 19 2025 lzq11122 - 3.7.0-1 - Update to 3.7.0 for fix CVE-2025-9732 CVE-2025-14841 and CVE-2025-14607 - Remove patch new version included -- Gitee