From: larrybr Date: Thu, 2 Sep 2021 01:21:14 +0000 (+0000) Subject: Meld -safe option into CLI X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb05c996a3271f396e7aea3c0a7a22f4f0526e5a;p=thirdparty%2Fsqlite.git Meld -safe option into CLI FossilOrigin-Name: c7c84998dbec5dfd71d62e12cfa741edba4b6439cc384ab46b21199f290feedd --- diff --git a/manifest b/manifest index e0bb517500..c527c93e5e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Sync\sto\strunk -D 2021-08-09T19:15:03.129 +C Meld\s-safe\soption\sinto\sCLI +D 2021-09-02T01:21:14.704 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -545,7 +545,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 42b94d37a54200707a95566eff4f7e8a380e32d080016b699f23bd79a73a5028 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 63077c0243ded1432d97c90c1a4c3419b3a574b36634c674599a68bfe4c3bdc2 -F src/shell.c.in 92fbe48f2b96c62a57ca17530624f61a4076d17ec082dd1da09e19d6792051e9 +F src/shell.c.in 16e84ce4dc4c538fe9b2759b1c1ea7e5923e5f297691a4b97bf1ef9528541b31 F src/sqlite.h.in 43fcf0fe2af04081f420a906fc020bde1243851ba44b0aa567a27f94bf8c3145 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 @@ -1920,7 +1920,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 d449941b81a796fa30382bd00e88dc744a6745dc3d5a0eb8377aa90e4966a391 d44f74f14a387960ce105913526b572f4a3d1935351c6aab10cee85946488a9e -R 7070e57e23b183c775afc6963903e7ac +P dd356ace4ffa57518c16fa7fd9b6bc7bef0bb0ddcbc9bdf60ab0a17c25f8e5c0 +R bde6c7d36d347a265cfb3284dd778d5f U larrybr -Z 9e19bb94e770b4ba1f8a18c5933850e6 +Z ac16bca9a518d5a67bb303386dbab385 diff --git a/manifest.uuid b/manifest.uuid index 13b73e4aee..440abb6081 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd356ace4ffa57518c16fa7fd9b6bc7bef0bb0ddcbc9bdf60ab0a17c25f8e5c0 \ No newline at end of file +c7c84998dbec5dfd71d62e12cfa741edba4b6439cc384ab46b21199f290feedd \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index f7af553c52..7ba35838f8 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1106,6 +1106,8 @@ struct ShellState { u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ + u8 bSafeMode; /* True when unsafe operations are prohibited */ + u8 bSafeModeFuture; /* Next bSafeMode - 0, 1 or suspending downto 1 */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ int outCount; /* Revert to stdout when reaching zero */ @@ -1157,8 +1159,9 @@ struct ShellState { int *aiIndent; /* Array of indents used in MODE_Explain */ int nIndent; /* Size of array aiIndent[] */ int iIndent; /* Index of current op in aiIndent[] */ + char *zNonce; /* Nonce for temporary safe-mode excapes */ EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ - ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ + ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; @@ -1294,6 +1297,27 @@ static void shellPutsFunc( sqlite3_result_value(pCtx, apVal[0]); } +/* +** If in safe mode, print an error message described by the arguments +** and exit immediately. +*/ +static void failIfSafeMode( + ShellState *p, + const char *zErrMsg, + ... +){ + if( p->bSafeMode ){ + va_list ap; + char *zMsg; + va_start(ap, zErrMsg); + zMsg = sqlite3_vmprintf(zErrMsg, ap); + va_end(ap); + raw_printf(stderr, "line %d: ", p->lineno); + utf8_printf(stderr, "%s\n", zMsg); + exit(1); + } +} + /* ** SQL function: edit(VALUE) ** edit(VALUE,EDITOR) @@ -1771,6 +1795,49 @@ static BOOL WINAPI ConsoleCtrlHandler( #endif #ifndef SQLITE_OMIT_AUTHORIZATION +/* +** This authorizer runs in safe mode. +*/ +static int safeModeAuth( + void *pClientData, + int op, + const char *zA1, + const char *zA2, + const char *zA3, + const char *zA4 +){ + ShellState *p = (ShellState*)pClientData; + static const char *azProhibitedFunctions[] = { + "edit", + "fts3_tokenizer", + "load_extension", + "readfile", + "writefile", + "zipfile", + "zipfile_cds", + }; + UNUSED_PARAMETER(zA2); + UNUSED_PARAMETER(zA3); + UNUSED_PARAMETER(zA4); + switch( op ){ + case SQLITE_ATTACH: { + failIfSafeMode(p, "cannot run ATTACH in safe mode"); + break; + } + case SQLITE_FUNCTION: { + int i; + for(i=0; iout, "\n"); + if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); return SQLITE_OK; } #endif @@ -4450,6 +4518,9 @@ static void open_db(ShellState *p, int openFlags){ } #endif } + if( p->bSafeModeFuture && p->db!=0 ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); + } } /* @@ -6823,6 +6894,7 @@ static int writeDb( char *azArg[], int nArg, ShellState *p ){ int j; int bAsync = 0; const char *zVfs = 0; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); for(j=1; jdb, shellAuth, p); + }else if( p->bSafeModeFuture ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); }else{ sqlite3_set_authorizer(p->db, 0, 0); } @@ -7026,6 +7101,7 @@ DISPATCHABLE_COMMAND( binary 3 2 2 ){ DISPATCHABLE_COMMAND( cd ? 2 2 ){ int rc=0; + failIfSafeMode(p, "cannot run .cd in safe mode"); #if defined(_WIN32) || defined(WIN32) wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); rc = !SetCurrentDirectoryW(z); @@ -7088,6 +7164,7 @@ DISPATCHABLE_COMMAND( check 3 0 0 ){ return rc; } DISPATCHABLE_COMMAND( clone ? 2 2 ){ + failIfSafeMode(p, "cannot run .clone in safe mode"); tryToClone(p, azArg[1]); return 0; } @@ -7471,6 +7548,7 @@ static int outputRedirs(char *azArg[], int nArg, ShellState *p, int bTxtMode = 0; int i; int bBOM = 0; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); for(i=1; imode==MODE_Ascii ){ xRead = ascii_read_one_field; @@ -8283,6 +8362,7 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){ DISPATCHABLE_COMMAND( load ? 2 3 ){ const char *zFile, *zProc; char *zErrMsg = 0; + failIfSafeMode(p, "cannot run .load in safe mode"); zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); @@ -8296,6 +8376,7 @@ DISPATCHABLE_COMMAND( load ? 2 3 ){ DISPATCHABLE_COMMAND( log ? 2 2 ){ const char *zFile = azArg[1]; + failIfSafeMode(p, "cannot run .log in safe mode"); output_file_close(p->pLog); p->pLog = output_file_open(zFile, 0); return 0; @@ -8416,7 +8497,7 @@ DISPATCHABLE_COMMAND( oom ? 1 4 ){ } /***************** - * The .open and .nullvalue commands + * The .open, .nonce and .nullvalue commands */ COLLECT_HELP_TEXT[ ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", @@ -8431,6 +8512,7 @@ COLLECT_HELP_TEXT[ " --nofollow Do not follow symbolic links", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", + ".nonce STRING Disable safe mode for one command if nonce matches", ".nullvalue STRING Use STRING in place of NULL values", ]; DISPATCHABLE_COMMAND( open 3 1 0 ){ @@ -8484,7 +8566,14 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){ } /* If a filename is specified, try to open it first */ if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ - if( newFlag ) shellDeleteFile(zNewFilename); + if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename); + if( p->bSafeMode + && p->openMode!=SHELL_OPEN_HEXDB + && zNewFilename + && strcmp(zNewFilename,":memory:")!=0 + ){ + failIfSafeMode(p, "cannot open disk-based database files in safe mode"); + } p->pAuxDb->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ @@ -8502,6 +8591,17 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){ return 0; } +DISPATCHABLE_COMMAND( nonce ? 2 2 ){ + if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){ + raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", + p->lineno, azArg[1]); + exit(1); + } + /* Suspend safe mode for 1 meta-command after this. */ + p->bSafeModeFuture = 2; + return 0; +} + DISPATCHABLE_COMMAND( nullvalue ? 2 2 ){ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); @@ -8720,6 +8820,7 @@ DISPATCHABLE_COMMAND( read 3 2 2 ){ int rc = 0; FILE *inSaved = p->in; int savedLineno = p->lineno; + failIfSafeMode(p, "cannot run .read in safe mode"); if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); @@ -9075,6 +9176,7 @@ DISPATCHABLE_COMMAND( restore ? 2 3 ){ sqlite3_backup *pBackup; int nTimeout = 0; + failIfSafeMode(p, "cannot run .restore in safe mode"); if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; @@ -9366,6 +9468,7 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){ */ if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ FILE *out = 0; + failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); @@ -9758,6 +9861,7 @@ DISPATCHABLE_COMMAND( selftest 4 0 0 ){ static int shellOut(char *azArg[], int nArg, ShellState *p){ char *zCmd; int i, x; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; ioutCount--; if( p->outCount==0 ) output_reset(p); } + switch( p->bSafeModeFuture ){ + default: + --p->bSafeModeFuture; + /* fall thru */ + case 0: + p->bSafeMode = 0; + break; + case 1: + p->bSafeMode = 1; + } return rc; } @@ -10896,6 +11010,7 @@ static int process_input(ShellState *p){ }else{ clearTempFile(p); } + p->bSafeMode = p->bSafeModeFuture!= 1; }else if( nSql && _all_whitespace(zSql) ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); nSql = 0; @@ -11062,10 +11177,12 @@ static const char zOptions[] = #endif " -newline SEP set output row separator. Default: '\\n'\n" " -nofollow refuse to open symbolic links to database files\n" + " -nonce STRING set the safe-mode escape nonce\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -quote set output mode to 'quote'\n" " -readonly open the database read-only\n" + " -safe enable safe-mode\n" " -separator SEP set output column separator. Default: '|'\n" #ifdef SQLITE_ENABLE_SORTER_REFERENCES " -sorterref SIZE sorter references threshold size\n" @@ -11411,6 +11528,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ sqlite3MemTraceActivate(stderr); }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; + }else if( strcmp(z,"-nonce")==0 ){ + free(data.zNonce); + data.zNonce = strdup(argv[++i]); + }else if( strcmp(z,"-safe")==0 ){ + /* no-op - catch this on the second pass */ } } verify_uninitialized(); @@ -11573,6 +11695,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ i+=2; }else if( strcmp(z,"-threadsafe")==0 ){ i+=2; + }else if( strcmp(z,"-nonce")==0 ){ + i += 2; }else if( strcmp(z,"-mmap")==0 ){ i++; }else if( strcmp(z,"-memtrace")==0 ){ @@ -11631,6 +11755,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ readStdin = 0; break; #endif + }else if( strcmp(z,"-safe")==0 ){ + data.bSafeMode = data.bSafeModeFuture = 1; }else{ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); raw_printf(stderr,"Use -help for a list of options.\n"); @@ -11733,6 +11859,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ free(argvToFree); #endif free(data.colWidth); + free(data.zNonce); /* Clear the global data structure so that valgrind will detect memory ** leaks */ memset(&data, 0, sizeof(data));