/ Check-in [84194c41]
Login

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

Overview
Comment:Fix a buffer overread in fts3 that can occur if the database is corrupt.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 84194c4195d7144ff7f9cedcdc74fdd908f3bfcd
User & Date: dan 2010-10-27 16:52:27
Context
2010-10-27
18:10
Merge experimental fts3/fts4 changes with trunk. check-in: 988164cf user: dan tags: trunk
16:52
Fix a buffer overread in fts3 that can occur if the database is corrupt. Closed-Leaf check-in: 84194c41 user: dan tags: experimental
10:55
In fts4, store the total number of bytes of for all records in the table in the %_stat table. check-in: 941647d1 user: dan tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_write.c.

   912    912       pReader->zTerm = zNew;
   913    913       pReader->nTermAlloc = nNew;
   914    914     }
   915    915     memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix);
   916    916     pReader->nTerm = nPrefix+nSuffix;
   917    917     pNext += nSuffix;
   918    918     pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist);
   919         -  assert( pNext<&pReader->aNode[pReader->nNode] );
   920    919     pReader->aDoclist = pNext;
   921    920     pReader->pOffsetList = 0;
          921  +
          922  +  /* Check that the doclist does not appear to extend past the end of the
          923  +  ** b-tree node. And that the final byte of the doclist is either an 0x00 
          924  +  ** or 0x01. If either of these statements is untrue, then the data structure 
          925  +  ** is corrupt.
          926  +  */
          927  +  if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
          928  +   || (pReader->aDoclist[pReader->nDoclist-1]&0xFE)!=0
          929  +  ){
          930  +    return SQLITE_CORRUPT;
          931  +  }
   922    932     return SQLITE_OK;
   923    933   }
   924    934   
   925    935   /*
   926    936   ** Set the SegReader to point to the first docid in the doclist associated
   927    937   ** with the current term.
   928    938   */

Added test/fts3corrupt.test.

            1  +# 2010 October 27
            2  +#
            3  +#    May you do good and not evil.
            4  +#    May you find forgiveness for yourself and forgive others.
            5  +#    May you share freely, never taking more than you give.
            6  +#
            7  +#***********************************************************************
            8  +# Test that the FTS3 extension does not crash when it encounters a
            9  +# corrupt data structure on disk.
           10  +#
           11  +
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +
           16  +# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
           17  +ifcapable !fts3 { finish_test ; return }
           18  +
           19  +set ::testprefix fts3corrupt
           20  +
           21  +do_execsql_test 1.0 {
           22  +  CREATE VIRTUAL TABLE t1 USING fts3;
           23  +  INSERT INTO t1 VALUES('hello');
           24  +} {}
           25  +
           26  +do_test fts3corrupt-1.1 {
           27  +  set blob [db one {SELECT root from t1_segdir}]
           28  +  set blob [binary format a7ca* $blob 24 [string range $blob 8 end]]
           29  +  execsql { UPDATE t1_segdir SET root = $blob }
           30  +} {}
           31  +
           32  +do_test fts3corrupt-1.2 {
           33  +  foreach w {a b c d e f g h i j k l m n o} {
           34  +    execsql { INSERT INTO t1 VALUES($w) }
           35  +  }
           36  +} {}
           37  +
           38  +do_catchsql_test 1.3 {
           39  +  INSERT INTO t1 VALUES('world');
           40  +} {1 {database disk image is malformed}}
           41  +
           42  +finish_test
           43  +

Changes to test/fts3defer2.test.

    32     32   do_execsql_test 1.1.1 {
    33     33     CREATE VIRTUAL TABLE t1 USING fts4;
    34     34   }
    35     35   do_execsql_test 1.1.2 "INSERT INTO t1 VALUES('[string repeat {a } 20000]')"
    36     36   do_execsql_test 1.1.3 "INSERT INTO t1 VALUES('[string repeat {z } 20000]')"
    37     37   do_execsql_test 1.1.4 {
    38     38     INSERT INTO t1 VALUES('a b c d e f a x y');
           39  +  INSERT INTO t1 VALUES('');
           40  +  INSERT INTO t1 VALUES('');
           41  +  INSERT INTO t1 VALUES('');
           42  +  INSERT INTO t1 VALUES('');
           43  +  INSERT INTO t1 VALUES('');
    39     44     INSERT INTO t1(t1) VALUES('optimize');
    40         -  UPDATE t1_segments 
    41         -    SET block = zeroblob(length(block)) 
    42         -    WHERE length(block)>10000;
    43     45   }
    44     46   do_execsql_test 1.1.4 {
    45     47     SELECT count(*) FROM t1_segments WHERE length(block)>10000;
    46         -  UPDATE t1_segments 
    47         -    SET block = zeroblob(length(block)) WHERE length(block)>10000;
           48  +  UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
    48     49   } {2}
    49     50   
    50     51   do_execsql_test 1.2.1 {
    51     52     SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
    52     53   } {{a b c d e f a x y}}
    53     54   
    54     55   do_execsql_test 1.2.2 {
    55     56     SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
    56     57     FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
    57     58   } [list                              \
    58     59      {a b c d [e] [f] [a] x y}         \
    59     60      {0 1 8 1 0 0 10 1 0 2 12 1}       \
    60         -   [list 3 1   1 1 1   1 3 3   1 3 3   3 13336 9]
           61  +   [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
    61     62   ]
    62     63   
    63     64   do_execsql_test 1.2.3 {
    64     65     SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
    65     66     FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
    66     67   } [list                                 \
    67     68      {[a] b c d [e] [f] [a] x y}          \
    68     69      {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
    69         -   [list 3 1   1 1 1   1 3 3   2 3 3   3 13336 9]
           70  +   [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
    70     71   ]
    71     72   
    72     73   do_execsql_test 1.3.1 { DROP TABLE t1 }
    73     74   
    74     75   #-----------------------------------------------------------------------------
    75     76   # Test cases fts3defer2-2.* focus specifically on the matchinfo function.
    76     77   # 
................................................................................
   100    101   
   101    102   do_execsql_test 2.3.1 {
   102    103     CREATE VIRTUAL TABLE t3 USING fts4;
   103    104     INSERT INTO t3 VALUES('a b c d e f');
   104    105     INSERT INTO t3 VALUES('x b c d e f');
   105    106     INSERT INTO t3 VALUES('d e f a b c');
   106    107     INSERT INTO t3 VALUES('b c d e f');
          108  +  INSERT INTO t3 VALUES('');
          109  +  INSERT INTO t3 VALUES('');
          110  +  INSERT INTO t3 VALUES('');
          111  +  INSERT INTO t3 VALUES('');
          112  +  INSERT INTO t3 VALUES('');
          113  +  INSERT INTO t3 VALUES('');
   107    114   }
   108    115   do_execsql_test 2.3.2 "
   109    116     INSERT INTO t3 VALUES('f e d c b [string repeat {a } 10000]')
   110    117   "
   111    118   foreach {tn sql} {
   112    119     1 {}
   113    120     2 { INSERT INTO t3(t3) VALUES('optimize') }
................................................................................
   114    121     3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
   115    122         WHERE length(block)>10000;
   116    123     }
   117    124   } {
   118    125     execsql $sql
   119    126     do_execsql_test 2.4.$tn {
   120    127       SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"';
   121         -  } {1 {1 1 1 4 4 5 2006 6} 3 {1 1 1 4 4 5 2006 6}}
          128  +  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
   122    129   }
   123    130   
   124    131   
   125    132   finish_test
   126    133