SQLite

Check-in [faa6bd7b61]
Login

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

Overview
Comment:Avoid some buffer overreads detected by valgrind while running corruptC.test. (CVS 5898)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: faa6bd7b615837c920b5b3b027115caa2f56ec15
User & Date: danielk1977 2008-11-12 18:21:36.000
Context
2008-11-13
14:28
Add an API to support custom page cache implementations. (CVS 5899) (check-in: 47866d6708 user: danielk1977 tags: trunk)
2008-11-12
18:21
Avoid some buffer overreads detected by valgrind while running corruptC.test. (CVS 5898) (check-in: faa6bd7b61 user: danielk1977 tags: trunk)
15:38
Version 3.6.5 (CVS 5897) (check-in: 369f74983b user: drh tags: trunk, release)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/btree.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.533 2008/11/12 08:49:52 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.534 2008/11/12 18:21:36 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

745
746
747
748
749
750
751
  cbrk = get2byte(&data[hdr+5]);
  memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk);
  cbrk = usableSize;
  for(i=0; i<nCell; i++){
    u8 *pAddr;     /* The i-th cell pointer */
    pAddr = &data[cellOffset + i*2];
    pc = get2byte(pAddr);
    if (pc >= pPage->pBt->usableSize) {
      return SQLITE_CORRUPT_BKPT;
    }
    size = cellSizePtr(pPage, &temp[pc]);
    cbrk -= size;
    if ((cbrk < cellOffset+2*nCell) || (cbrk+size>pPage->pBt->usableSize)) {
      return SQLITE_CORRUPT_BKPT;
    }

    memcpy(&data[cbrk], &temp[pc], size);
    put2byte(pAddr, cbrk);
  }
  assert( cbrk>=cellOffset+2*nCell );
  put2byte(&data[hdr+5], cbrk);
  data[hdr+1] = 0;
  data[hdr+2] = 0;







|




|


>







730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
  cbrk = get2byte(&data[hdr+5]);
  memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk);
  cbrk = usableSize;
  for(i=0; i<nCell; i++){
    u8 *pAddr;     /* The i-th cell pointer */
    pAddr = &data[cellOffset + i*2];
    pc = get2byte(pAddr);
    if( pc>=pPage->pBt->usableSize ){
      return SQLITE_CORRUPT_BKPT;
    }
    size = cellSizePtr(pPage, &temp[pc]);
    cbrk -= size;
    if( cbrk<cellOffset+2*nCell || pc+size>usableSize ){
      return SQLITE_CORRUPT_BKPT;
    }
    assert( cbrk+size<=usableSize && cbrk>=0 );
    memcpy(&data[cbrk], &temp[pc], size);
    put2byte(pAddr, cbrk);
  }
  assert( cbrk>=cellOffset+2*nCell );
  put2byte(&data[hdr+5], cbrk);
  data[hdr+1] = 0;
  data[hdr+2] = 0;
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199


3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
  int eOp              /* zero to read. non-zero to write. */
){
  unsigned char *aPayload;
  int rc = SQLITE_OK;
  u32 nKey;
  int iIdx = 0;
  MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
  BtShared *pBt;                              /* Btree this cursor belongs to */

  assert( pPage );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
  assert( offset>=0 );
  assert( cursorHoldsMutex(pCur) );

  getCellInfo(pCur);
  aPayload = pCur->info.pCell + pCur->info.nHeader;
  nKey = (pPage->intKey ? 0 : pCur->info.nKey);

  if( skipKey ){
    offset += nKey;
  }
  if( offset+amt > nKey+pCur->info.nData ){


    /* Trying to read or write past the end of the data is an error */
    return SQLITE_CORRUPT_BKPT;
  }

  /* Check if data must be read/written to/from the btree page itself. */
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }
    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
    offset = 0;
    pBuf += a;
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }

  pBt = pCur->pBt;
  if( rc==SQLITE_OK && amt>0 ){
    const int ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
    Pgno nextPage;

    nextPage = get4byte(&aPayload[pCur->info.nLocal]);

#ifndef SQLITE_OMIT_INCRBLOB







|














|
>
>


















<







3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220

3221
3222
3223
3224
3225
3226
3227
  int eOp              /* zero to read. non-zero to write. */
){
  unsigned char *aPayload;
  int rc = SQLITE_OK;
  u32 nKey;
  int iIdx = 0;
  MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
  BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */

  assert( pPage );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
  assert( offset>=0 );
  assert( cursorHoldsMutex(pCur) );

  getCellInfo(pCur);
  aPayload = pCur->info.pCell + pCur->info.nHeader;
  nKey = (pPage->intKey ? 0 : pCur->info.nKey);

  if( skipKey ){
    offset += nKey;
  }
  if( offset+amt > nKey+pCur->info.nData 
   || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
  ){
    /* Trying to read or write past the end of the data is an error */
    return SQLITE_CORRUPT_BKPT;
  }

  /* Check if data must be read/written to/from the btree page itself. */
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }
    rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
    offset = 0;
    pBuf += a;
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }


  if( rc==SQLITE_OK && amt>0 ){
    const int ovflSize = pBt->usableSize - 4;  /* Bytes content per ovfl page */
    Pgno nextPage;

    nextPage = get4byte(&aPayload[pCur->info.nLocal]);

#ifndef SQLITE_OMIT_INCRBLOB
Changes to test/corruptC.test.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It creates a base
# data base file, then tests that single byte corruptions in 
# increasingly larger quantities are handled gracefully.
#
# $Id: corruptC.test,v 1.7 2008/11/12 14:22:25 danielk1977 Exp $

catch {file delete -force test.db test.db-journal test.bu}

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Set a uniform random seed







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It creates a base
# data base file, then tests that single byte corruptions in 
# increasingly larger quantities are handled gracefully.
#
# $Id: corruptC.test,v 1.8 2008/11/12 18:21:36 danielk1977 Exp $

catch {file delete -force test.db test.db-journal test.bu}

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Set a uniform random seed
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  hexio_write test.db 4073 [format %02x 0xbf]

  sqlite3 db test.db
  catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
  catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
Corruption detected in cell 710 on page 4
Multiple uses for byte 116 of page 4
Fragmented space is 0 byte reported as 21 on page 4}}}

# test that a corrupt free cell size is handled (seed 169595)
do_test corruptC-2.6 {
  db close
  copy_file test.bu test.db

  # insert corrupt byte(s)







|
|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  hexio_write test.db 4073 [format %02x 0xbf]

  sqlite3 db test.db
  catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
  catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
Corruption detected in cell 710 on page 4
Multiple uses for byte 661 of page 4
Fragmented space is 249 byte reported as 21 on page 4}}}

# test that a corrupt free cell size is handled (seed 169595)
do_test corruptC-2.6 {
  db close
  copy_file test.bu test.db

  # insert corrupt byte(s)