summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-02-08 14:34:10 +0100
committerBram Moolenaar <Bram@vim.org>2019-02-08 14:34:10 +0100
commit8c62a08faf89663e5633dc5036cd8695c80f1075 (patch)
treeaf5faafe055ea91f652f006d05a29a2dd5c8521b
parentc6ddce3f2cf6daa3a545405373b661f8a9bccad9 (diff)
patch 8.1.0881: can execute shell commands in rvim through interfacesv8.1.0881
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.
-rw-r--r--runtime/doc/starting.txt14
-rw-r--r--src/evalfunc.c22
-rw-r--r--src/ex_cmds.c2
-rw-r--r--src/ex_docmd.c7
-rw-r--r--src/if_perl.xs13
-rw-r--r--src/testdir/Make_all.mak2
-rw-r--r--src/testdir/test_restricted.vim107
-rw-r--r--src/version.c2
8 files changed, 151 insertions, 18 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 711a4876b6..6289e9c8f7 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -248,12 +248,18 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
changes and writing.
{not in Vi}
- *-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(),
- job_start(), etc.
+ ":sh", filtering, the system() function, backtick expansion
+ and libcall().
+ 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}
*-g*
diff --git a/src/evalfunc.c b/src/evalfunc.c
index fa7ed9bab1..eb082b771b 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6817,7 +6817,7 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
#endif
rettv->vval.v_number = FALSE;
- if (check_restricted() || check_secure())
+ if (check_secure())
return;
#ifdef FEAT_CMDHIST
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 buf[NUMBUFLEN];
+ if (check_restricted() || check_secure())
+ return;
+
str = tv_get_string_buf(&argvars[0], buf);
do_luaeval(str, argvars + 1, rettv);
}
@@ -8644,6 +8647,8 @@ f_mzeval(typval_T *argvars, typval_T *rettv)
char_u *str;
char_u buf[NUMBUFLEN];
+ if (check_restricted() || check_secure())
+ return;
str = tv_get_string_buf(&argvars[0], buf);
do_mzeval(str, rettv);
}
@@ -8932,6 +8937,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
char_u *str;
char_u buf[NUMBUFLEN];
+ if (check_restricted() || check_secure())
+ return;
+
if (p_pyx == 0)
p_pyx = 3;
@@ -8950,6 +8958,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
char_u *str;
char_u buf[NUMBUFLEN];
+ if (check_restricted() || check_secure())
+ return;
+
if (p_pyx == 0)
p_pyx = 2;
@@ -8965,6 +8976,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
static void
f_pyxeval(typval_T *argvars, typval_T *rettv)
{
+ if (check_restricted() || check_secure())
+ return;
+
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
init_pyxversion();
if (p_pyx == 2)
@@ -10819,7 +10833,7 @@ f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
typval_T *varp;
char_u nbuf[NUMBUFLEN];
- if (check_restricted() || check_secure())
+ if (check_secure())
return;
(void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
varname = tv_get_string_chk(&argvars[1]);
@@ -11341,7 +11355,7 @@ f_settabvar(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 0;
- if (check_restricted() || check_secure())
+ if (check_secure())
return;
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;
rettv->vval.v_number = -1;
- if (check_restricted() || check_secure())
+ if (check_secure())
return;
if (argvars[0].v_type == VAR_LIST)
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index a3974c1bad..681ef422a9 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -4775,7 +4775,7 @@ check_restricted(void)
{
if (restricted)
{
- emsg(_("E145: Shell commands not allowed in rvim"));
+ emsg(_("E145: Shell commands and some functionality not allowed in rvim"));
return TRUE;
}
return FALSE;
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index b90ea7b17c..ccca2f98fa 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -2007,11 +2007,16 @@ do_one_cmd(
#ifdef HAVE_SANDBOX
if (sandbox != 0 && !(ea.argt & SBOXOK))
{
- /* Command not allowed in sandbox. */
+ // Command not allowed in sandbox.
errormsg = _(e_sandbox);
goto doend;
}
#endif
+ if (restricted != 0 && (ea.argt & RESTRICT))
+ {
+ errormsg = _("E981: Command not allowed in rvim");
+ goto doend;
+ }
if (!curbuf->b_p_ma && (ea.argt & MODIFY))
{
/* Command not allowed in non-'modifiable' buffer */
diff --git a/src/if_perl.xs b/src/if_perl.xs
index 203bb6a679..67d0b94888 100644
--- a/src/if_perl.xs
+++ b/src/if_perl.xs
@@ -971,6 +971,7 @@ VIM_init(void)
#ifdef DYNAMIC_PERL
static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
#endif
+static char *e_perlsandbox = N_("E299: Perl evaluation forbidden in sandbox without the Safe module");
/*
* ":perl"
@@ -1019,13 +1020,12 @@ ex_perl(exarg_T *eap)
vim_free(script);
}
-#ifdef HAVE_SANDBOX
- if (sandbox)
+ if (sandbox || secure)
{
safe = perl_get_sv("VIM::safe", FALSE);
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
if (safe == NULL || !SvTRUE(safe))
- emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
+ emsg(_(e_perlsandbox));
else
# endif
{
@@ -1037,7 +1037,6 @@ ex_perl(exarg_T *eap)
}
}
else
-#endif
perl_eval_sv(sv, G_DISCARD | G_NOARGS);
SvREFCNT_dec(sv);
@@ -1298,13 +1297,12 @@ do_perleval(char_u *str, typval_T *rettv)
ENTER;
SAVETMPS;
-#ifdef HAVE_SANDBOX
- if (sandbox)
+ if (sandbox || secure)
{
safe = get_sv("VIM::safe", FALSE);
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
if (safe == NULL || !SvTRUE(safe))
- emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
+ emsg(_(e_perlsandbox));
else
# endif
{
@@ -1320,7 +1318,6 @@ do_perleval(char_u *str, typval_T *rettv)
}
}
else
-#endif /* HAVE_SANDBOX */
sv = eval_pv((char *)str, 0);
if (sv) {
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 5857a228f5..2ca5f2b1de 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -213,6 +213,7 @@ NEW_TESTS = \
test_regexp_utf8 \
test_registers \
test_reltime \
+ test_restricted \
test_retab \
test_ruby \
test_scriptnames \
@@ -375,6 +376,7 @@ NEW_TESTS_RES = \
test_quotestar.res \
test_regex_char_classes.res \
test_registers.res \
+ test_restricted.res \
test_retab.res \
test_ruby.res \
test_scriptnames.res \
diff --git a/src/testdir/test_restricted.vim b/src/testdir/test_restricted.vim
new file mode 100644
index 0000000000..9dd937cf3e
--- /dev/null
+++ b/src/testdir/test_restricted.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 1235cf0eda..48236fe354 100644
--- a/src/version.c
+++ b/src/version.c
@@ -784,6 +784,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 881,
+/**/
880,
/**/
879,