CVE-2021-46389 (published 2022-02-07T14:15Z)

IIPImage High Resolution Streaming Image Server prior to commit 882925b295a80ec992063deffc2a3b0d803c3195 is affected by an integer overflow in iipsrv.fcgi through malformed HTTP query parameters.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/ruven/iipsrv
commit_details: repo_url: https://github.com/ruven/iipsrv
author: ruven
author_date: 2022-01-14 23:22:09+01:00
msg: Added verification that image has been set in SPECTRA.cc and check on the validity of the requested tile resolution in JTL.cc. Fixes a couple of the crash conditions reported in https://github.com/ruven/iipsrv/issues/223
repository: repo_url: https://github.com/ruven/iipsrv
repo_name: ruven/iipsrv
description: iipsrv is an advanced high-performance feature-rich image server for web-based streamed viewing and zooming of ultra high-resolution images.
repo_language: C++
owner: ruven
file_changes: filename: ChangeLog
change_type: ModificationType.MODIFY
diff: @@ -1,3 +1,8 @@
+15/01/2022:
+	- Added verification that image has been set in SPECTRA.cc and check on the validity of the requested tile
+	  resolution in JTL.cc. Fixes a couple of the crash conditions reported in https://github.com/ruven/iipsrv/issues/223
+
+
 14/01/2022:
 	- Detection of HTJ2K also added for KakaduImage.cc for logging purposes (DEBUG needs to be enabled at compile time)
 

programming_language: Markdown
filename: JTL.cc
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 /*
     IIP JTL Command Handler Class Member Function: Export a single tile
 
-    Copyright (C) 2006-2021 Ruven Pillay.
+    Copyright (C) 2006-2022 Ruven Pillay.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -43,6 +43,10 @@ void JTL::send( Session* session, int resolution, int tile ){
   if( session->loglevel >= 2 ) command_timer.start();
 
 
+  // Need to know the number of resolutions
+  int num_res = (*session->image)->getNumResolutions();
+
+
   // If we have requested a rotation, remap the tile index to rotated coordinates
   if( (int)((session->view)->getRotation()) % 360 == 90 ){
 
@@ -51,7 +55,6 @@ void JTL::send( Session* session, int resolution, int tile ){
 
   }
   else if( (int)((session->view)->getRotation()) % 360 == 180 ){
-    int num_res = (*session->image)->getNumResolutions();
     unsigned int im_width = (*session->image)->image_widths[num_res-resolution-1];
     unsigned int im_height = (*session->image)->image_heights[num_res-resolution-1];
     unsigned int tw = (*session->image)->getTileWidth();
@@ -62,7 +65,7 @@ void JTL::send( Session* session, int resolution, int tile ){
 
 
   // Sanity check
-  if( (resolution<0) || (tile<0) ){
+  if( (resolution<0) || (tile<0) || (resolution>=num_res) ){
     ostringstream error;
     error << "JTL :: Invalid resolution/tile number: " << resolution << "," << tile;
     throw error.str();
@@ -120,18 +123,20 @@ void JTL::send( Session* session, int resolution, int tile ){
 
 
   // Set the physical output resolution for this particular view and zoom level
-  int num_res = (*session->image)->getNumResolutions();
-  unsigned int im_width = (*session->image)->image_widths[num_res-resolution-1];
-  unsigned int im_height = (*session->image)->image_heights[num_res-resolution-1];
-  float dpi_x = (*session->image)->dpi_x * (float) im_width / (float) (*session->image)->getImageWidth();
-  float dpi_y = (*session->image)->dpi_y * (float) im_height / (float) (*session->image)->getImageHeight();
-  compressor->setResolution( dpi_x, dpi_y, (*session->image)->dpi_units );
-
-  if( session->loglevel >= 5 ){
-    *(session->logfile) << "JTL :: Setting physical resolution of tile to " <<  dpi_x << " x " << dpi_y
-                        << ( ((*session->image)->dpi_units==1) ? " pixels/inch" : " pixels/cm" ) << endl;
+  if( (*session->image)->dpi_x > 0 && (*session->image)->dpi_y > 0 ){
+    unsigned int im_width = (*session->image)->image_widths[num_res-resolution-1];
+    unsigned int im_height = (*session->image)->image_heights[num_res-resolution-1];
+    float dpi_x = (*session->image)->dpi_x * ( (float)im_width / (float)(*session->image)->getImageWidth() );
+    float dpi_y = (*session->image)->dpi_y * ( (float)im_height / (float)(*session->image)->getImageHeight() );
+    compressor->setResolution( dpi_x, dpi_y, (*session->image)->dpi_units );
+
+    if( session->loglevel >= 5 ){
+      *(session->logfile) << "JTL :: Setting physical resolution of tile to " <<  dpi_x << " x " << dpi_y
+			  << ( ((*session->image)->dpi_units==1) ? " pixels/inch" : " pixels/cm" ) << endl;
+    }
   }
 
+
   // Embed ICC profile
   if( session->view->embedICC() && ((*session->image)->getMetadata("icc").size()>0) ){
     if( session->loglevel >= 3 ){

programming_language: C++
filename: SPECTRA.cc
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 /*
     IIP SPECTRA Command Handler Class Member Function
 
-    Copyright (C) 2009-2021 Ruven Pillay.
+    Copyright (C) 2009-2022 Ruven Pillay.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -36,7 +36,10 @@ void SPECTRA::run( Session* session, const std::string& argument ){
 
   if( session->loglevel >= 3 ) (*session->logfile) << "SPECTRA handler reached" << endl;
 
-  int resolution, tile, x, y;
+
+  // Make sure we have set our image
+  this->session = session;
+  checkImage();
 
 
   // Time this command
@@ -46,19 +49,19 @@ void SPECTRA::run( Session* session, const std::string& argument ){
   // Parse the argument list
   string arg = argument;
   int delimitter = arg.find( "," );
-  resolution = atoi( arg.substr(0,delimitter).c_str() );
+  int resolution = atoi( arg.substr(0,delimitter).c_str() );
 
   arg = arg.substr( delimitter + 1, arg.length() );
   delimitter = arg.find( "," );
-  tile = atoi( arg.substr(0,delimitter).c_str() );
+  int tile = atoi( arg.substr(0,delimitter).c_str() );
 
   arg = arg.substr( delimitter + 1, arg.length() );
   delimitter = arg.find( "," );
-  x = atoi( arg.substr(0,delimitter).c_str() );
+  int x = atoi( arg.substr(0,delimitter).c_str() );
 
   arg = arg.substr( delimitter + 1, arg.length() );
   delimitter = arg.find( "," );
-  y = atoi( arg.substr(0,arg.length()).c_str() );
+  int y = atoi( arg.substr(0,arg.length()).c_str() );
 
   if( session->loglevel >= 5 ){ 
     (*session->logfile) << "SPECTRA :: resolution: " << resolution

programming_language: C++
repo_url: https://github.com/ruven/iipsrv
commit_details: repo_url: https://github.com/ruven/iipsrv
author: ruven
author_date: 2022-01-16 14:34:07+01:00
msg: - Modified TileManager.cc to verify that malloc() has correctly allocated memory.
- Updated numerical types to std::size_t in RawTile.h, TileManager.cc, KakaduImage.cc, OpenJPEG.cc and Transforms.cc when allocating memory via new to avoid integer overflow - fixes remaining problems identified in https://github.com/ruven/iipsrv/issues/223.
repository: repo_url: https://github.com/ruven/iipsrv
repo_name: ruven/iipsrv
description: iipsrv is an advanced high-performance feature-rich image server for web-based streamed viewing and zooming of ultra high-resolution images.
repo_language: C++
owner: ruven
file_changes: filename: ChangeLog
change_type: ModificationType.MODIFY
diff: @@ -1,3 +1,10 @@
+16/01/2022:
+	- Modified TileManager.cc to verify that malloc() has correctly allocated memory.
+	- Updated numerical types to std::size_t in RawTile.h, TileManager.cc, KakaduImage.cc, OpenJPEG.cc and Transforms.cc
+	  when allocating memory via new to avoid integer overflow - fixes remaining problems identified in
+	  https://github.com/ruven/iipsrv/issues/223.
+
+
 15/01/2022:
 	- Added verification that image has been set in SPECTRA.cc and check on the validity of the requested tile
 	  resolution in JTL.cc. Fixes a couple of the crash conditions reported in https://github.com/ruven/iipsrv/issues/223

programming_language: Markdown
filename: KakaduImage.cc
change_type: ModificationType.MODIFY
diff: @@ -447,11 +447,12 @@ RawTile KakaduImage::getRegion( int seq, int ang, unsigned int res, int layers,
 
   RawTile rawtile( 0, res, seq, ang, w, h, channels, obpc );
 
-  if( obpc == 16 ) rawtile.data = new unsigned short[w*h*channels];
-  else if( obpc == 8 ) rawtile.data = new unsigned char[w*h*channels];
+  size_t np = (size_t) w * (size_t) h * (size_t) channels;
+  if( obpc == 16 ) rawtile.data = new unsigned short[np];
+  else if( obpc == 8 ) rawtile.data = new unsigned char[np];
   else throw file_error( "Kakadu :: Unsupported number of bits" );
 
-  rawtile.dataLength = w*h*channels*(obpc/8);
+  rawtile.dataLength = np*(obpc/8);
   rawtile.filename = getImagePath();
   rawtile.timestamp = timestamp;
 

programming_language: C++
filename: OpenJPEGImage.cc
change_type: ModificationType.MODIFY
diff: @@ -376,11 +376,12 @@ RawTile OpenJPEGImage::getRegion( int ha, int va, unsigned int res, int layers,
 
   RawTile rawtile( 0, res, ha, va, w, h, channels, obpc );
 
-  if( obpc == 16 ) rawtile.data = new unsigned short[w * h * channels];
-  else if( obpc == 8 ) rawtile.data = new unsigned char[w * h * channels];
+  size_t np = (size_t) w * (size_t) h * (size_t) channels;
+  if( obpc == 16 ) rawtile.data = new unsigned short[np];
+  else if( obpc == 8 ) rawtile.data = new unsigned char[np];
   else throw file_error( "OpenJPEG :: Unsupported number of bits" );
 
-  rawtile.dataLength = w*h*channels*(obpc/8);
+  rawtile.dataLength = np*(obpc/8);
   rawtile.filename = getImagePath();
   rawtile.timestamp = timestamp;
 

programming_language: C++
filename: RawTile.h
change_type: ModificationType.MODIFY
diff: @@ -79,7 +79,7 @@ class RawTile{
   int memoryManaged;
 
   /// The size of the data pointed to by data
-  unsigned int dataLength;
+  size_t dataLength;
 
   /// The width in pixels of this tile
   unsigned int width;

programming_language: C++
filename: TileManager.cc
change_type: ModificationType.MODIFY
diff: @@ -4,7 +4,7 @@
 
 /*  IIP Server: Tile Cache Handler
 
-    Copyright (C) 2005-2021 Ruven Pillay.
+    Copyright (C) 2005-2022 Ruven Pillay.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -130,8 +130,14 @@ void TileManager::crop( RawTile *ttt ){
 
   // Create a new buffer, fill it with the old data, then copy
   // back the cropped part into the RawTile buffer
-  int len = tw * th * ttt->channels * (ttt->bpc/8);
+  unsigned int len = tw * th * ttt->channels * (ttt->bpc/8);
   unsigned char* buffer = (unsigned char*) malloc( len );
+
+  // Check whether we have successfully allocated memory via malloc
+  if( buffer == NULL ){
+    std::bad_alloc e;
+    throw e;
+  }
   unsigned char* src_ptr = (unsigned char*) memcpy( buffer, ttt->data, len );
   unsigned char* dst_ptr = (unsigned char*) ttt->data;
 
@@ -365,21 +371,22 @@ RawTile TileManager::getRegion( unsigned int res, int seq, int ang, int layers,
 
   // Create an empty tile with the correct dimensions
   RawTile region( 0, res, seq, ang, width, height, channels, bpc );
-  region.dataLength = width * height * channels * (bpc/8);
+  size_t np = (size_t) width * (size_t) height * (size_t) channels;
+  region.dataLength = np * (bpc/8);
   region.sampleType = sampleType;
 
   // Allocate memory for the region
-  if( bpc == 8 ) region.data = new unsigned char[width*height*channels];
-  else if( bpc == 16 ) region.data = new unsigned short[width*height*channels];
-  else if( bpc == 32 && sampleType == FIXEDPOINT ) region.data = new int[width*height*channels];
-  else if( bpc == 32 && sampleType == FLOATINGPOINT ) region.data = new float[width*height*channels];
+  if( bpc == 8 ) region.data = new unsigned char[np];
+  else if( bpc == 16 ) region.data = new unsigned short[np];
+  else if( bpc == 32 && sampleType == FIXEDPOINT ) region.data = new int[np];
+  else if( bpc == 32 && sampleType == FLOATINGPOINT ) region.data = new float[np];
 
   unsigned int current_height = 0;
 
   // Decode the image strip by strip
   for( unsigned int i=starty; i<endy; i++ ){
 
-    unsigned int buffer_index = 0;
+    unsigned long buffer_index = 0;
 
     // Keep track of the current pixel boundary horizontally. ie. only up
     //  to the beginning of the current tile boundary.

programming_language: C++
filename: Transforms.cc
change_type: ModificationType.MODIFY
diff: @@ -532,7 +532,7 @@ void Transform::interpolate_nearestneighbour( RawTile& in, unsigned int resample
   // Correctly set our Rawtile info
   in.width = resampled_width;
   in.height = resampled_height;
-  in.dataLength = resampled_width * resampled_height * channels * (in.bpc/8);
+  in.dataLength = (size_t)resampled_width * (size_t)resampled_height * (size_t)channels * (size_t)(in.bpc/8);
   in.data = output;
 }
 
@@ -618,7 +618,7 @@ void Transform::interpolate_bilinear( RawTile& in, unsigned int resampled_width,
   // Correctly set our Rawtile info
   in.width = resampled_width;
   in.height = resampled_height;
-  in.dataLength = resampled_width * resampled_height * channels * (in.bpc/8);
+  in.dataLength = (size_t)resampled_width * (size_t)resampled_height * (size_t)channels * (size_t)(in.bpc/8);
   in.data = output;
 }
 

programming_language: C++