462 lines
14 KiB
Diff
462 lines
14 KiB
Diff
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
|
|
index 8256152..8320039 100644
|
|
--- a/runtime/doc/starting.txt
|
|
+++ b/runtime/doc/starting.txt
|
|
@@ -247,12 +247,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 dd4462d..3cc305a 100644
|
|
--- a/src/evalfunc.c
|
|
+++ b/src/evalfunc.c
|
|
@@ -6446,7 +6446,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 = get_tv_string_chk(&argvars[0]); /* NULL on type error */
|
|
@@ -7456,6 +7456,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
|
|
char_u *str;
|
|
char_u buf[NUMBUFLEN];
|
|
|
|
+ if (check_restricted() || check_secure())
|
|
+ return;
|
|
+
|
|
str = get_tv_string_buf(&argvars[0], buf);
|
|
do_luaeval(str, argvars + 1, rettv);
|
|
}
|
|
@@ -8188,6 +8191,8 @@ f_mzeval(typval_T *argvars, typval_T *rettv)
|
|
char_u *str;
|
|
char_u buf[NUMBUFLEN];
|
|
|
|
+ if (check_restricted() || check_secure())
|
|
+ return;
|
|
str = get_tv_string_buf(&argvars[0], buf);
|
|
do_mzeval(str, rettv);
|
|
}
|
|
@@ -8398,6 +8403,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;
|
|
|
|
@@ -8416,6 +8424,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;
|
|
|
|
@@ -8431,6 +8442,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)
|
|
@@ -10272,7 +10286,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)get_tv_number(&argvars[0]); /* issue errmsg if type error */
|
|
varname = get_tv_string_chk(&argvars[1]);
|
|
@@ -10792,7 +10806,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)get_tv_number_chk(&argvars[0], NULL));
|
|
@@ -13674,7 +13688,7 @@ f_writefile(typval_T *argvars, typval_T *rettv)
|
|
list_T *list;
|
|
|
|
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 111fe01..1827fec 100644
|
|
--- a/src/ex_cmds.c
|
|
+++ b/src/ex_cmds.c
|
|
@@ -4693,7 +4693,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_cmds.h b/src/ex_cmds.h
|
|
index 48b0253..82d6e29 100644
|
|
--- a/src/ex_cmds.h
|
|
+++ b/src/ex_cmds.h
|
|
@@ -56,6 +56,7 @@
|
|
* curbuf_lock is set */
|
|
#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */
|
|
#define EXFLAGS 0x400000L /* allow flags after count in argument */
|
|
+#define RESTRICT 0x800000L /* forbidden in restricted mode */
|
|
#define FILES (XFILE | EXTRA) /* multiple extra files allowed */
|
|
#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */
|
|
#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */
|
|
@@ -860,13 +861,13 @@ EX(CMD_lunmap, "lunmap", ex_unmap,
|
|
EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
|
|
ADDR_LINES),
|
|
EX(CMD_lua, "lua", ex_lua,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_luado, "luado", ex_luado,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_luafile, "luafile", ex_luafile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_lvimgrep, "lvimgrep", ex_vimgrep,
|
|
RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
|
|
@@ -929,10 +930,10 @@ EX(CMD_mode, "mode", ex_mode,
|
|
WORD1|TRLBAR|CMDWIN,
|
|
ADDR_LINES),
|
|
EX(CMD_mzscheme, "mzscheme", ex_mzscheme,
|
|
- RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK,
|
|
+ RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_mzfile, "mzfile", ex_mzfile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_next, "next", ex_next,
|
|
RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
|
|
@@ -1115,37 +1116,37 @@ EX(CMD_pwd, "pwd", ex_pwd,
|
|
TRLBAR|CMDWIN,
|
|
ADDR_LINES),
|
|
EX(CMD_python, "python", ex_python,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pydo, "pydo", ex_pydo,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pyfile, "pyfile", ex_pyfile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_py3, "py3", ex_py3,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_py3do, "py3do", ex_py3do,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_python3, "python3", ex_py3,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_py3file, "py3file", ex_py3file,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pyx, "pyx", ex_pyx,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pyxdo, "pyxdo", ex_pyxdo,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pythonx, "pythonx", ex_pyx,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_pyxfile, "pyxfile", ex_pyxfile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_quit, "quit", ex_quit,
|
|
BANG|RANGE|COUNT|NOTADR|TRLBAR|CMDWIN,
|
|
@@ -1199,13 +1200,13 @@ EX(CMD_runtime, "runtime", ex_runtime,
|
|
BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN,
|
|
ADDR_LINES),
|
|
EX(CMD_ruby, "ruby", ex_ruby,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_rubydo, "rubydo", ex_rubydo,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_rubyfile, "rubyfile", ex_rubyfile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_rundo, "rundo", ex_rundo,
|
|
NEEDARG|FILE1,
|
|
@@ -1472,13 +1473,13 @@ EX(CMD_tabs, "tabs", ex_tabs,
|
|
TRLBAR|CMDWIN,
|
|
ADDR_TABS),
|
|
EX(CMD_tcl, "tcl", ex_tcl,
|
|
- RANGE|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_tcldo, "tcldo", ex_tcldo,
|
|
- RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
|
|
+ RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_tclfile, "tclfile", ex_tclfile,
|
|
- RANGE|FILE1|NEEDARG|CMDWIN,
|
|
+ RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
|
|
ADDR_LINES),
|
|
EX(CMD_tearoff, "tearoff", ex_tearoff,
|
|
NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN,
|
|
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
|
|
index ef86fc8..aaf2f9d 100644
|
|
--- a/src/ex_docmd.c
|
|
+++ b/src/ex_docmd.c
|
|
@@ -2372,11 +2372,16 @@ do_one_cmd(
|
|
#ifdef HAVE_SANDBOX
|
|
if (sandbox != 0 && !(ea.argt & SBOXOK))
|
|
{
|
|
- /* Command not allowed in sandbox. */
|
|
+ // Command not allowed in sandbox.
|
|
errormsg = (char_u *)_(e_sandbox);
|
|
goto doend;
|
|
}
|
|
#endif
|
|
+ if (restricted != 0 && (ea.argt & RESTRICT))
|
|
+ {
|
|
+ errormsg = (char_u *)_("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 7b45033..fc8d613 100644
|
|
--- a/src/if_perl.xs
|
|
+++ b/src/if_perl.xs
|
|
@@ -930,6 +930,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"
|
|
@@ -978,13 +979,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
|
|
{
|
|
@@ -996,7 +996,6 @@ ex_perl(exarg_T *eap)
|
|
}
|
|
}
|
|
else
|
|
-#endif
|
|
perl_eval_sv(sv, G_DISCARD | G_NOARGS);
|
|
|
|
SvREFCNT_dec(sv);
|
|
@@ -1259,13 +1258,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
|
|
{
|
|
@@ -1281,7 +1279,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 e36089a..5f1c38c 100644
|
|
--- a/src/testdir/Make_all.mak
|
|
+++ b/src/testdir/Make_all.mak
|
|
@@ -156,6 +156,7 @@ NEW_TESTS = test_arabic.res \
|
|
test_quotestar.res \
|
|
test_regex_char_classes.res \
|
|
test_registers.res \
|
|
+ test_restricted.res \
|
|
test_retab.res \
|
|
test_ruby.res \
|
|
test_scrollbind.res \
|
|
diff --git a/src/testdir/test_restricted.vim b/src/testdir/test_restricted.vim
|
|
new file mode 100644
|
|
index 0000000..9dd937c
|
|
--- /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
|