/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/vdbeaux.c.

3571
3572
3573
3574
3575
3576
3577

3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
....
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725








3726
3727
3728
3729
3730
3731
3732
3733
** byte (i.e. is less than 128).
*/
static int vdbeRecordCompareInt(
  int nKey1, const void *pKey1, /* Left key */
  const UnpackedRecord *pPKey2, /* Right key */
  int bSkip                     /* Ignored */
){

  const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1];
  int serial_type = ((const u8*)pKey1)[1];
  int res;
  i64 v = pPKey2->aMem[0].u.i;
  i64 lhs;
  UNUSED_PARAMETER(bSkip);

  assert( bSkip==0 );

  switch( serial_type ){
    case 1:
      lhs = (char)(aKey[0]);
      break;
    case 2:
      lhs = 256*(signed char)aKey[0] + aKey[1];
      break;
................................................................................

/*
** Return a pointer to an sqlite3VdbeRecordCompare() compatible function
** suitable for comparing serialized records to the unpacked record passed
** as the only argument.
*/
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
  /* As the varints that make up a record header are all 5 bytes in size
  ** or less, if the binary keys being compared have 25 or fewer fields 
  ** then it is guaranteed that the varint at the start of every record 
  ** (the record-header size in bytes) fits in a single byte. If this
  ** is not the case, then sqlite3VdbeRecordCompare() must be used.  */








  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=25 ){
    int flags = p->aMem[0].flags;
    if( p->pKeyInfo->aSortOrder[0] ){
      p->r1 = 1;
      p->r2 = -1;
    }else{
      p->r1 = -1;
      p->r2 = 1;







>
|







<







 







|
|
|
|
|
>
>
>
>
>
>
>
>
|







3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586

3587
3588
3589
3590
3591
3592
3593
....
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
** byte (i.e. is less than 128).
*/
static int vdbeRecordCompareInt(
  int nKey1, const void *pKey1, /* Left key */
  const UnpackedRecord *pPKey2, /* Right key */
  int bSkip                     /* Ignored */
){
  int szHdr = *(const u8*)pKey1;
  const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
  int serial_type = ((const u8*)pKey1)[1];
  int res;
  i64 v = pPKey2->aMem[0].u.i;
  i64 lhs;
  UNUSED_PARAMETER(bSkip);

  assert( bSkip==0 );

  switch( serial_type ){
    case 1:
      lhs = (char)(aKey[0]);
      break;
    case 2:
      lhs = 256*(signed char)aKey[0] + aKey[1];
      break;
................................................................................

/*
** Return a pointer to an sqlite3VdbeRecordCompare() compatible function
** suitable for comparing serialized records to the unpacked record passed
** as the only argument.
*/
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
  /* varintRecordCompareInt() and varintRecordCompareString() both assume
  ** that the size-of-header varint that occurs at the start of each record
  ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
  ** also assumes that it is safe to overread a buffer by at least the 
  ** maximum possible legal header size plus 8 bytes. Because there is
  ** guaranteed to be at least 74 (but not 136) bytes of padding following each
  ** buffer passed to varintRecordCompareInt() this makes it convenient to
  ** limit the size of the header to 64 bytes in cases where the first field
  ** is an integer.
  **
  ** The easiest way to enforce this limit is to consider only records with
  ** 13 fields or less. If the first field is an integer, the maximum legal
  ** header size is (12*5 + 1 + 1) bytes.  */
  if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
    int flags = p->aMem[0].flags;
    if( p->pKeyInfo->aSortOrder[0] ){
      p->r1 = 1;
      p->r2 = -1;
    }else{
      p->r1 = -1;
      p->r2 = 1;

Added test/corruptI.test.































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 2014-01-20
#
# 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.
#
#***********************************************************************
#

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

# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
do_not_use_codec
database_may_be_corrupt

# Initialize the database.
#
do_execsql_test 1.1 {
  PRAGMA page_size=1024;
  PRAGMA auto_vacuum=0;
  CREATE TABLE t1(a);
  CREATE INDEX i1 ON t1(a);
  INSERT INTO t1 VALUES('a');
} {}
db close

do_test 1.2 {
  set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
  set off [expr 2*1024 + $offset + 1]
  hexio_write test.db $off FF06

  breakpoint

  sqlite3 db test.db
  catchsql { SELECT * FROM t1 WHERE a = 10 }
} {1 {database disk image is malformed}}


finish_test