CVE-2021-46389: Integer Overflow or Wraparound (CWE-190)
value: IIPImage High Resolution Streaming Image Server prior to commit 882925b295a80ec992063deffc2a3b0d803c3195 is affected by an integer overflow in iipsrv.fcgi through malformed HTTP query parameters.
CWE 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.
CVSS v3 base score: 7.5
Published: 2022-02-07T14:15Z
Repository: https://github.com/ruven/iipsrv
Language: C++
Files changed: ChangeLog, src/JTL.cc, src/SPECTRA.cc
Commit date: 2022-01-14 23:22:09 +0100
Commit message: 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

Diff: diff --git a/ChangeLog b/ChangeLog
index ea906d8..6725c69 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
+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)
 
 
 07/01/2022:
diff --git a/src/JTL.cc b/src/JTL.cc
index 4d75c68..4d48af9 100644
--- a/src/JTL.cc
+++ b/src/JTL.cc
@@ -1,9 +1,9 @@
 /*
     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
     the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
@@ -41,30 +41,33 @@ void JTL::send( Session* session, int resolution, int tile ){
 
   // Time this command
   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 ){
 
   }
   else if( (int)((session->view)->getRotation()) % 360 == 270 ){
 
   }
   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();
     //    unsigned int th = (*session->image)->getTileHeight();
     int ntiles = (int) ceil( (double)im_width/tw ) * (int) ceil( (double)im_height/tw );
     tile = ntiles - tile - 1;
   }
 
 
   // 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();
   }
 
@@ -118,22 +121,24 @@ void JTL::send( Session* session, int resolution, int tile ){
       || session->view->getRotation() != 0.0 || session->view->flip != 0
       ) ct = UNCOMPRESSED;
 
 
   // 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 ){
       *(session->logfile) << "JTL :: Embedding ICC profile with size "
 			  << (*session->image)->getMetadata("icc").size() << " bytes" << endl;
diff --git a/src/SPECTRA.cc b/src/SPECTRA.cc
index c07c9de..500e207 100644
--- a/src/SPECTRA.cc
+++ b/src/SPECTRA.cc
@@ -1,9 +1,9 @@
 /*
     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
     the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
@@ -34,33 +34,36 @@ void SPECTRA::run( Session* session, const std::string& argument ){
      4) pixel index in y direction
   */
 
   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
   if( session->loglevel >= 2 ) command_timer.start();
 
 
   // 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
 			<< ", tile: " << tile
 			<< ", x: " << x

Vulnerable code:     Copyright (C) 2006-2021 Ruven Pillay.
    int num_res = (*session->image)->getNumResolutions();
  if( (resolution<0) || (tile<0) ){
  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;
    Copyright (C) 2009-2021 Ruven Pillay.
  int resolution, tile, x, y;
  resolution = atoi( arg.substr(0,delimitter).c_str() );
  tile = atoi( arg.substr(0,delimitter).c_str() );
  x = atoi( arg.substr(0,delimitter).c_str() );
  y = atoi( arg.substr(0,arg.length()).c_str() );
Fixed code: 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


    Copyright (C) 2006-2022 Ruven Pillay.
  // Need to know the number of resolutions
  int num_res = (*session->image)->getNumResolutions();


  if( (resolution<0) || (tile<0) || (resolution>=num_res) ){
  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;
    }

    Copyright (C) 2009-2022 Ruven Pillay.

  // Make sure we have set our image
  this->session = session;
  checkImage();
  int resolution = atoi( arg.substr(0,delimitter).c_str() );
  int tile = atoi( arg.substr(0,delimitter).c_str() );
  int x = atoi( arg.substr(0,delimitter).c_str() );
  int y = atoi( arg.substr(0,arg.length()).c_str() );