]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Prevent direct and indirect recursive content= options in fts3/4 and fts5.
authordan <dan@noemail.net>
Thu, 21 Nov 2019 14:20:59 +0000 (14:20 +0000)
committerdan <dan@noemail.net>
Thu, 21 Nov 2019 14:20:59 +0000 (14:20 +0000)
FossilOrigin-Name: 2eb997327c2c369c10b7835be80112d77cb2a7cfa9fe4d564042984c21d94698

ext/fts3/fts3.c
ext/fts3/fts3Int.h
ext/fts5/fts5_main.c
ext/fts5/test/fts5content.test
manifest
manifest.uuid
test/fts4content.test

index 39a3dc35c1f53b105b2e80883c659540e5c84ec6..0b567ae45fe93f25959092f61a0d89521c25322f 100644 (file)
@@ -1611,6 +1611,10 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
   int iDocidLe = -1;              /* Index of docid<=x constraint, if present */
   int iIdx;
 
+  if( p->bLock ){
+    return SQLITE_ERROR;
+  }
+
   /* By default use a full table scan. This is an expensive option,
   ** so search through the constraints to see if a more efficient 
   ** strategy is possible.
@@ -1809,7 +1813,11 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
     }else{
       zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
       if( !zSql ) return SQLITE_NOMEM;
-      rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
+      p->bLock++;
+      rc = sqlite3_prepare_v3(
+          p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+      );
+      p->bLock--;
       sqlite3_free(zSql);
     }
     if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
@@ -1827,11 +1835,15 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
   if( pCsr->isRequireSeek ){
     rc = fts3CursorSeekStmt(pCsr);
     if( rc==SQLITE_OK ){
+      Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
+      pTab->bLock++;
       sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
       pCsr->isRequireSeek = 0;
       if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
+        pTab->bLock--;
         return SQLITE_OK;
       }else{
+        pTab->bLock--;
         rc = sqlite3_reset(pCsr->pStmt);
         if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
           /* If no row was found and no error has occurred, then the %_content
@@ -3218,6 +3230,8 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
   int rc;
   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
   if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
+    Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
+    pTab->bLock++;
     if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
       pCsr->isEof = 1;
       rc = sqlite3_reset(pCsr->pStmt);
@@ -3225,6 +3239,7 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
       pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
       rc = SQLITE_OK;
     }
+    pTab->bLock--;
   }else{
     rc = fts3EvalNext((Fts3Cursor *)pCursor);
   }
@@ -3285,6 +3300,10 @@ static int fts3FilterMethod(
   UNUSED_PARAMETER(idxStr);
   UNUSED_PARAMETER(nVal);
 
+  if( p->bLock ){
+    return SQLITE_ERROR;
+  }
+
   eSearch = (idxNum & 0x0000FFFF);
   assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
   assert( p->pSegments==0 );
@@ -3356,7 +3375,11 @@ static int fts3FilterMethod(
       );
     }
     if( zSql ){
-      rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
+      p->bLock++;
+      rc = sqlite3_prepare_v3(
+          p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+      );
+      p->bLock--;
       sqlite3_free(zSql);
     }else{
       rc = SQLITE_NOMEM;
index 3833e067e484aa2eb6fb621afec1cfd7fe37925d..26b23b66f2a9ba6761ebd3a7f56d110a28dd5144 100644 (file)
@@ -239,6 +239,7 @@ struct Fts3Table {
   char *zLanguageid;              /* languageid=xxx option, or NULL */
   int nAutoincrmerge;             /* Value configured by 'automerge' */
   u32 nLeafAdd;                   /* Number of leaf blocks added this trans */
+  int bLock;                      /* Used to prevent recursive content= tbls */
 
   /* Precompiled statements used by the implementation. Each of these 
   ** statements is run and reset within a single virtual table API call. 
index a0450a6e4fffd2a7bbcf06570ba83a679cdb3319..d0cfcbe413090de6aa62097a094c72f6640aab3c 100644 (file)
@@ -895,15 +895,24 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
         break;
       }
   
-      default:
+      default: {
+        Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
+        pConfig->bLock++;
         rc = sqlite3_step(pCsr->pStmt);
+        pConfig->bLock--;
         if( rc!=SQLITE_ROW ){
           CsrFlagSet(pCsr, FTS5CSR_EOF);
           rc = sqlite3_reset(pCsr->pStmt);
+          if( rc!=SQLITE_OK ){
+            pCursor->pVtab->zErrMsg = sqlite3_mprintf(
+                "%s", sqlite3_errmsg(pConfig->db)
+            );
+          }
         }else{
           rc = SQLITE_OK;
         }
         break;
+      }
     }
   }
   
@@ -1188,6 +1197,13 @@ static int fts5FilterMethod(
   int iIdxStr = 0;
   Fts5Expr *pExpr = 0;
 
+  if( pConfig->bLock ){
+    pTab->p.base.zErrMsg = sqlite3_mprintf(
+        "recursively defined fts5 content table"
+    );
+    return SQLITE_ERROR;
+  }
+
   if( pCsr->ePlan ){
     fts5FreeCursorComponents(pCsr);
     memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -1408,10 +1424,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
   }
 
   if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
+    Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
     assert( pCsr->pExpr );
     sqlite3_reset(pCsr->pStmt);
     sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
+    pTab->pConfig->bLock++;
     rc = sqlite3_step(pCsr->pStmt);
+    pTab->pConfig->bLock--;
     if( rc==SQLITE_ROW ){
       rc = SQLITE_OK;
       CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
@@ -1419,6 +1438,10 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
       rc = sqlite3_reset(pCsr->pStmt);
       if( rc==SQLITE_OK ){
         rc = FTS5_CORRUPT;
+      }else{
+        pTab->base.zErrMsg = sqlite3_mprintf(
+            "%s", sqlite3_errmsg(pTab->pConfig->db)
+        );
       }
     }
   }
index bd510a552d33cdd44826e28e262bd0422f7d4df4..74a74e2ad02f35146761c5be53f3343c3531c169 100644 (file)
@@ -257,16 +257,41 @@ do_execsql_test 6.2 {
 # Check that an fts5 table cannot be its own content table.
 #
 reset_db
-do_execsql_test 7.1 {
+do_execsql_test 7.1.1 {
   CREATE VIRTUAL TABLE t1 USING fts5(a, c=t1 );
   INSERT INTO t1( a ) VALUES('abc');
 }
-do_catchsql_test 7.2 { 
+do_catchsql_test 7.1.2 { 
   SELECT * FROM t1; 
 } {1 {recursively defined fts5 content table}}
-do_catchsql_test 7.3 { 
+do_catchsql_test 7.1.3 { 
   SELECT * FROM t1('abc'); 
 } {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.1.4 { 
+  SELECT count(*) FROM t1;
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.1.5 { 
+  SELECT * FROM t1('abc') ORDER BY rank;
+} {1 {recursively defined fts5 content table}}
+
+reset_db
+do_execsql_test 7.2.1 {
+  CREATE VIRTUAL TABLE t1 USING fts5(a, c=t2 );
+  CREATE VIRTUAL TABLE t2 USING fts5(a, c=t1 );
+  INSERT INTO t1( a ) VALUES('abc');
+}
+do_catchsql_test 7.2.2 { 
+  SELECT * FROM t1; 
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.3 { 
+  SELECT * FROM t1('abc'); 
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.4 { 
+  SELECT count(*) FROM t1;
+} {1 {recursively defined fts5 content table}}
+do_catchsql_test 7.2.5 { 
+  SELECT * FROM t1('abc') ORDER BY rank;
+} {1 {recursively defined fts5 content table}}
 
 finish_test
 
index 0e0e65a3e256cdf7b2aa80355a2afaf0fd724f6b..d2b8a71850858871f1fdfc6193a43be04544e649 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\suse-after-free\sproblem\sin\sthe\stest\ssuite.\sNo\schanges\sto\sproduction\scode.
-D 2019-11-20T16:10:40.296
+C Prevent\sdirect\sand\sindirect\srecursive\scontent=\soptions\sin\sfts3/4\sand\sfts5.
+D 2019-11-21T14:20:59.705
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -81,9 +81,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
 F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c 9c2ac0443f4207e523e0b26046553b28c3e1234d867a19ac477504f37f3875be
+F ext/fts3/fts3.c f2e6743c765488b727b6186dcefd6dcfa2da72a28cb67152849285a7b32ade78
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
-F ext/fts3/fts3Int.h 7201d419716896951044f980350f0ccb376fdc15932ff1a81f0d43f5e7051a45
+F ext/fts3/fts3Int.h ba4e5445a0daf4a251345d4704259268fd98a3e0282fedfcaedb9fc6da9f250c
 F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
 F ext/fts3/fts3_expr.c b132af223e90e35b9f9efa9fe63d6ae737d34153a3b6066736086df8abc78a1f
 F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
@@ -117,7 +117,7 @@ F ext/fts5/fts5_config.c aab6117f8f85933e051c66f227414fdcaf7f2313688e16276b895f9
 F ext/fts5/fts5_expr.c 5661fe64f4f5a499710df9561075de84b743f01e808af46df4130a9ec343a0fd
 F ext/fts5/fts5_hash.c 1cc0095646f5f3b46721aa112fb4f9bf29ae175cb5338f89dcec66ed97acfe75
 F ext/fts5/fts5_index.c 99b77ae1f503978ca76985bcfff7345c822aed8bbaa8edb3747f804f614685b5
-F ext/fts5/fts5_main.c 1b2d41fd7cc2e8277f60e4156826f41fe5d6b1ccc2e54d70450883ab2ca697d2
+F ext/fts5/fts5_main.c dad126d1dede87df748c65b389ec67edcc803d939980b55a0280386b54fd7e7b
 F ext/fts5/fts5_storage.c 167e3d8f8052a71032d498e32a2f2ed5ffe489e5d4d47e298adfa02ed55c7882
 F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
 F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
@@ -154,7 +154,7 @@ F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f3
 F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
 F ext/fts5/test/fts5conflict.test 655925678e630d3cdf145d18725a558971806416f453ac8410ca8c04d934238d
 F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c073e19b3ae9126b2f4
-F ext/fts5/test/fts5content.test 9517cc527a8e8a33949652d5c7b5e251f8c3d5ae3f23f01d4320e30f29a0336b
+F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
 F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
 F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
 F ext/fts5/test/fts5corrupt3.test 4100ac398eefbf033ebdf5a5a9399b37b4f8e1285fa35ab9d0119d4c7f21dc0c
@@ -975,7 +975,7 @@ F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
 F test/fts3varint.test 0b84a3fd4eba8a39f3687523804d18f3b322e6d4539a55bf342079c3614f2ada
 F test/fts4aa.test 4338ea7a67f7e19269bf6e6fb4a291352aa32296e7daed87f9823d57016a1ef7
 F test/fts4check.test 6259f856604445d7b684c9b306b2efb6346834c3f50e8fc4a59a2ca6d5319ad0
-F test/fts4content.test 1518195a9f92b711d94419f76409a31cc78755854fb0abb1da2b74b9e0cf843e
+F test/fts4content.test 73bbb123420d2c46ef2fb3b24761e9acdb78b0877179d3a5d7d57aada08066f6
 F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
 F test/fts4growth.test 289833c34ad45a5e6e6133b53b6a71647231fb89d36ddcb8d9c87211b6721d7f
 F test/fts4growth2.test 13ad4e76451af6e6906c95cdc725d01b00044269
@@ -1850,7 +1850,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P a0f6d526baecd061a5e2bec5eb698fb5dfb10122ac79c853d7b3f4a48bc9f49b
-R f8d336959087d4a7ae5775d40c8495c8
+P 0d1055a5da8274a59f35170b1f9469597ce4c5a4c5e851a1b81d3be2ccd32871
+R 200f7549382b29efd6fcb95f943bb744
 U dan
-Z a7988e13d0d9940f3811a9b074dcc031
+Z 37f61c8ae9fc951a55a1a29cfd01745c
index ef54236abbd6853c86e1ef13202eddb350aa34e7..abafc575bf808b83c90efb5ce1f33ab0c2caad9c 100644 (file)
@@ -1 +1 @@
-0d1055a5da8274a59f35170b1f9469597ce4c5a4c5e851a1b81d3be2ccd32871
\ No newline at end of file
+2eb997327c2c369c10b7835be80112d77cb2a7cfa9fe4d564042984c21d94698
\ No newline at end of file
index 2da51d151618b76f9707ab9f1ae9ec931aa6c545..980586ea3aa864464c49b2d3db8771fac4a7cef5 100644 (file)
@@ -634,5 +634,41 @@ do_catchsql_test 11.1 {
   CREATE VIRTUAL TABLE x1 USING fts4(content=x1);
 } {1 {vtable constructor called recursively: x1}}
 
+#---------------------------------------------------------------------------
+# 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');
+}
+do_catchsql_test 12.1.2 { 
+  SELECT * FROM t1; 
+} {1 {SQL logic error}}
+do_catchsql_test 12.1.3 { 
+  SELECT * FROM t1('abc'); 
+} {1 {SQL logic error}}
+do_catchsql_test 12.1.4 { 
+  SELECT count(*) FROM t1;
+} {1 {SQL logic error}}
+
+reset_db
+do_execsql_test 12.2.1 {
+  CREATE VIRTUAL TABLE t1 USING fts4(a, content=t2 );
+  CREATE VIRTUAL TABLE t2 USING fts4(a, content=t1 );
+  INSERT INTO t1(rowid, a) VALUES(1, 'abc');
+}
+do_catchsql_test 12.2.2 { 
+  SELECT * FROM t1; 
+} {1 {SQL logic error}}
+do_catchsql_test 12.2.3 { 
+  SELECT * FROM t1('abc'); 
+} {1 {SQL logic error}}
+do_catchsql_test 12.2.4 { 
+  SELECT count(*) FROM t1;
+} {1 {SQL logic error}}
+
+
 
 finish_test