From 8aaa252d8c4f72eec7a285f8ae356dc1b5850e11 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 27 Oct 2010 16:52:27 +0000 Subject: [PATCH] Fix a buffer overread in fts3 that can occur if the database is corrupt. FossilOrigin-Name: 84194c4195d7144ff7f9cedcdc74fdd908f3bfcd --- ext/fts3/fts3_write.c | 12 +++++++++++- manifest | 15 ++++++++------- manifest.uuid | 2 +- test/fts3corrupt.test | 43 +++++++++++++++++++++++++++++++++++++++++++ test/fts3defer2.test | 23 +++++++++++++++-------- 5 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 test/fts3corrupt.test diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 2bb5fb9c13..50dafe06ee 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -916,9 +916,19 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){ pReader->nTerm = nPrefix+nSuffix; pNext += nSuffix; pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist); - assert( pNext<&pReader->aNode[pReader->nNode] ); pReader->aDoclist = pNext; pReader->pOffsetList = 0; + + /* Check that the doclist does not appear to extend past the end of the + ** b-tree node. And that the final byte of the doclist is either an 0x00 + ** or 0x01. If either of these statements is untrue, then the data structure + ** is corrupt. + */ + if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] + || (pReader->aDoclist[pReader->nDoclist-1]&0xFE)!=0 + ){ + return SQLITE_CORRUPT; + } return SQLITE_OK; } diff --git a/manifest b/manifest index 055fab5938..8fbcf3fb0e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sfts4,\sstore\sthe\stotal\snumber\sof\sbytes\sof\sfor\sall\srecords\sin\sthe\stable\sin\sthe\s%_stat\stable. -D 2010-10-27T10:55:54 +C Fix\sa\sbuffer\soverread\sin\sfts3\sthat\scan\soccur\sif\sthe\sdatabase\sis\scorrupt. +D 2010-10-27T16:52:27 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2c8cefd962eca0147132c7cf9eaa4bb24c656f3f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -73,7 +73,7 @@ F ext/fts3/fts3_snippet.c 300c12b7f0a2a6ae0491bb2d00e2d5ff9c28f685 F ext/fts3/fts3_tokenizer.c b4f2d01c24573852755bc92864816785dae39318 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c 943216b144447a1fbadef373cbd2b7eb3fd17a65 +F ext/fts3/fts3_write.c a9189fa8719158b695f33e1490f56256308e2525 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -431,10 +431,11 @@ F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9 F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 +F test/fts3corrupt.test 8d2ef629be9eff997db32ec3f0f7b53b0c61d086 F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52 F test/fts3defer.test eab4f24c8402fb4e1e6aad44bcdfbe5bf42160b2 -F test/fts3defer2.test 1a9f213ca79509b60d81460febc7e4e5b64af95c +F test/fts3defer2.test d3c7db6584aab06a2781b8de58747c33b23cb19c F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851 F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a @@ -879,7 +880,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 97c6b2616ddcce2337778c6ee88a973cc4fe999d -R 8864817f6f3963775cfdd60519bb3822 +P 941647d121ac60e2eabc998cfe79b157fb918d7e +R 4228d3b4dbf28842cbc96083972fc4a8 U dan -Z 890501f0776b5167d933a1fceff6796c +Z 82331704b60d2b02d0a92d3a85b091f9 diff --git a/manifest.uuid b/manifest.uuid index 9e8bb976fe..ae661d2bc4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -941647d121ac60e2eabc998cfe79b157fb918d7e \ No newline at end of file +84194c4195d7144ff7f9cedcdc74fdd908f3bfcd \ No newline at end of file diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test new file mode 100644 index 0000000000..217ef940c4 --- /dev/null +++ b/test/fts3corrupt.test @@ -0,0 +1,43 @@ +# 2010 October 27 +# +# 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. +# +#*********************************************************************** +# Test that the FTS3 extension does not crash when it encounters a +# corrupt data structure on disk. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If SQLITE_ENABLE_FTS3 is not defined, omit this file. +ifcapable !fts3 { finish_test ; return } + +set ::testprefix fts3corrupt + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE t1 USING fts3; + INSERT INTO t1 VALUES('hello'); +} {} + +do_test fts3corrupt-1.1 { + set blob [db one {SELECT root from t1_segdir}] + set blob [binary format a7ca* $blob 24 [string range $blob 8 end]] + execsql { UPDATE t1_segdir SET root = $blob } +} {} + +do_test fts3corrupt-1.2 { + foreach w {a b c d e f g h i j k l m n o} { + execsql { INSERT INTO t1 VALUES($w) } + } +} {} + +do_catchsql_test 1.3 { + INSERT INTO t1 VALUES('world'); +} {1 {database disk image is malformed}} + +finish_test + diff --git a/test/fts3defer2.test b/test/fts3defer2.test index 7bf4210f13..ccae5bc3da 100644 --- a/test/fts3defer2.test +++ b/test/fts3defer2.test @@ -36,15 +36,16 @@ do_execsql_test 1.1.2 "INSERT INTO t1 VALUES('[string repeat {a } 20000]')" do_execsql_test 1.1.3 "INSERT INTO t1 VALUES('[string repeat {z } 20000]')" do_execsql_test 1.1.4 { INSERT INTO t1 VALUES('a b c d e f a x y'); + INSERT INTO t1 VALUES(''); + INSERT INTO t1 VALUES(''); + INSERT INTO t1 VALUES(''); + INSERT INTO t1 VALUES(''); + INSERT INTO t1 VALUES(''); INSERT INTO t1(t1) VALUES('optimize'); - UPDATE t1_segments - SET block = zeroblob(length(block)) - WHERE length(block)>10000; } do_execsql_test 1.1.4 { SELECT count(*) FROM t1_segments WHERE length(block)>10000; - UPDATE t1_segments - SET block = zeroblob(length(block)) WHERE length(block)>10000; + UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000; } {2} do_execsql_test 1.2.1 { @@ -57,7 +58,7 @@ do_execsql_test 1.2.2 { } [list \ {a b c d [e] [f] [a] x y} \ {0 1 8 1 0 0 10 1 0 2 12 1} \ - [list 3 1 1 1 1 1 3 3 1 3 3 3 13336 9] + [list 3 1 1 1 1 1 8 8 1 8 8 8 5001 9] ] do_execsql_test 1.2.3 { @@ -66,7 +67,7 @@ do_execsql_test 1.2.3 { } [list \ {[a] b c d [e] [f] [a] x y} \ {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1} \ - [list 3 1 1 1 1 1 3 3 2 3 3 3 13336 9] + [list 3 1 1 1 1 1 8 8 2 8 8 8 5001 9] ] do_execsql_test 1.3.1 { DROP TABLE t1 } @@ -104,6 +105,12 @@ do_execsql_test 2.3.1 { INSERT INTO t3 VALUES('x b c d e f'); INSERT INTO t3 VALUES('d e f a b c'); INSERT INTO t3 VALUES('b c d e f'); + INSERT INTO t3 VALUES(''); + INSERT INTO t3 VALUES(''); + INSERT INTO t3 VALUES(''); + INSERT INTO t3 VALUES(''); + INSERT INTO t3 VALUES(''); + INSERT INTO t3 VALUES(''); } do_execsql_test 2.3.2 " INSERT INTO t3 VALUES('f e d c b [string repeat {a } 10000]') @@ -118,7 +125,7 @@ foreach {tn sql} { execsql $sql do_execsql_test 2.4.$tn { SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"'; - } {1 {1 1 1 4 4 5 2006 6} 3 {1 1 1 4 4 5 2006 6}} + } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}} }