Blame SOURCES/sqlite-3.26.0-CVE-2019-13750.patch

77bd1e
Subject: [PATCH] In defensive mode, do not allow shadow tables to be renamed 
77bd1e
 using ALTER TABLE and do not allow shadow tables to be dropped.
77bd1e
77bd1e
diff --git a/src/alter.c b/src/alter.c
77bd1e
index 0fa24c0..707472a 100644
77bd1e
--- a/src/alter.c
77bd1e
+++ b/src/alter.c
77bd1e
@@ -28,9 +28,16 @@
77bd1e
 **
77bd1e
 ** Or, if zName is not a system table, zero is returned.
77bd1e
 */
77bd1e
-static int isSystemTable(Parse *pParse, const char *zName){
77bd1e
-  if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
77bd1e
-    sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
77bd1e
+static int isAlterableTable(Parse *pParse, Table *pTab){
77bd1e
+  if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) 
77bd1e
+#ifndef SQLITE_OMIT_VIRTUALTABLE
77bd1e
+   || ( (pTab->tabFlags & TF_Shadow) 
77bd1e
+     && (pParse->db->flags & SQLITE_Defensive)
77bd1e
+     && pParse->db->nVdbeExec==0
77bd1e
+   )
77bd1e
+#endif
77bd1e
+  ){
77bd1e
+    sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
77bd1e
     return 1;
77bd1e
   }
77bd1e
   return 0;
77bd1e
@@ -129,7 +136,7 @@ void sqlite3AlterRenameTable(
77bd1e
   /* Make sure it is not a system table being altered, or a reserved name
77bd1e
   ** that the table is being renamed to.
77bd1e
   */
77bd1e
-  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
77bd1e
+  if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
77bd1e
     goto exit_rename_table;
77bd1e
   }
77bd1e
   if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto
77bd1e
@@ -427,7 +434,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
77bd1e
     sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
77bd1e
     goto exit_begin_add_column;
77bd1e
   }
77bd1e
-  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
77bd1e
+  if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
77bd1e
     goto exit_begin_add_column;
77bd1e
   }
77bd1e
 
77bd1e
@@ -529,7 +536,7 @@ void sqlite3AlterRenameColumn(
77bd1e
   if( !pTab ) goto exit_rename_column;
77bd1e
 
77bd1e
   /* Cannot alter a system table */
77bd1e
-  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
77bd1e
+  if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
77bd1e
   if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
77bd1e
 
77bd1e
   /* Which schema holds the table to be altered */  
77bd1e
diff --git a/src/build.c b/src/build.c
77bd1e
index 1dc2614..3412670 100644
77bd1e
--- a/src/build.c
77bd1e
+++ b/src/build.c
77bd1e
@@ -2661,6 +2661,22 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
77bd1e
   sqliteViewResetAll(db, iDb);
77bd1e
 }
77bd1e
 
77bd1e
+/*
77bd1e
+** Return true if it is not allowed to drop the given table
77bd1e
+*/
77bd1e
+static int tableMayNotBeDropped(Parse *pParse, Table *pTab){
77bd1e
+  if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
77bd1e
+    if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
77bd1e
+    if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
77bd1e
+    return 1;
77bd1e
+  }
77bd1e
+  if( pTab->tabFlags & TF_Shadow ){
77bd1e
+    sqlite3 *db = pParse->db;
77bd1e
+    if( (db->flags & SQLITE_Defensive)!=0 && db->nVdbeExec==0 ) return 1;
77bd1e
+  }
77bd1e
+  return 0;
77bd1e
+}
77bd1e
+
77bd1e
 /*
77bd1e
 ** This routine is called to do the work of a DROP TABLE statement.
77bd1e
 ** pName is the name of the table to be dropped.
77bd1e
@@ -2730,8 +2746,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
77bd1e
     }
77bd1e
   }
77bd1e
 #endif
77bd1e
-  if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 
77bd1e
-    && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
77bd1e
+  if( tableMayNotBeDropped(pParse, pTab) ){
77bd1e
     sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
77bd1e
     goto exit_drop_table;
77bd1e
   }
77bd1e
diff --git a/test/altertab.test b/test/altertab.test
77bd1e
index a364207..891b081 100644
77bd1e
--- a/test/altertab.test
77bd1e
+++ b/test/altertab.test
77bd1e
@@ -505,5 +505,62 @@ do_execsql_test 15.5 {
77bd1e
   SELECT sql FROM sqlite_master WHERE name = 'y';
77bd1e
 } {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}}
77bd1e
 
77bd1e
+#-------------------------------------------------------------------------
77bd1e
+# Test that it is not possible to rename a shadow table in DEFENSIVE mode.
77bd1e
+#
77bd1e
+ifcapable fts3 {
77bd1e
+  proc vtab_command {method args} {
77bd1e
+    switch -- $method {
77bd1e
+      xConnect {
77bd1e
+        if {[info exists ::vtab_connect_sql]} {
77bd1e
+          execsql $::vtab_connect_sql
77bd1e
+        }
77bd1e
+        return "CREATE TABLE t1(a, b, c)"
77bd1e
+      }
77bd1e
+
77bd1e
+      xBestIndex {
77bd1e
+        set clist [lindex $args 0]
77bd1e
+        if {[llength $clist]!=1} { error "unexpected constraint list" }
77bd1e
+        catch { array unset C }
77bd1e
+        array set C [lindex $clist 0]
77bd1e
+        if {$C(usable)} {
77bd1e
+          return "omit 0 cost 0 rows 1 idxnum 555 idxstr eq!"
77bd1e
+        } else {
77bd1e
+          return "cost 1000000 rows 0 idxnum 0 idxstr scan..."
77bd1e
+        }
77bd1e
+      }
77bd1e
+    }
77bd1e
+
77bd1e
+    return {}
77bd1e
+  }
77bd1e
+
77bd1e
+  register_tcl_module db
77bd1e
+
77bd1e
+  sqlite3_db_config db DEFENSIVE 1
77bd1e
+
77bd1e
+  do_execsql_test 16.0 {
77bd1e
+    CREATE VIRTUAL TABLE y1 USING fts3;
77bd1e
+  }
77bd1e
+
77bd1e
+  do_catchsql_test 16.10 {
77bd1e
+    INSERT INTO y1_segments VALUES(1, X'1234567890');
77bd1e
+  } {1 {table y1_segments may not be modified}}
77bd1e
+
77bd1e
+  do_catchsql_test 16.20 {
77bd1e
+    ALTER TABLE y1_segments RENAME TO abc;
77bd1e
+  } {1 {table y1_segments may not be altered}}
77bd1e
+
77bd1e
+  do_catchsql_test 16.21 {
77bd1e
+    DROP TABLE y1_segments;
77bd1e
+  } {1 {table y1_segments may not be dropped}}
77bd1e
+
77bd1e
+  do_execsql_test 16.30 {
77bd1e
+    ALTER TABLE y1 RENAME TO z1;
77bd1e
+  }
77bd1e
+
77bd1e
+  do_execsql_test 16.40 {
77bd1e
+    SELECT * FROM z1_segments;
77bd1e
+  }
77bd1e
+}
77bd1e
 
77bd1e
 finish_test