[mapserver-commits] r7383 - trunk/mapserver

svn at osgeo.org svn at osgeo.org
Thu Feb 14 10:02:58 EST 2008


Author: sdlime
Date: 2008-02-14 10:02:58 -0500 (Thu, 14 Feb 2008)
New Revision: 7383

Modified:
   trunk/mapserver/mapshape.c
Log:
Applied patch to avoid crashing on corrupt shapefiles. (bug 2510)

Modified: trunk/mapserver/mapshape.c
===================================================================
--- trunk/mapserver/mapshape.c	2008-02-13 20:12:40 UTC (rev 7382)
+++ trunk/mapserver/mapshape.c	2008-02-14 15:02:58 UTC (rev 7383)
@@ -285,6 +285,16 @@
   psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256 + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
   psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
   
+  if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
+  {
+    msSetError(MS_SHPERR, "Corrupted .shp file : nRecords = %d.", "msSHPOpen()",
+               psSHP->nRecords);
+    fclose( psSHP->fpSHP );
+    fclose( psSHP->fpSHX );
+    free( psSHP );
+    return( NULL );
+  }
+  
   psSHP->nShapeType = pabyBuf[32];
   
   if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
@@ -330,6 +340,20 @@
   psSHP->panRecSize = (int *) malloc(sizeof(int) * psSHP->nMaxRecords );
   
   pabyBuf = (uchar *) malloc(8 * psSHP->nRecords );
+  if (psSHP->panRecOffset == NULL ||
+      psSHP->panRecSize == NULL ||
+      pabyBuf == NULL)
+  {
+    free(psSHP->panRecOffset);
+    free(psSHP->panRecOffset);
+    free( pabyBuf );
+    fclose( psSHP->fpSHP );
+    fclose( psSHP->fpSHX );
+    free( psSHP );
+    msSetError(MS_MEMERR, "Out of memory", "msSHPOpen()");
+    return( NULL );
+  }
+
   fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX );
   
   for( i = 0; i < psSHP->nRecords; i++ ) {
@@ -931,10 +955,42 @@
 }
 
 /*
+ ** msSHPReadAllocateBuffer() - Ensure our record buffer is large enough.
+ */
+static int msSHPReadAllocateBuffer( SHPHandle psSHP, int hEntity, const char* pszCallingFunction)
+{
+  int nEntitySize = psSHP->panRecSize[hEntity]+8;
+  /* -------------------------------------------------------------------- */
+  /*      Ensure our record buffer is large enough.                       */
+  /* -------------------------------------------------------------------- */
+  if( nEntitySize > psSHP->nBufSize ) {
+    psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
+    if (psSHP->pabyRec == NULL)
+    {
+        /* Reallocate previous successfull size for following features */
+        psSHP->pabyRec = malloc(psSHP->nBufSize);
+
+        msSetError(MS_MEMERR, "Out of memory. Cannot allocate %d bytes. Probably broken shapefile at feature %d",
+                   pszCallingFunction, nEntitySize, hEntity);
+        return(MS_FAILURE);
+    }
+    psSHP->nBufSize = nEntitySize;
+  }
+  if (psSHP->pabyRec == NULL)
+  {
+    msSetError(MS_MEMERR, "Out of memory", pszCallingFunction);
+    return(MS_FAILURE);
+  }
+  return MS_SUCCESS;
+}
+
+/*
 ** msSHPReadPoint() - Reads a single point from a POINT shape file.
 */
 int msSHPReadPoint( SHPHandle psSHP, int hEntity, pointObj *point )
 {
+  int nEntitySize;
+
   /* -------------------------------------------------------------------- */
   /*      Only valid for point shapefiles                                 */
   /* -------------------------------------------------------------------- */
@@ -951,24 +1007,28 @@
     return(MS_FAILURE);
   }
 
+  nEntitySize = psSHP->panRecSize[hEntity]+8;
+
   if( psSHP->panRecSize[hEntity] == 4 ) {
     msSetError(MS_SHPERR, "NULL feature encountered.", "msSHPReadPoint()");
     return(MS_FAILURE);
-  }   
+  }
+  else if ( nEntitySize < 28 ) {
+    msSetError(MS_SHPERR, "Corrupted feature encountered.  hEntity=%d, nEntitySize=%d", "msSHPReadPoint()",
+               hEntity, nEntitySize);
+    return(MS_FAILURE);
+  }
 
-  /* -------------------------------------------------------------------- */
-  /*      Ensure our record buffer is large enough.                       */
-  /* -------------------------------------------------------------------- */
-  if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize ) {
-    psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
-    psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
-  }    
+  if (msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadPoint()") == MS_FAILURE)
+  {
+    return MS_FAILURE;
+  }
 
   /* -------------------------------------------------------------------- */
   /*      Read the record.                                                */
   /* -------------------------------------------------------------------- */
   fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
-  fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
+  fread( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP );
       
   memcpy( &(point->x), psSHP->pabyRec + 12, 8 );
   memcpy( &(point->y), psSHP->pabyRec + 20, 8 );
@@ -990,6 +1050,7 @@
 #ifdef USE_POINT_Z_M
   int nOffset = 0;
 #endif
+  int nEntitySize, nRequiredSize;
 
   msInitShape(shape); /* initialize the shape */
 
@@ -1004,19 +1065,18 @@
     return;
   }
 
-  /* -------------------------------------------------------------------- */
-  /*      Ensure our record buffer is large enough.                       */
-  /* -------------------------------------------------------------------- */
-  if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize ) {
-    psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
-    psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
-  }    
+  nEntitySize = psSHP->panRecSize[hEntity]+8;
+  if (msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadShape()") == MS_FAILURE)
+  {
+    shape->type = MS_SHAPE_NULL;
+    return;
+  }
 
   /* -------------------------------------------------------------------- */
   /*      Read the record.                                                */
   /* -------------------------------------------------------------------- */
   fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 );
-  fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP );
+  fread( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP );
 
   /* -------------------------------------------------------------------- */
   /*  Extract vertices for a Polygon or Arc.				    */
@@ -1026,6 +1086,14 @@
       psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ)
   {
     ms_int32  nPoints, nParts;      
+    
+    if (nEntitySize < 40 + 8 + 4)
+    {
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted feature encountered.  hEntity = %d, nEntitySize=%d", "msSHPReadShape()",
+                 hEntity, nEntitySize);
+      return;
+    }
 
     /* copy the bounding box */
     memcpy( &shape->bounds.minx, psSHP->pabyRec + 8 + 4, 8 );
@@ -1048,13 +1116,49 @@
       SwapWord( 4, &nParts );
     }
 
+    if (nPoints < 0 || nParts < 0 || 
+        nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) 
+    {
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted feature encountered.  hEntity = %d, nPoints =%d, nParts = %d", "msSHPReadShape()",
+                 hEntity, nPoints, nParts);
+      return;
+    }
+    
     /* -------------------------------------------------------------------- */
     /*      Copy out the part array from the record.                        */
     /* -------------------------------------------------------------------- */
     if( psSHP->nPartMax < nParts ) {
+      psSHP->panParts = (int *) SfRealloc(psSHP->panParts, nParts * sizeof(int) );
+      if (psSHP->panParts == NULL)
+      {
+        /* Reallocate previous successfull size for following features */ 
+        psSHP->panParts = (int *) malloc(psSHP->nPartMax * sizeof(int) );
+
+        shape->type = MS_SHAPE_NULL;
+        msSetError(MS_MEMERR, "Out of memory. Cannot allocate %d bytes. Probably broken shapefile at feature %d",
+                   "msSHPReadShape()", nParts * sizeof(int), hEntity);
+        return;
+      }
       psSHP->nPartMax = nParts;
-      psSHP->panParts = (int *) SfRealloc(psSHP->panParts, psSHP->nPartMax * sizeof(int) );
     }
+    if (psSHP->panParts == NULL)
+    {
+       shape->type = MS_SHAPE_NULL;
+       msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
+       return;
+    }
+    
+    /* With the previous checks on nPoints and nParts, */
+    /* we should not overflow here and after */
+    /* since 50 M * (16 + 8 + 8) = 1 600 MB */
+    if (44 + 8 + 4 * nParts + 16 * nPoints > nEntitySize)
+    {
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
+                 "msSHPReadShape()", hEntity, nPoints, nParts);
+      return;
+    }
       
     memcpy( psSHP->panParts, psSHP->pabyRec + 44 + 8, 4 * nParts );
     for( i = 0; i < nParts; i++ )
@@ -1064,7 +1168,8 @@
     /*      Fill the shape structure.                                       */
     /* -------------------------------------------------------------------- */
     if( (shape->line = (lineObj *)malloc(sizeof(lineObj)*nParts)) == NULL ) {
-      msSetError(MS_MEMERR, NULL, "SHPReadShape()");
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_MEMERR, NULL, "msSHPReadShape()");
       return;
     }
 
@@ -1076,10 +1181,25 @@
         shape->line[i].numpoints = nPoints - psSHP->panParts[i];
       else
         shape->line[i].numpoints = psSHP->panParts[i+1] - psSHP->panParts[i];
+      if (shape->line[i].numpoints <= 0)
+      {
+        msSetError(MS_SHPERR, "Corrupted .shp file : shape %d, shape->line[%d].numpoints=%d", "msSHPReadShape()",
+                   hEntity, i, shape->line[i].numpoints);
+        while(--i >= 0)
+          free(shape->line[i].point);
+        free(shape->line);
+        shape->numlines = 0;
+        shape->type = MS_SHAPE_NULL;
+        return;
+      }
 	
       if( (shape->line[i].point = (pointObj *)malloc(sizeof(pointObj)*shape->line[i].numpoints)) == NULL ) {
+        while(--i >= 0)
+          free(shape->line[i].point);
         free(shape->line);
         shape->numlines = 0;
+        shape->type = MS_SHAPE_NULL;
+        msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
         return;
       }
 
@@ -1100,7 +1220,7 @@
         shape->line[i].point[j].z = 0.0; /* initialize */
         if (psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ) {
           nOffset = 44 + 8 + (4*nParts) + (16*nPoints) ;
-          if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) {
+          if( nEntitySize >= nOffset + 16 + 8*nPoints ) {
             memcpy(&(shape->line[i].point[j].z), psSHP->pabyRec + nOffset + 16 + k*8, 8 );
             if( bBigEndian ) SwapWord( 8, &(shape->line[i].point[j].z) );
           }   
@@ -1112,7 +1232,7 @@
         shape->line[i].point[j].m = 0; /* initialize */
         if (psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM) {
           nOffset = 44 + 8 + (4*nParts) + (16*nPoints) ;
-          if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) {
+          if( nEntitySize >= nOffset + 16 + 8*nPoints ) {
             memcpy(&(shape->line[i].point[j].m), psSHP->pabyRec + nOffset + 16 + k*8, 8 );
             if( bBigEndian ) SwapWord( 8, &(shape->line[i].point[j].m) );
           }   
@@ -1138,6 +1258,14 @@
            psSHP->nShapeType == SHP_MULTIPOINTZ) {
     ms_int32 nPoints;
 
+    if (nEntitySize < 44 + 4)
+    {
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted feature encountered.  psSHP->panRecSize[%d]=%d", "msSHPReadShape()",
+                 hEntity, psSHP->panRecSize[hEntity]);
+      return;
+    }
+
     /* copy the bounding box */
     memcpy( &shape->bounds.minx, psSHP->pabyRec + 8 + 4, 8 );
     memcpy( &shape->bounds.miny, psSHP->pabyRec + 8 + 12, 8 );
@@ -1158,13 +1286,43 @@
     /*      Fill the shape structure.                                       */
     /* -------------------------------------------------------------------- */
     if( (shape->line = (lineObj *)malloc(sizeof(lineObj))) == NULL ) {
-      msSetError(MS_MEMERR, NULL, "SHPReadShape()");
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
       return;
     }
 
+    if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
+    {
+      free(shape->line);
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted .shp file : shape %d, nPoints=%d.",
+                 "msSHPReadShape()", hEntity, nPoints);
+      return;
+    }
+
+    nRequiredSize = 48 + nPoints * 16;
+    if (psSHP->nShapeType == SHP_MULTIPOINTZ || psSHP->nShapeType == SHP_MULTIPOINTM)
+        nRequiredSize += 16 + nPoints * 8;
+    if (nRequiredSize > nEntitySize)
+    {
+      free(shape->line);
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
+                 "msSHPReadShape()", hEntity, nPoints, nEntitySize); 
+      return;
+    }
+
     shape->numlines = 1;
     shape->line[0].numpoints = nPoints;
     shape->line[0].point = (pointObj *) malloc( nPoints * sizeof(pointObj) );
+    if (shape->line[0].point == NULL)
+    {
+      free(shape->line);
+      shape->numlines = 0;
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
+      return;
+    }
       
     for( i = 0; i < nPoints; i++ ) {
       memcpy(&(shape->line[0].point[i].x), psSHP->pabyRec + 48 + 16 * i, 8 );
@@ -1207,11 +1365,19 @@
   else if(psSHP->nShapeType == SHP_POINT ||  psSHP->nShapeType == SHP_POINTM ||
           psSHP->nShapeType == SHP_POINTZ) {    
 
+    if (nEntitySize < 20 + 8)
+    {
+      shape->type = MS_SHAPE_NULL;
+      msSetError(MS_SHPERR, "Corrupted feature encountered.  psSHP->panRecSize[%d]=%d", "msSHPReadShape()",
+                 hEntity, psSHP->panRecSize[hEntity]);
+      return;
+    }
+
     /* -------------------------------------------------------------------- */
     /*      Fill the shape structure.                                       */
     /* -------------------------------------------------------------------- */
     if( (shape->line = (lineObj *)malloc(sizeof(lineObj))) == NULL ) {
-      msSetError(MS_MEMERR, NULL, "SHPReadShape()");
+      msSetError(MS_MEMERR, NULL, "msSHPReadShape()");
       return;
     }
 
@@ -1234,7 +1400,7 @@
     shape->line[0].point[0].z = 0; /* initialize */
     if (psSHP->nShapeType == SHP_POINTZ) {
       nOffset = 20 + 8;
-      if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 ) {
+      if( nEntitySize >= nOffset + 8 ) {
         memcpy(&(shape->line[0].point[0].z), psSHP->pabyRec + nOffset, 8 );        
         if( bBigEndian ) SwapWord( 8, &(shape->line[0].point[0].z));
       }
@@ -1246,7 +1412,7 @@
     shape->line[0].point[0].m = 0; /* initialize */
     if (psSHP->nShapeType == SHP_POINTM) {
       nOffset = 20 + 8;
-      if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 ) {
+      if( nEntitySize >= nOffset + 8 ) {
         memcpy(&(shape->line[0].point[0].m), psSHP->pabyRec + nOffset, 8 );
         if( bBigEndian ) SwapWord( 8, &(shape->line[0].point[0].m));
       }



More information about the mapserver-commits mailing list