vim-patch:8.1.0881: can execute shell commands in rvim through interfaces

Problem:    Can execute shell commands in rvim through interfaces.
Solution:   Disable using interfaces in restricted mode. Allow for writing
            file with writefile(), histadd() and a few others.
8c62a08faf
This commit is contained in:
Jan Edmund Lazo 2020-02-24 20:33:43 -05:00
parent 3618fe9e8c
commit d846f47cc8
No known key found for this signature in database
GPG Key ID: 64915E6E9F735B15
5 changed files with 134 additions and 19 deletions

View File

@ -184,12 +184,17 @@ argument.
the 'modifiable' and 'write' options can be set to enable
changes and writing.
*-Z* *restricted-mode* *E145*
*-Z* *restricted-mode* *E145* *E981*
-Z Restricted mode. All commands that make use of an external
shell are disabled. This includes suspending with CTRL-Z,
":sh", filtering, the system() function, backtick expansion,
delete(), rename(), mkdir(), writefile(), libcall(),
jobstart(), etc.
":sh", filtering, the system() function, backtick expansion
and libcall().
Also disallowed are delete(), rename(), mkdir(), jobstart(),
etc.
Interfaces, such as Python, Ruby and Lua, are also disabled,
since they could be used to execute shell commands.
Note that the user may still find a loophole to execute a
shell command, it has only been made difficult.
-e *-e* *-E*
-E Start Nvim in Ex mode |gQ|.

View File

@ -4317,7 +4317,7 @@ static void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
HistoryType histype;
rettv->vval.v_number = false;
if (check_restricted() || check_secure()) {
if (check_secure()) {
return;
}
const char *str = tv_get_string_chk(&argvars[0]); // NULL on type error
@ -7779,8 +7779,7 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
if (check_restricted()
|| check_secure()
if (check_secure()
|| !tv_check_str_or_nr(&argvars[0])) {
return;
}
@ -8284,7 +8283,7 @@ static void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
if (check_secure()) {
return;
}
@ -11005,7 +11004,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = -1;
if (check_restricted() || check_secure()) {
if (check_secure()) {
return;
}

View File

@ -3008,18 +3008,18 @@ void ex_z(exarg_T *eap)
ex_no_reprint = true;
}
/*
* Check if the restricted flag is set.
* If so, give an error message and return TRUE.
* Otherwise, return FALSE.
*/
int check_restricted(void)
// Check if the restricted flag is set.
// If so, give an error message and return true.
// Otherwise, return false.
bool check_restricted(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (restricted) {
EMSG(_("E145: Shell commands not allowed in restricted mode"));
return TRUE;
EMSG(_("E145: Shell commands and some functionality not allowed"
" in restricted mode"));
return true;
}
return FALSE;
return false;
}
/*

View File

@ -1783,10 +1783,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (!ea.skip) {
if (sandbox != 0 && !(ea.argt & SBOXOK)) {
/* Command not allowed in sandbox. */
// Command not allowed in sandbox.
errormsg = (char_u *)_(e_sandbox);
goto doend;
}
if (restricted != 0 && (ea.argt & RESTRICT)) {
errormsg = (char_u *)_("E981: Command not allowed in restricted mode");
goto doend;
}
if (!MODIFIABLE(curbuf) && (ea.argt & MODIFY)
// allow :put in terminals
&& (!curbuf->terminal || ea.cmdidx != CMD_put)) {

View File

@ -0,0 +1,107 @@
" Test for "rvim" or "vim -Z"
source shared.vim
func Test_restricted()
let cmd = GetVimCommand('Xrestricted')
if cmd == ''
return
endif
call writefile([
\ "silent !ls",
\ "call writefile([v:errmsg], 'Xrestrout')",
\ "qa!",
\ ], 'Xrestricted')
call system(cmd . ' -Z')
call assert_match('E145:', join(readfile('Xrestrout')))
call delete('Xrestricted')
call delete('Xrestrout')
endfunc
func Run_restricted_test(ex_cmd, error)
let cmd = GetVimCommand('Xrestricted')
if cmd == ''
return
endif
call writefile([
\ a:ex_cmd,
\ "call writefile([v:errmsg], 'Xrestrout')",
\ "qa!",
\ ], 'Xrestricted')
call system(cmd . ' -Z')
call assert_match(a:error, join(readfile('Xrestrout')))
call delete('Xrestricted')
call delete('Xrestrout')
endfunc
func Test_restricted_lua()
if !has('lua')
throw 'Skipped: Lua is not supported'
endif
call Run_restricted_test('lua print("Hello, Vim!")', 'E981:')
call Run_restricted_test('luado return "hello"', 'E981:')
call Run_restricted_test('luafile somefile', 'E981:')
call Run_restricted_test('call luaeval("expression")', 'E145:')
endfunc
func Test_restricted_mzscheme()
if !has('mzscheme')
throw 'Skipped: MzScheme is not supported'
endif
call Run_restricted_test('mzscheme statement', 'E981:')
call Run_restricted_test('mzfile somefile', 'E981:')
call Run_restricted_test('call mzeval("expression")', 'E145:')
endfunc
func Test_restricted_perl()
if !has('perl')
throw 'Skipped: Perl is not supported'
endif
" TODO: how to make Safe mode fail?
" call Run_restricted_test('perl system("ls")', 'E981:')
" call Run_restricted_test('perldo system("hello")', 'E981:')
" call Run_restricted_test('perlfile somefile', 'E981:')
" call Run_restricted_test('call perleval("system(\"ls\")")', 'E145:')
endfunc
func Test_restricted_python()
if !has('python')
throw 'Skipped: Python is not supported'
endif
call Run_restricted_test('python print "hello"', 'E981:')
call Run_restricted_test('pydo return "hello"', 'E981:')
call Run_restricted_test('pyfile somefile', 'E981:')
call Run_restricted_test('call pyeval("expression")', 'E145:')
endfunc
func Test_restricted_python3()
if !has('python3')
throw 'Skipped: Python3 is not supported'
endif
call Run_restricted_test('py3 print "hello"', 'E981:')
call Run_restricted_test('py3do return "hello"', 'E981:')
call Run_restricted_test('py3file somefile', 'E981:')
call Run_restricted_test('call py3eval("expression")', 'E145:')
endfunc
func Test_restricted_ruby()
if !has('ruby')
throw 'Skipped: Ruby is not supported'
endif
call Run_restricted_test('ruby print "Hello"', 'E981:')
call Run_restricted_test('rubydo print "Hello"', 'E981:')
call Run_restricted_test('rubyfile somefile', 'E981:')
endfunc
func Test_restricted_tcl()
if !has('tcl')
throw 'Skipped: Tcl is not supported'
endif
call Run_restricted_test('tcl puts "Hello"', 'E981:')
call Run_restricted_test('tcldo puts "Hello"', 'E981:')
call Run_restricted_test('tclfile somefile', 'E981:')
endfunc