changeset 6646:f1140bd7ed65 machine-spirits

Fix possible overflow when calling /tools/create-dicom with a PAM file
author Alain Mazy <am@orthanc.team>
date Tue, 03 Mar 2026 16:04:54 +0100
parents b8e78ccac532
children 983a74f5b875
files NEWS OrthancFramework/Sources/Images/PamReader.cpp
diffstat 2 files changed, 21 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Mar 20 09:32:16 2026 +0100
+++ b/NEWS	Tue Mar 03 16:04:54 2026 +0100
@@ -143,6 +143,7 @@
   - Avoid adding twice the same tag in DB for the same resource, e.g. when
     "TimeZoneOffsetFromUTC" is added to the "ExtraMainDicomTags" at Patient level.
     https://discourse.orthanc-server.org/t/jobs-api-the-dicommovescu-job-doesnt-seems-to-track-progress/3140/14
+  - Fix possible overflow when calling /tools/create-dicom with a PAM file.
 * Upgraded dependencies for static builds:
   - civetweb 1.16, including patch for CVE-2025-55763
   - SQLite 3.50.4
--- a/OrthancFramework/Sources/Images/PamReader.cpp	Fri Mar 20 09:32:16 2026 +0100
+++ b/OrthancFramework/Sources/Images/PamReader.cpp	Tue Mar 03 16:04:54 2026 +0100
@@ -38,6 +38,7 @@
 #include <boost/algorithm/string/find.hpp>
 #include <boost/lexical_cast.hpp>
 
+static const uint64_t MAX_PAM_IMAGE_BUFFER_SIZE = 4ul * 1024ul * 1024ul * 1024ul;
 
 namespace Orthanc
 {
@@ -181,11 +182,28 @@
     const unsigned int maxValue = LookupIntegerParameter(parameters, "MAXVAL");
     const std::string tupleType = LookupStringParameter(parameters, "TUPLTYPE");
 
+    if (width > 65535 || height > 65535 || channelCount > 4 || maxValue > 65535)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat, "PAM header values exceed reasonable limits");
+    }
+
     unsigned int bytesPerChannel;
     PixelFormat format;
     GetPixelFormat(format, bytesPerChannel, maxValue, channelCount, tupleType);
 
-    unsigned int pitch = width * channelCount * bytesPerChannel;
+    // unsigned int pitch = width * channelCount * bytesPerChannel;
+    uint64_t pitch = static_cast<uint64_t>(width) * channelCount * bytesPerChannel;
+
+    if (pitch > std::numeric_limits<unsigned int>::max())
+    {
+      throw OrthancException(ErrorCode_BadFileFormat, "PAM dimensions exceed limits");
+    }
+
+    uint64_t totalSize = pitch * height;
+    if (totalSize > MAX_PAM_IMAGE_BUFFER_SIZE)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat, "PAM image too large");
+    }
 
     if (content_.size() != header.size() + headerDelimiter.size() + pitch * height)
     {
@@ -196,7 +214,7 @@
 
     {
       intptr_t bufferAddr = reinterpret_cast<intptr_t>(&content_[offset]);
-      if((bufferAddr % 8) == 0)
+      if ((bufferAddr % 8) == 0)
         LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr;
       else
         LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr << " (not a multiple of 8!)";