forked from aniani/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.
This commit is contained in:
@@ -248,12 +248,18 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
|
|||||||
changes and writing.
|
changes and writing.
|
||||||
{not in Vi}
|
{not in Vi}
|
||||||
|
|
||||||
*-Z* *restricted-mode* *E145*
|
*-Z* *restricted-mode* *E145* *E981*
|
||||||
-Z Restricted mode. All commands that make use of an external
|
-Z Restricted mode. All commands that make use of an external
|
||||||
shell are disabled. This includes suspending with CTRL-Z,
|
shell are disabled. This includes suspending with CTRL-Z,
|
||||||
":sh", filtering, the system() function, backtick expansion,
|
":sh", filtering, the system() function, backtick expansion
|
||||||
delete(), rename(), mkdir(), writefile(), libcall(),
|
and libcall().
|
||||||
job_start(), etc.
|
Also disallowed are delete(), rename(), mkdir(), job_start(),
|
||||||
|
etc.
|
||||||
|
Interfaces, such as Python, Ruby and Lua, are also disabled,
|
||||||
|
since they could be used to execute shell commands. Perl uses
|
||||||
|
the Safe module.
|
||||||
|
Note that the user may still find a loophole to execute a
|
||||||
|
shell command, it has only been made difficult.
|
||||||
{not in Vi}
|
{not in Vi}
|
||||||
|
|
||||||
*-g*
|
*-g*
|
||||||
|
@@ -6817,7 +6817,7 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
rettv->vval.v_number = FALSE;
|
rettv->vval.v_number = FALSE;
|
||||||
if (check_restricted() || check_secure())
|
if (check_secure())
|
||||||
return;
|
return;
|
||||||
#ifdef FEAT_CMDHIST
|
#ifdef FEAT_CMDHIST
|
||||||
str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
|
str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
|
||||||
@@ -7898,6 +7898,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *str;
|
char_u *str;
|
||||||
char_u buf[NUMBUFLEN];
|
char_u buf[NUMBUFLEN];
|
||||||
|
|
||||||
|
if (check_restricted() || check_secure())
|
||||||
|
return;
|
||||||
|
|
||||||
str = tv_get_string_buf(&argvars[0], buf);
|
str = tv_get_string_buf(&argvars[0], buf);
|
||||||
do_luaeval(str, argvars + 1, rettv);
|
do_luaeval(str, argvars + 1, rettv);
|
||||||
}
|
}
|
||||||
@@ -8644,6 +8647,8 @@ f_mzeval(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *str;
|
char_u *str;
|
||||||
char_u buf[NUMBUFLEN];
|
char_u buf[NUMBUFLEN];
|
||||||
|
|
||||||
|
if (check_restricted() || check_secure())
|
||||||
|
return;
|
||||||
str = tv_get_string_buf(&argvars[0], buf);
|
str = tv_get_string_buf(&argvars[0], buf);
|
||||||
do_mzeval(str, rettv);
|
do_mzeval(str, rettv);
|
||||||
}
|
}
|
||||||
@@ -8932,6 +8937,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *str;
|
char_u *str;
|
||||||
char_u buf[NUMBUFLEN];
|
char_u buf[NUMBUFLEN];
|
||||||
|
|
||||||
|
if (check_restricted() || check_secure())
|
||||||
|
return;
|
||||||
|
|
||||||
if (p_pyx == 0)
|
if (p_pyx == 0)
|
||||||
p_pyx = 3;
|
p_pyx = 3;
|
||||||
|
|
||||||
@@ -8950,6 +8958,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *str;
|
char_u *str;
|
||||||
char_u buf[NUMBUFLEN];
|
char_u buf[NUMBUFLEN];
|
||||||
|
|
||||||
|
if (check_restricted() || check_secure())
|
||||||
|
return;
|
||||||
|
|
||||||
if (p_pyx == 0)
|
if (p_pyx == 0)
|
||||||
p_pyx = 2;
|
p_pyx = 2;
|
||||||
|
|
||||||
@@ -8965,6 +8976,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
|
|||||||
static void
|
static void
|
||||||
f_pyxeval(typval_T *argvars, typval_T *rettv)
|
f_pyxeval(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
|
if (check_restricted() || check_secure())
|
||||||
|
return;
|
||||||
|
|
||||||
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
|
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
|
||||||
init_pyxversion();
|
init_pyxversion();
|
||||||
if (p_pyx == 2)
|
if (p_pyx == 2)
|
||||||
@@ -10819,7 +10833,7 @@ f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
typval_T *varp;
|
typval_T *varp;
|
||||||
char_u nbuf[NUMBUFLEN];
|
char_u nbuf[NUMBUFLEN];
|
||||||
|
|
||||||
if (check_restricted() || check_secure())
|
if (check_secure())
|
||||||
return;
|
return;
|
||||||
(void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
|
(void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
|
||||||
varname = tv_get_string_chk(&argvars[1]);
|
varname = tv_get_string_chk(&argvars[1]);
|
||||||
@@ -11341,7 +11355,7 @@ f_settabvar(typval_T *argvars, typval_T *rettv)
|
|||||||
|
|
||||||
rettv->vval.v_number = 0;
|
rettv->vval.v_number = 0;
|
||||||
|
|
||||||
if (check_restricted() || check_secure())
|
if (check_secure())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
|
tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
|
||||||
@@ -14714,7 +14728,7 @@ f_writefile(typval_T *argvars, typval_T *rettv)
|
|||||||
blob_T *blob = NULL;
|
blob_T *blob = NULL;
|
||||||
|
|
||||||
rettv->vval.v_number = -1;
|
rettv->vval.v_number = -1;
|
||||||
if (check_restricted() || check_secure())
|
if (check_secure())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (argvars[0].v_type == VAR_LIST)
|
if (argvars[0].v_type == VAR_LIST)
|
||||||
|
@@ -4775,7 +4775,7 @@ check_restricted(void)
|
|||||||
{
|
{
|
||||||
if (restricted)
|
if (restricted)
|
||||||
{
|
{
|
||||||
emsg(_("E145: Shell commands not allowed in rvim"));
|
emsg(_("E145: Shell commands and some functionality not allowed in rvim"));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@@ -2007,11 +2007,16 @@ do_one_cmd(
|
|||||||
#ifdef HAVE_SANDBOX
|
#ifdef HAVE_SANDBOX
|
||||||
if (sandbox != 0 && !(ea.argt & SBOXOK))
|
if (sandbox != 0 && !(ea.argt & SBOXOK))
|
||||||
{
|
{
|
||||||
/* Command not allowed in sandbox. */
|
// Command not allowed in sandbox.
|
||||||
errormsg = _(e_sandbox);
|
errormsg = _(e_sandbox);
|
||||||
goto doend;
|
goto doend;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (restricted != 0 && (ea.argt & RESTRICT))
|
||||||
|
{
|
||||||
|
errormsg = _("E981: Command not allowed in rvim");
|
||||||
|
goto doend;
|
||||||
|
}
|
||||||
if (!curbuf->b_p_ma && (ea.argt & MODIFY))
|
if (!curbuf->b_p_ma && (ea.argt & MODIFY))
|
||||||
{
|
{
|
||||||
/* Command not allowed in non-'modifiable' buffer */
|
/* Command not allowed in non-'modifiable' buffer */
|
||||||
|
@@ -971,6 +971,7 @@ VIM_init(void)
|
|||||||
#ifdef DYNAMIC_PERL
|
#ifdef DYNAMIC_PERL
|
||||||
static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
|
static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
|
||||||
#endif
|
#endif
|
||||||
|
static char *e_perlsandbox = N_("E299: Perl evaluation forbidden in sandbox without the Safe module");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":perl"
|
* ":perl"
|
||||||
@@ -1019,13 +1020,12 @@ ex_perl(exarg_T *eap)
|
|||||||
vim_free(script);
|
vim_free(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SANDBOX
|
if (sandbox || secure)
|
||||||
if (sandbox)
|
|
||||||
{
|
{
|
||||||
safe = perl_get_sv("VIM::safe", FALSE);
|
safe = perl_get_sv("VIM::safe", FALSE);
|
||||||
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
|
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
|
||||||
if (safe == NULL || !SvTRUE(safe))
|
if (safe == NULL || !SvTRUE(safe))
|
||||||
emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
|
emsg(_(e_perlsandbox));
|
||||||
else
|
else
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
@@ -1037,7 +1037,6 @@ ex_perl(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
perl_eval_sv(sv, G_DISCARD | G_NOARGS);
|
perl_eval_sv(sv, G_DISCARD | G_NOARGS);
|
||||||
|
|
||||||
SvREFCNT_dec(sv);
|
SvREFCNT_dec(sv);
|
||||||
@@ -1298,13 +1297,12 @@ do_perleval(char_u *str, typval_T *rettv)
|
|||||||
ENTER;
|
ENTER;
|
||||||
SAVETMPS;
|
SAVETMPS;
|
||||||
|
|
||||||
#ifdef HAVE_SANDBOX
|
if (sandbox || secure)
|
||||||
if (sandbox)
|
|
||||||
{
|
{
|
||||||
safe = get_sv("VIM::safe", FALSE);
|
safe = get_sv("VIM::safe", FALSE);
|
||||||
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
|
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
|
||||||
if (safe == NULL || !SvTRUE(safe))
|
if (safe == NULL || !SvTRUE(safe))
|
||||||
emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
|
emsg(_(e_perlsandbox));
|
||||||
else
|
else
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
@@ -1320,7 +1318,6 @@ do_perleval(char_u *str, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* HAVE_SANDBOX */
|
|
||||||
sv = eval_pv((char *)str, 0);
|
sv = eval_pv((char *)str, 0);
|
||||||
|
|
||||||
if (sv) {
|
if (sv) {
|
||||||
|
@@ -213,6 +213,7 @@ NEW_TESTS = \
|
|||||||
test_regexp_utf8 \
|
test_regexp_utf8 \
|
||||||
test_registers \
|
test_registers \
|
||||||
test_reltime \
|
test_reltime \
|
||||||
|
test_restricted \
|
||||||
test_retab \
|
test_retab \
|
||||||
test_ruby \
|
test_ruby \
|
||||||
test_scriptnames \
|
test_scriptnames \
|
||||||
@@ -375,6 +376,7 @@ NEW_TESTS_RES = \
|
|||||||
test_quotestar.res \
|
test_quotestar.res \
|
||||||
test_regex_char_classes.res \
|
test_regex_char_classes.res \
|
||||||
test_registers.res \
|
test_registers.res \
|
||||||
|
test_restricted.res \
|
||||||
test_retab.res \
|
test_retab.res \
|
||||||
test_ruby.res \
|
test_ruby.res \
|
||||||
test_scriptnames.res \
|
test_scriptnames.res \
|
||||||
|
107
src/testdir/test_restricted.vim
Normal file
107
src/testdir/test_restricted.vim
Normal 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
|
@@ -783,6 +783,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
881,
|
||||||
/**/
|
/**/
|
||||||
880,
|
880,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user