/ Check-in [7c0b4381]
Login

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

Overview
Comment:Avoid a buffer overread in vdbeCompareRecordInt() that might occur if the database is corrupt.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 7c0b4381f0e6f33cb13299a915851d9431bf3850
User & Date: dan 2014-03-03 20:48:50
Context
2014-03-03
21:46
Fix a couple of harmless compiler warnings. Closed-Leaf check-in: fcf480cc user: drh tags: experimental
20:48
Avoid a buffer overread in vdbeCompareRecordInt() that might occur if the database is corrupt. check-in: 7c0b4381 user: dan tags: experimental
19:29
Fix a typo in a comment. No changes to code. check-in: 1f4991ab user: drh tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbeaux.c.

  3571   3571   ** byte (i.e. is less than 128).
  3572   3572   */
  3573   3573   static int vdbeRecordCompareInt(
  3574   3574     int nKey1, const void *pKey1, /* Left key */
  3575   3575     const UnpackedRecord *pPKey2, /* Right key */
  3576   3576     int bSkip                     /* Ignored */
  3577   3577   ){
  3578         -  const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1];
         3578  +  int szHdr = *(const u8*)pKey1;
         3579  +  const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
  3579   3580     int serial_type = ((const u8*)pKey1)[1];
  3580   3581     int res;
  3581   3582     i64 v = pPKey2->aMem[0].u.i;
  3582   3583     i64 lhs;
  3583   3584     UNUSED_PARAMETER(bSkip);
  3584   3585   
  3585   3586     assert( bSkip==0 );
  3586         -
  3587   3587     switch( serial_type ){
  3588   3588       case 1:
  3589   3589         lhs = (char)(aKey[0]);
  3590   3590         break;
  3591   3591       case 2:
  3592   3592         lhs = 256*(signed char)aKey[0] + aKey[1];
  3593   3593         break;
................................................................................
  3714   3714   
  3715   3715   /*
  3716   3716   ** Return a pointer to an sqlite3VdbeRecordCompare() compatible function
  3717   3717   ** suitable for comparing serialized records to the unpacked record passed
  3718   3718   ** as the only argument.
  3719   3719   */
  3720   3720   RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
  3721         -  /* As the varints that make up a record header are all 5 bytes in size
  3722         -  ** or less, if the binary keys being compared have 25 or fewer fields 
  3723         -  ** then it is guaranteed that the varint at the start of every record 
  3724         -  ** (the record-header size in bytes) fits in a single byte. If this
  3725         -  ** is not the case, then sqlite3VdbeRecordCompare() must be used.  */
  3726         -  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=25 ){
         3721  +  /* varintRecordCompareInt() and varintRecordCompareString() both assume
         3722  +  ** that the size-of-header varint that occurs at the start of each record
         3723  +  ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
         3724  +  ** also assumes that it is safe to overread a buffer by at least the 
         3725  +  ** maximum possible legal header size plus 8 bytes. Because there is
         3726  +  ** guaranteed to be at least 74 (but not 136) bytes of padding following each
         3727  +  ** buffer passed to varintRecordCompareInt() this makes it convenient to
         3728  +  ** limit the size of the header to 64 bytes in cases where the first field
         3729  +  ** is an integer.
         3730  +  **
         3731  +  ** The easiest way to enforce this limit is to consider only records with
         3732  +  ** 13 fields or less. If the first field is an integer, the maximum legal
         3733  +  ** header size is (12*5 + 1 + 1) bytes.  */
         3734  +  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
  3727   3735       int flags = p->aMem[0].flags;
  3728   3736       if( p->pKeyInfo->aSortOrder[0] ){
  3729   3737         p->r1 = 1;
  3730   3738         p->r2 = -1;
  3731   3739       }else{
  3732   3740         p->r1 = -1;
  3733   3741         p->r2 = 1;

Added test/corruptI.test.

            1  +# 2014-01-20
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +set testprefix corruptI
           16  +
           17  +# Do not use a codec for tests in this file, as the database file is
           18  +# manipulated directly using tcl scripts (using the [hexio_write] command).
           19  +#
           20  +do_not_use_codec
           21  +database_may_be_corrupt
           22  +
           23  +# Initialize the database.
           24  +#
           25  +do_execsql_test 1.1 {
           26  +  PRAGMA page_size=1024;
           27  +  PRAGMA auto_vacuum=0;
           28  +  CREATE TABLE t1(a);
           29  +  CREATE INDEX i1 ON t1(a);
           30  +  INSERT INTO t1 VALUES('a');
           31  +} {}
           32  +db close
           33  +
           34  +do_test 1.2 {
           35  +  set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
           36  +  set off [expr 2*1024 + $offset + 1]
           37  +  hexio_write test.db $off FF06
           38  +
           39  +  breakpoint
           40  +
           41  +  sqlite3 db test.db
           42  +  catchsql { SELECT * FROM t1 WHERE a = 10 }
           43  +} {1 {database disk image is malformed}}
           44  +
           45  +
           46  +finish_test
           47  +