/ Check-in [9e5add51]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Experimental changes to prevent buffer overreads when parsing a corrupt database file.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | no-overread
Files: files | file ages | folders
SHA1: 9e5add51eead8e2e938870df0d0071854cadf414
User & Date: drh 2012-01-03 21:33:26
Context
2012-01-03
21:33
Experimental changes to prevent buffer overreads when parsing a corrupt database file. Closed-Leaf check-in: 9e5add51 user: drh tags: no-overread
14:50
Make sure filenames passed into sqlite3OsOpen() always have the extra zero-terminators needed by sqlite3_uri_parameter(). check-in: d73e93cf user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

   897    897   static void btreeParseCellPtr(
   898    898     MemPage *pPage,         /* Page containing the cell */
   899    899     u8 *pCell,              /* Pointer to the cell text. */
   900    900     CellInfo *pInfo         /* Fill in this structure */
   901    901   ){
   902    902     u16 n;                  /* Number bytes in cell content header */
   903    903     u32 nPayload;           /* Number of bytes of cell payload */
          904  +  u8 cellBuf[20];
   904    905   
   905    906     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
   906    907   
   907    908     pInfo->pCell = pCell;
          909  +  if( pCell >= pPage->aDataEnd - sizeof(cellBuf) && pCell < pPage->aDataEnd ){
          910  +    int x = pPage->aDataEnd - pCell;
          911  +    memcpy(cellBuf, pCell, x);
          912  +    memset(&cellBuf[x], 0, sizeof(cellBuf)-x);
          913  +    pCell = cellBuf;
          914  +  }
   908    915     assert( pPage->leaf==0 || pPage->leaf==1 );
   909    916     n = pPage->childPtrSize;
   910    917     assert( n==4-4*pPage->leaf );
   911    918     if( pPage->intKey ){
   912    919       if( pPage->hasData ){
   913    920         n += getVarint32(&pCell[n], nPayload);
   914    921       }else{
................................................................................
   973    980   /*
   974    981   ** Compute the total number of bytes that a Cell needs in the cell
   975    982   ** data area of the btree-page.  The return number includes the cell
   976    983   ** data header and the local payload, but not any overflow page or
   977    984   ** the space used by the cell pointer.
   978    985   */
   979    986   static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
   980         -  u8 *pIter = &pCell[pPage->childPtrSize];
          987  +  u8 *pX = pCell;
   981    988     u32 nSize;
          989  +  u8 cellBuf[25];
   982    990   
   983    991   #ifdef SQLITE_DEBUG
   984    992     /* The value returned by this function should always be the same as
   985    993     ** the (CellInfo.nSize) value found by doing a full parse of the
   986    994     ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
   987    995     ** this function verifies that this invariant is not violated. */
   988    996     CellInfo debuginfo;
   989    997     btreeParseCellPtr(pPage, pCell, &debuginfo);
   990    998   #endif
   991    999   
         1000  +  if( pX >= pPage->aDataEnd - sizeof(cellBuf) && pX < pPage->aDataEnd ){
         1001  +    int x = pPage->aDataEnd - pX;
         1002  +    memcpy(cellBuf, pCell, x);
         1003  +    memset(&cellBuf[x], 0, sizeof(cellBuf)-x);
         1004  +    pX = pCell = cellBuf;
         1005  +  }
         1006  +  pX += pPage->childPtrSize;
   992   1007     if( pPage->intKey ){
   993   1008       u8 *pEnd;
   994   1009       if( pPage->hasData ){
   995         -      pIter += getVarint32(pIter, nSize);
         1010  +      pX += getVarint32(pX, nSize);
   996   1011       }else{
   997   1012         nSize = 0;
   998   1013       }
   999   1014   
  1000   1015       /* pIter now points at the 64-bit integer key value, a variable length 
  1001   1016       ** integer. The following block moves pIter to point at the first byte
  1002   1017       ** past the end of the key value. */
  1003         -    pEnd = &pIter[9];
  1004         -    while( (*pIter++)&0x80 && pIter<pEnd );
         1018  +    pEnd = &pX[9];
         1019  +    while( (*pX++)&0x80 && pX<pEnd );
  1005   1020     }else{
  1006         -    pIter += getVarint32(pIter, nSize);
         1021  +    pX += getVarint32(pX, nSize);
  1007   1022     }
  1008   1023   
  1009   1024     testcase( nSize==pPage->maxLocal );
  1010   1025     testcase( nSize==pPage->maxLocal+1 );
  1011   1026     if( nSize>pPage->maxLocal ){
  1012   1027       int minLocal = pPage->minLocal;
  1013   1028       nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
................................................................................
  1014   1029       testcase( nSize==pPage->maxLocal );
  1015   1030       testcase( nSize==pPage->maxLocal+1 );
  1016   1031       if( nSize>pPage->maxLocal ){
  1017   1032         nSize = minLocal;
  1018   1033       }
  1019   1034       nSize += 4;
  1020   1035     }
  1021         -  nSize += (u32)(pIter - pCell);
         1036  +  nSize += (u32)(pX - pCell);
  1022   1037   
  1023   1038     /* The minimum size of any cell is 4 bytes. */
  1024   1039     if( nSize<4 ){
  1025   1040       nSize = 4;
  1026   1041     }
  1027   1042   
  1028   1043     assert( nSize==debuginfo.nSize );