From: dan Date: Mon, 22 Dec 2025 15:22:02 +0000 (+0000) Subject: Add the SQLITE_PREPARE_FROM_DDL flag to sqlite3_prepare_v3(). Use this to prevent... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=add73c831bfe86288839f6053b7fcc7adfa72a87;p=thirdparty%2Fsqlite.git Add the SQLITE_PREPARE_FROM_DDL flag to sqlite3_prepare_v3(). Use this to prevent fts3/4 tables in non-trusted schemas from calling unsafe SQL functions. FossilOrigin-Name: 26f39ac806a5582fab1497e38a4ce68dad2b79df8c8aade43c4e21eed7576931 --- diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index f178abafed..368e9b189a 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1816,9 +1816,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; p->bLock++; - rc = sqlite3_prepare_v3( - p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); } @@ -3393,9 +3391,7 @@ static int fts3FilterMethod( } if( zSql ){ p->bLock++; - rc = sqlite3_prepare_v3( - p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); }else{ @@ -4018,6 +4014,7 @@ static int fts3IntegrityMethod( UNUSED_PARAMETER(isQuick); rc = sqlite3Fts3IntegrityCheck(p, &bOk); + assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK ); assert( rc!=SQLITE_CORRUPT_VTAB ); if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){ *pzErr = sqlite3_mprintf("unable to validate the inverted index for" diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index e98b90a753..556635defa 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -601,6 +601,15 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int); (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) +int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +); + + /* fts3.c */ void sqlite3Fts3ErrMsg(char**,const char*,...); int sqlite3Fts3PutVarint(char *, sqlite3_int64); diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index d9074d37ab..1b8bca70f2 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -273,6 +273,24 @@ struct SegmentNode { #define SQL_UPDATE_LEVEL_IDX 38 #define SQL_UPDATE_LEVEL 39 +/* +** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL +** is always set. +*/ +int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +){ + int f = SQLITE_PREPARE_FROM_DDL + |((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0) + |(bPersist ? SQLITE_PREPARE_PERSISTENT : 0); + + return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL); +} + /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, @@ -398,12 +416,12 @@ static int fts3SqlStmt( pStmt = p->aStmt[eStmt]; if( !pStmt ){ - int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; + int bAllowVtab = 0; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ - f &= ~SQLITE_PREPARE_NO_VTAB; + bAllowVtab = 1; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); @@ -411,7 +429,7 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -3578,7 +3596,7 @@ static int fts3DoRebuild(Fts3Table *p){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } @@ -5331,7 +5349,7 @@ int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } diff --git a/manifest b/manifest index 86f203311a..43c3df6b92 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sspurious\serror\slog\sreports\scaused\sby\s[d25c8a6222d4e3f2].\s\sSee\n[forum:/forumpost/d2326687662430c1|forum\spost\sd2326687662]. -D 2025-12-22T12:33:27.145 +C Add\sthe\sSQLITE_PREPARE_FROM_DDL\sflag\sto\ssqlite3_prepare_v3().\sUse\sthis\sto\sprevent\sfts3/4\stables\sin\snon-trusted\sschemas\sfrom\scalling\sunsafe\sSQL\sfunctions. +D 2025-12-22T15:22:02.051 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -79,9 +79,9 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c F ext/fts3/README.syntax b72477722e9b4fe43f8403227d790a1c94221bfad15c27863a4b36d1052e892b F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 4f02858ab845a97bedf06e6cc1fba49a81fe5e00a26df68d0ad0f00a5814fa70 +F ext/fts3/fts3.c 6cc7bbc307f27e7b6ee2e1d5ff63ffff4df3b42529dfe00eb34ddded417961b3 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h ed9b8bc5ed5be402069651e49d4855cb849af706cf3fe68548f58a2c21eefc7f +F ext/fts3/fts3Int.h fd6051f7aa4db93e05fdc703ef35faf79f78170419e809139109d7aef28f4170 F ext/fts3/fts3_aux.c 7eab82a9cf0830f6551ba3abfdbe73ed39e322a4d3940ee82fbf723674ecd9f3 F ext/fts3/fts3_expr.c 5c13796638d8192c388777166075cdc8bc4b6712024cd5b72c31acdbefce5984 F ext/fts3/fts3_hash.c d9dba473741445789330c7513d4f65737c92df23c3212784312931641814672a @@ -97,7 +97,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c c1de4ae28356ad98ccb8b2e3388a7fdcce7607b5523738c9afb6275dab765154 F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226 F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f -F ext/fts3/fts3_write.c 3a412c62e39c72283e34a51ec60c59eee6d684882fea7156b09a9733bd1f10e8 +F ext/fts3/fts3_write.c d218b687fb55bce8c9340c6dbb368a10d94647cbe39801d85492d576a4e7da75 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73 F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674 @@ -686,8 +686,8 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2 F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c -F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42 -F src/expr.c b4530f3e23d8ea38c7de4c7b55af52d43156c79128c042a580e670776f59a9bc +F src/delete.c e020dde34838369e2f0eff75f25c44a4e56a41262593f7c48d1223689d674e4d +F src/expr.c 252e62742f5bb01517377c93057b6040ab954034ec3dde4d6fc583565d859a9c F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531 F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b @@ -736,9 +736,9 @@ F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 9d55dc7bfea75b7aec14e819b9f65ca97472cea301ac5115d45ad435a63f7350 +F src/select.c 85852256d860f3ba5be4a9edc1238e68dbea082a0167f31b7345c821ae45775d F src/shell.c.in c4b775c664c339ac0351549a998b5f8816bf2496af5385e3937050c1fb5688fe -F src/sqlite.h.in b7d0e99d1384e73882f3157d86e0cd886d0c510d8db2b288b1d17631d6f26089 +F src/sqlite.h.in ecdd8ee84fe9e30d51433a4cc7951bb0423f588943f5d6f32c6c6ea779662f90 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 F src/sqliteInt.h af67bc95fa6b66cd3c7f3d18d2d040ad386e4cbb02965ee318cc721ee9d5fa45 @@ -804,7 +804,7 @@ F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 F src/util.c 36fb1150062957280777655976f3f9a75db236cb8207a0770ceae8d5ec17fcd3 F src/vacuum.c 1bacdd0a81d2b5dc1c508fbf0d938c89fa78dd8d5b46ec92686d44030d4f4789 F src/vdbe.c b44c366e83412d3b8c190feb1f029b7d02e1bd69252a57b32f195107f0d03964 -F src/vdbe.h be33bd7b17f2ec92939642416030491508c51071f6c14e27cd195983fec56b63 +F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9 F src/vdbeInt.h 2aaeb6df2938b181b4700a9328688a3986f2bba71e8b96f6a80671316618fa49 F src/vdbeapi.c 6a2181cfd27c86b4cc1d8abb27ae11f3b3f0357567814fa276ec37b043542938 F src/vdbeaux.c 908d8a191aed444b2e4c920159249127f3ff67b94c56a16fad1dfdf9c7488f20 @@ -1153,7 +1153,7 @@ F test/fts3aux1.test 1880eaa75c586cd10f53080479a2b819b3915ae7ce55c4e0ba8f1fe05ac F test/fts3aux2.test 2459e7fa3e22734aed237d1e2ae192f5541c4d8b218956ad2d90754977bf907f F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd491 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 -F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c +F test/fts3comp1.test f1b05ece56481f3973ece6a968cbabeeb0866c43f5375318313c003518ac53fb F test/fts3conf.test c9cd45433b6787d48a43e84949aa2eb8b3b3d242bac7276731c1476290d31f29 F test/fts3corrupt.test 6732477c5ace050c5758a40a8b5706c8c0cccd416b9c558e0e15224805a40e57 F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0 @@ -1203,7 +1203,7 @@ F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d F test/fts3varint.test 0b84a3fd4eba8a39f3687523804d18f3b322e6d4539a55bf342079c3614f2ada F test/fts4aa.test 0e6bfd6a81695a39b23e448dda25d864e63dda75bde6949c45ddc95426c6c3f5 F test/fts4check.test f0ea5e5581951d8ef7a341eea14486daf6c5f516a2f3273b0d5e8cb8a6cd3bd2 -F test/fts4content.test 73bbb123420d2c46ef2fb3b24761e9acdb78b0877179d3a5d7d57aada08066f6 +F test/fts4content.test 7f441866207f5b1e76e0f18bde5d9925d1ee8f60388054613dd14a29a79f0bc4 F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 F test/fts4growth.test 289833c34ad45a5e6e6133b53b6a71647231fb89d36ddcb8d9c87211b6721d7f F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269 @@ -2187,8 +2187,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f43d3339c1f06aabcb8e678ed4b91a490cfd0bc880c642ce9c1138c7e08cb360 -R 368416e9322dccc113e01f13b887d649 -U drh -Z 991a818d717546a1f42472b805bde58a +P 403dafc7790a2e8d1772537800760addc47d3e3555bda343c3991d56c1b36e70 +R 7581ed8e32b81aa2384ce190ebdf96b2 +U dan +Z 1915d46eae49cba5052e06a07b4e8b93 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index baaa5c4372..81b7170f2f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -403dafc7790a2e8d1772537800760addc47d3e3555bda343c3991d56c1b36e70 +26f39ac806a5582fab1497e38a4ce68dad2b79df8c8aade43c4e21eed7576931 diff --git a/src/delete.c b/src/delete.c index 8fac7c2f32..19fd5b2cda 100644 --- a/src/delete.c +++ b/src/delete.c @@ -86,7 +86,7 @@ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS ** virtual tables if PRAGMA trusted_schema=ON. */ - if( pParse->pToplevel!=0 + if( (pParse->pToplevel!=0 || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && pTab->u.vtab.p->eVtabRisk > ((pParse->db->flags & SQLITE_TrustedSchema)!=0) ){ diff --git a/src/expr.c b/src/expr.c index 3eea5439ee..198467deac 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1280,7 +1280,9 @@ void sqlite3ExprFunctionUsable( ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); - if( ExprHasProperty(pExpr, EP_FromDDL) ){ + if( ExprHasProperty(pExpr, EP_FromDDL) + || pParse->prepFlags & SQLITE_PREPARE_FROM_DDL + ){ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 || (pParse->db->flags & SQLITE_TrustedSchema)==0 ){ diff --git a/src/select.c b/src/select.c index 7a5f8c65d7..662b01a12f 100644 --- a/src/select.c +++ b/src/select.c @@ -6181,7 +6181,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) - && pFrom->fg.fromDDL + && (pFrom->fg.fromDDL || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && ALWAYS(pTab->u.vtab.p!=0) && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 8d50c20606..154fddcd56 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4433,12 +4433,20 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** fails, the sqlite3_prepare_v3() call returns the same error indications ** with or without this flag; it just omits the call to [sqlite3_log()] that ** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
SQLITE_PREPARE_FROM_DDL
+**
The SQLITE_PREPARE_FROM_DDL causes the SQL compiler to behave as if +** the SQL statement was part of a database schema. This only makes a +** difference if the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is set to off. +** This flag may be used by virtual table implementations that do not +** completely control the SQL commands that they evaluate. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 #define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement diff --git a/src/vdbe.h b/src/vdbe.h index 28df764bc6..a2905eae4d 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -186,7 +186,7 @@ typedef struct VdbeOpList VdbeOpList; ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ -#define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */ +#define SQLITE_PREPARE_MASK 0x3f /* Mask of public flags */ /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/test/fts3comp1.test b/test/fts3comp1.test index 9f13aaa64e..63f0e1f556 100644 --- a/test/fts3comp1.test +++ b/test/fts3comp1.test @@ -112,4 +112,51 @@ do_catchsql_test 2.2 { CREATE VIRTUAL TABLE t2 USING fts4(x, uncompress=unzip) } {1 {missing compress parameter in fts4 constructor}} +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 3.0 { + PRAGMA trusted_schema = OFF; +} + +set ::myfunc_invoked 0 +proc myfunc {data} { + incr ::myfunc_invoked + return $data +} +db func myfunc myfunc + +do_execsql_test 3.1 { + CREATE VIEW v1 AS SELECT myfunc('xyz'); +} + +do_catchsql_test 3.2 { + SELECT * FROM v1 +} {1 {unsafe use of myfunc()}} + +do_execsql_test 3.3 { + CREATE VIRTUAL TABLE f1 USING fts4(x, compress=myfunc, uncompress=myfunc); +} + +do_catchsql_test 3.4 { + INSERT INTO f1(rowid, x) VALUES(123, 'one two three'); +} {1 {SQL logic error}} + +do_test 3.5 { + set ::myfunc_invoked +} {0} + +do_execsql_test 3.6.1 { + CREATE TABLE t1(x); + CREATE TABLE t2(y); + + CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + INSERT INTO t2 VALUES( myfunc(new.x) ); + END; +} + +do_catchsql_test 3.6.2 { + INSERT INTO t1 VALUES('hello world'); +} {1 {unsafe use of myfunc()}} + + finish_test diff --git a/test/fts4content.test b/test/fts4content.test index 980586ea3a..8268e734a8 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -638,7 +638,6 @@ do_catchsql_test 11.1 { # Check that an fts4 table cannot be its own content table. # reset_db -breakpoint do_execsql_test 12.1.1 { CREATE VIRTUAL TABLE t1 USING fts4(a, content=t1 ); INSERT INTO t1(rowid, a) VALUES(1, 'abc'); @@ -669,6 +668,64 @@ do_catchsql_test 12.2.4 { SELECT count(*) FROM t1; } {1 {SQL logic error}} +#--------------------------------------------------------------------------- +# Check that an fts4 table cannot read from an unsafe vtab in a non-trusted +# schema. +reset_db +do_execsql_test 13.0 { + PRAGMA trusted_schema = off; + CREATE VIRTUAL TABLE t1 USING fts4(data, content=sqlite_dbpage); +} + +do_catchsql_test 13.1 { + INSERT INTO t1(t1) VALUES('rebuild'); +} {1 {SQL logic error}} + +proc vtab_command {method args} { + switch -- $method { + xConnect { + return "CREATE TABLE t1(a)" + } + + xBestIndex { + return "" + } + + xFilter { + return [list sql {SELECT 1, 123}] + } + + xUpdate { + return 123 + } + } + + return {} +} + +register_tcl_module db xyz + +do_execsql_test 13.2.0 { + CREATE VIRTUAL TABLE aa USING tcl(vtab_command); +} + +do_execsql_test 13.2.1 { + INSERT INTO aa VALUES('one two three'); +} + +do_test 13.2.2 { + set ::stmt [sqlite3_prepare_v3 db \ + "INSERT INTO aa VALUES('one two three');" -1 0x00 + ] + sqlite3_finalize $::stmt +} {SQLITE_OK} +do_test 13.2.2 { + list [catch { + set ::stmt [sqlite3_prepare_v3 db \ + "INSERT INTO aa VALUES('one two three');" -1 0x20 + ] + } msg] $msg +} {1 {(1) unsafe use of virtual table "aa"}} finish_test