1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-16 23:02:26 +03:00

Validate the type, name, and tbl_name fields of the sqlite_master table when

loading the schema, unless writable_schema is engaged.

FossilOrigin-Name: 724f4df9ccc2b683f7091a3f7a8c20ee210f44d7a610cd1b4c49da1c274add08
This commit is contained in:
drh
2019-08-12 00:08:07 +00:00
parent 14c865e859
commit c5a93d4c85
11 changed files with 295 additions and 52 deletions

View File

@@ -64,9 +64,11 @@ int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
**
** Each callback contains the following information:
**
** argv[0] = name of thing being created
** argv[1] = root page number for table or index. 0 for trigger or view.
** argv[2] = SQL text for the CREATE statement.
** argv[0] = type of object: "table", "index", "trigger", or "view".
** argv[1] = name of thing being created
** argv[2] = associated table if an index or trigger
** argv[3] = root page number for table or index. 0 for trigger or view.
** argv[4] = SQL text for the CREATE statement.
**
*/
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
@@ -74,21 +76,21 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
sqlite3 *db = pData->db;
int iDb = pData->iDb;
assert( argc==3 );
assert( argc==5 );
UNUSED_PARAMETER2(NotUsed, argc);
assert( sqlite3_mutex_held(db->mutex) );
DbClearProperty(db, iDb, DB_Empty);
pData->nInitRow++;
if( db->mallocFailed ){
corruptSchema(pData, argv[0], 0);
corruptSchema(pData, argv[1], 0);
return 1;
}
assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 ){
corruptSchema(pData, argv[0], 0);
}else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
if( argv[3]==0 ){
corruptSchema(pData, argv[1], 0);
}else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data
@@ -101,9 +103,10 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = sqlite3Atoi(argv[1]);
db->init.newTnum = sqlite3Atoi(argv[3]);
db->init.orphanTrigger = 0;
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
db->init.azInit = argv;
TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
@@ -116,13 +119,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
corruptSchema(pData, argv[1], sqlite3_errmsg(db));
}
}
}
sqlite3_finalize(pStmt);
}else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
corruptSchema(pData, argv[0], 0);
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
corruptSchema(pData, argv[1], 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -131,13 +134,13 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
** to do here is record the root page number for that index.
*/
Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
if( pIndex==0
|| sqlite3GetInt32(argv[1],&pIndex->tnum)==0
|| sqlite3GetInt32(argv[3],&pIndex->tnum)==0
|| pIndex->tnum<2
|| sqlite3IndexHasDuplicateRootPage(pIndex)
){
corruptSchema(pData, argv[0], pIndex?"invalid rootpage":"orphan index");
corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
}
}
return 0;
@@ -158,7 +161,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
int size;
#endif
Db *pDb;
char const *azArg[4];
char const *azArg[6];
int meta[5];
InitData initData;
const char *zMasterName;
@@ -177,18 +180,20 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
** table name will be inserted automatically by the parser so we can just
** use the abbreviation "x" here. The parser will also automatically tag
** the schema table as read-only. */
azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
azArg[1] = "1";
azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
azArg[0] = "table";
azArg[1] = zMasterName = SCHEMA_TABLE(iDb);
azArg[2] = azArg[1];
azArg[3] = "1";
azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
"rootpage int,sql text)";
azArg[3] = 0;
azArg[5] = 0;
initData.db = db;
initData.iDb = iDb;
initData.rc = SQLITE_OK;
initData.pzErrMsg = pzErrMsg;
initData.mInitFlags = mFlags;
initData.nInitRow = 0;
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
if( initData.rc ){
rc = initData.rc;
goto error_out;
@@ -314,7 +319,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
{
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
"SELECT*FROM\"%w\".%s ORDER BY rowid",
db->aDb[iDb].zDbSName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{