]> granicus.if.org Git - vim/commitdiff
patch 8.1.0881: can execute shell commands in rvim through interfaces v8.1.0881
authorBram Moolenaar <Bram@vim.org>
Fri, 8 Feb 2019 13:34:10 +0000 (14:34 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 8 Feb 2019 13:34:10 +0000 (14:34 +0100)
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.

runtime/doc/starting.txt
src/evalfunc.c
src/ex_cmds.c
src/ex_docmd.c
src/if_perl.xs
src/testdir/Make_all.mak
src/testdir/test_restricted.vim [new file with mode: 0644]
src/version.c

index 711a4876b62820bf8bb1c94d535439aff1722c7f..6289e9c8f795c04a89d3d645340f73fe52f219e3 100644 (file)
@@ -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*
index fa7ed9bab1c4eed1f480dd8a411ded03cf42e093..eb082b771be43f582edb943e0e91cbf354d8a515 100644 (file)
@@ -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)
index a3974c1bad8f89062d6e913aed125f3d36438295..681ef422a9d3836c360964becc595632630c7ee5 100644 (file)
@@ -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;
index b90ea7b17c3a3b8d4a69a3b387244cdc1ef0aac4..ccca2f98fa31eee8226378a8e5860cce311ab433 100644 (file)
@@ -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 */
index 203bb6a6795b39f23c35a2864f4844ce9f2be23c..67d0b94888a5bdbdecf051468c9e2100fe7e3977 100644 (file)
@@ -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) {
index 5857a228f53a1d836dbfa7ec72adf7e5369370ca..2ca5f2b1de231f918da32ca8a057543bedd52386 100644 (file)
@@ -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 (file)
index 0000000..9dd937c
--- /dev/null
@@ -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
index 1235cf0edaaea2626de0ffaeefbe78ad79e6a54d..48236fe35464ccffb3f07d05a94b6dba03b9f99e 100644 (file)
@@ -783,6 +783,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    881,
 /**/
     880,
 /**/