Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a fairly obscure buffer overread in fts5. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
130580207ab5cee762b2893808acef7c |
User & Date: | dan 2016-02-12 17:56:27 |
Context
2016-02-12
| ||
18:48 | Fix a potential buffer overread provoked by invalid utf-8 in fts5. (check-in: a049fbbd user: dan tags: trunk) | |
17:56 | Fix a fairly obscure buffer overread in fts5. (check-in: 13058020 user: dan tags: trunk) | |
17:30 | Fix a documentation typo. No changes to code. (check-in: d9c98587 user: drh tags: trunk) | |
Changes
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <assert.h> #ifndef SQLITE_AMALGAMATION typedef unsigned char u8; typedef unsigned int u32; typedef unsigned short u16; typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; #define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) #define testcase(x) #define ALWAYS(x) 1 | > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <assert.h> #ifndef SQLITE_AMALGAMATION typedef unsigned char u8; typedef unsigned int u32; typedef unsigned short u16; typedef short i16; typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; #define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) #define testcase(x) #define ALWAYS(x) 1 |
︙ | ︙ |
Changes to ext/fts5/fts5_hash.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 | struct Fts5HashEntry { Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ Fts5HashEntry *pScanNext; /* Next entry in sorted order */ int nAlloc; /* Total size of allocation */ int iSzPoslist; /* Offset of space for 4-byte poslist size */ int nData; /* Total bytes of data (incl. structure) */ u8 bDel; /* Set delete-flag @ iSzPoslist */ u8 bContent; /* Set content-flag (detail=none mode) */ | > < | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | struct Fts5HashEntry { Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ Fts5HashEntry *pScanNext; /* Next entry in sorted order */ int nAlloc; /* Total size of allocation */ int iSzPoslist; /* Offset of space for 4-byte poslist size */ int nData; /* Total bytes of data (incl. structure) */ int nKey; /* Length of zKey[] in bytes */ u8 bDel; /* Set delete-flag @ iSzPoslist */ u8 bContent; /* Set content-flag (detail=none mode) */ i16 iCol; /* Column of last value written */ int iPos; /* Position of last value written */ i64 iRowid; /* Rowid of last value written */ char zKey[8]; /* Nul-terminated entry key */ }; /* ** Size of Fts5HashEntry without the zKey[] array. |
︙ | ︙ | |||
241 242 243 244 245 246 247 248 | bNew = (pHash->eDetail==FTS5_DETAIL_FULL); /* Attempt to locate an existing hash entry */ iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ if( p->zKey[0]==bByte && memcmp(&p->zKey[1], pToken, nToken)==0 | > < | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | bNew = (pHash->eDetail==FTS5_DETAIL_FULL); /* Attempt to locate an existing hash entry */ iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ if( p->zKey[0]==bByte && p->nKey==nToken && memcmp(&p->zKey[1], pToken, nToken)==0 ){ break; } } /* If an existing hash entry cannot be found, create a new one. */ if( p==0 ){ |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 | p = (Fts5HashEntry*)sqlite3_malloc(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, FTS5_HASHENTRYSIZE); p->nAlloc = nByte; p->zKey[0] = bByte; memcpy(&p->zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); p->zKey[nToken+1] = '\0'; p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; /* Add the first rowid field to the hash-entry */ | > | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | p = (Fts5HashEntry*)sqlite3_malloc(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, FTS5_HASHENTRYSIZE); p->nAlloc = nByte; p->zKey[0] = bByte; memcpy(&p->zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); p->nKey = nToken; p->zKey[nToken+1] = '\0'; p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; /* Add the first rowid field to the hash-entry */ |
︙ | ︙ |
Changes to ext/fts5/test/fts5hash.test.
︙ | ︙ | |||
62 63 64 65 66 67 68 | lappend doc [lindex $vocab $j] } return $doc } foreach_detail_mode $testprefix { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | lappend doc [lindex $vocab $j] } return $doc } foreach_detail_mode $testprefix { set vocab [build_vocab1] db func r random_doc do_execsql_test 1.0 { CREATE VIRTUAL TABLE eee USING fts5(e, ee, detail=%DETAIL%); BEGIN; WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) INSERT INTO eee SELECT r($vocab, 5), r($vocab, 7) FROM ii; INSERT INTO eee(eee) VALUES('integrity-check'); COMMIT; INSERT INTO eee(eee) VALUES('integrity-check'); } set hash [sqlite3_fts5_token_hash 1024 xyz] set vocab [build_vocab1 -prefix xyz -hash $hash] lappend vocab xyz do_execsql_test 1.1 { CREATE VIRTUAL TABLE vocab USING fts5vocab(eee, 'row'); BEGIN; } do_test 1.2 { for {set i 1} {$i <= 100} {incr i} { execsql { INSERT INTO eee VALUES( r($vocab, 5), r($vocab, 7) ) } } } {} do_test 1.3 { db eval { SELECT term, doc FROM vocab } { set nRow [db one {SELECT count(*) FROM eee WHERE eee MATCH $term}] if {$nRow != $doc} { error "term=$term fts5vocab=$doc cnt=$nRow" } } set {} {} } {} do_execsql_test 1.4 { COMMIT; INSERT INTO eee(eee) VALUES('integrity-check'); } #----------------------------------------------------------------------- # Add a small and very large token with the same hash value to an # empty table. At one point this would provoke an asan error. # do_test 2.0 { set big [string repeat 12345 40] set hash [sqlite3_fts5_token_hash 1024 $big] while {1} { set small [random_token] if {[sqlite3_fts5_token_hash 1024 $small]==$hash} break } execsql { CREATE VIRTUAL TABLE t2 USING fts5(x, detail=%DETAIL%) } breakpoint execsql { INSERT INTO t2 VALUES($small || ' ' || $big); } } {} } ;# foreach_detail_mode finish_test |