Skip to content

Commit 8c62a08

Browse files
committed
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.
1 parent c6ddce3 commit 8c62a08

File tree

8 files changed

+151
-18
lines changed

8 files changed

+151
-18
lines changed

Diff for: runtime/doc/starting.txt

+10-4
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,18 @@ a slash. Thus "-R" means recovery and "-/R" readonly.
248248
changes and writing.
249249
{not in Vi}
250250

251-
*-Z* *restricted-mode* *E145*
251+
*-Z* *restricted-mode* *E145* *E981*
252252
-Z Restricted mode. All commands that make use of an external
253253
shell are disabled. This includes suspending with CTRL-Z,
254-
":sh", filtering, the system() function, backtick expansion,
255-
delete(), rename(), mkdir(), writefile(), libcall(),
256-
job_start(), etc.
254+
":sh", filtering, the system() function, backtick expansion
255+
and libcall().
256+
Also disallowed are delete(), rename(), mkdir(), job_start(),
257+
etc.
258+
Interfaces, such as Python, Ruby and Lua, are also disabled,
259+
since they could be used to execute shell commands. Perl uses
260+
the Safe module.
261+
Note that the user may still find a loophole to execute a
262+
shell command, it has only been made difficult.
257263
{not in Vi}
258264

259265
*-g*

Diff for: src/evalfunc.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -6817,7 +6817,7 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
68176817
#endif
68186818

68196819
rettv->vval.v_number = FALSE;
6820-
if (check_restricted() || check_secure())
6820+
if (check_secure())
68216821
return;
68226822
#ifdef FEAT_CMDHIST
68236823
str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
@@ -7898,6 +7898,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
78987898
char_u *str;
78997899
char_u buf[NUMBUFLEN];
79007900

7901+
if (check_restricted() || check_secure())
7902+
return;
7903+
79017904
str = tv_get_string_buf(&argvars[0], buf);
79027905
do_luaeval(str, argvars + 1, rettv);
79037906
}
@@ -8644,6 +8647,8 @@ f_mzeval(typval_T *argvars, typval_T *rettv)
86448647
char_u *str;
86458648
char_u buf[NUMBUFLEN];
86468649

8650+
if (check_restricted() || check_secure())
8651+
return;
86478652
str = tv_get_string_buf(&argvars[0], buf);
86488653
do_mzeval(str, rettv);
86498654
}
@@ -8932,6 +8937,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
89328937
char_u *str;
89338938
char_u buf[NUMBUFLEN];
89348939

8940+
if (check_restricted() || check_secure())
8941+
return;
8942+
89358943
if (p_pyx == 0)
89368944
p_pyx = 3;
89378945

@@ -8950,6 +8958,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
89508958
char_u *str;
89518959
char_u buf[NUMBUFLEN];
89528960

8961+
if (check_restricted() || check_secure())
8962+
return;
8963+
89538964
if (p_pyx == 0)
89548965
p_pyx = 2;
89558966

@@ -8965,6 +8976,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
89658976
static void
89668977
f_pyxeval(typval_T *argvars, typval_T *rettv)
89678978
{
8979+
if (check_restricted() || check_secure())
8980+
return;
8981+
89688982
# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
89698983
init_pyxversion();
89708984
if (p_pyx == 2)
@@ -10819,7 +10833,7 @@ f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
1081910833
typval_T *varp;
1082010834
char_u nbuf[NUMBUFLEN];
1082110835

10822-
if (check_restricted() || check_secure())
10836+
if (check_secure())
1082310837
return;
1082410838
(void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
1082510839
varname = tv_get_string_chk(&argvars[1]);
@@ -11341,7 +11355,7 @@ f_settabvar(typval_T *argvars, typval_T *rettv)
1134111355

1134211356
rettv->vval.v_number = 0;
1134311357

11344-
if (check_restricted() || check_secure())
11358+
if (check_secure())
1134511359
return;
1134611360

1134711361
tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
@@ -14714,7 +14728,7 @@ f_writefile(typval_T *argvars, typval_T *rettv)
1471414728
blob_T *blob = NULL;
1471514729

1471614730
rettv->vval.v_number = -1;
14717-
if (check_restricted() || check_secure())
14731+
if (check_secure())
1471814732
return;
1471914733

1472014734
if (argvars[0].v_type == VAR_LIST)

Diff for: src/ex_cmds.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -4775,7 +4775,7 @@ check_restricted(void)
47754775
{
47764776
if (restricted)
47774777
{
4778-
emsg(_("E145: Shell commands not allowed in rvim"));
4778+
emsg(_("E145: Shell commands and some functionality not allowed in rvim"));
47794779
return TRUE;
47804780
}
47814781
return FALSE;

Diff for: src/ex_docmd.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -2007,11 +2007,16 @@ do_one_cmd(
20072007
#ifdef HAVE_SANDBOX
20082008
if (sandbox != 0 && !(ea.argt & SBOXOK))
20092009
{
2010-
/* Command not allowed in sandbox. */
2010+
// Command not allowed in sandbox.
20112011
errormsg = _(e_sandbox);
20122012
goto doend;
20132013
}
20142014
#endif
2015+
if (restricted != 0 && (ea.argt & RESTRICT))
2016+
{
2017+
errormsg = _("E981: Command not allowed in rvim");
2018+
goto doend;
2019+
}
20152020
if (!curbuf->b_p_ma && (ea.argt & MODIFY))
20162021
{
20172022
/* Command not allowed in non-'modifiable' buffer */

Diff for: src/if_perl.xs

+5-8
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ VIM_init(void)
971971
#ifdef DYNAMIC_PERL
972972
static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
973973
#endif
974+
static char *e_perlsandbox = N_("E299: Perl evaluation forbidden in sandbox without the Safe module");
974975

975976
/*
976977
* ":perl"
@@ -1019,13 +1020,12 @@ ex_perl(exarg_T *eap)
10191020
vim_free(script);
10201021
}
10211022

1022-
#ifdef HAVE_SANDBOX
1023-
if (sandbox)
1023+
if (sandbox || secure)
10241024
{
10251025
safe = perl_get_sv("VIM::safe", FALSE);
10261026
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
10271027
if (safe == NULL || !SvTRUE(safe))
1028-
emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
1028+
emsg(_(e_perlsandbox));
10291029
else
10301030
# endif
10311031
{
@@ -1037,7 +1037,6 @@ ex_perl(exarg_T *eap)
10371037
}
10381038
}
10391039
else
1040-
#endif
10411040
perl_eval_sv(sv, G_DISCARD | G_NOARGS);
10421041

10431042
SvREFCNT_dec(sv);
@@ -1298,13 +1297,12 @@ do_perleval(char_u *str, typval_T *rettv)
12981297
ENTER;
12991298
SAVETMPS;
13001299

1301-
#ifdef HAVE_SANDBOX
1302-
if (sandbox)
1300+
if (sandbox || secure)
13031301
{
13041302
safe = get_sv("VIM::safe", FALSE);
13051303
# ifndef MAKE_TEST /* avoid a warning for unreachable code */
13061304
if (safe == NULL || !SvTRUE(safe))
1307-
emsg(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
1305+
emsg(_(e_perlsandbox));
13081306
else
13091307
# endif
13101308
{
@@ -1320,7 +1318,6 @@ do_perleval(char_u *str, typval_T *rettv)
13201318
}
13211319
}
13221320
else
1323-
#endif /* HAVE_SANDBOX */
13241321
sv = eval_pv((char *)str, 0);
13251322

13261323
if (sv) {

Diff for: src/testdir/Make_all.mak

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ NEW_TESTS = \
213213
test_regexp_utf8 \
214214
test_registers \
215215
test_reltime \
216+
test_restricted \
216217
test_retab \
217218
test_ruby \
218219
test_scriptnames \
@@ -375,6 +376,7 @@ NEW_TESTS_RES = \
375376
test_quotestar.res \
376377
test_regex_char_classes.res \
377378
test_registers.res \
379+
test_restricted.res \
378380
test_retab.res \
379381
test_ruby.res \
380382
test_scriptnames.res \

Diff for: src/testdir/test_restricted.vim

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
" Test for "rvim" or "vim -Z"
2+
3+
source shared.vim
4+
5+
func Test_restricted()
6+
let cmd = GetVimCommand('Xrestricted')
7+
if cmd == ''
8+
return
9+
endif
10+
11+
call writefile([
12+
\ "silent !ls",
13+
\ "call writefile([v:errmsg], 'Xrestrout')",
14+
\ "qa!",
15+
\ ], 'Xrestricted')
16+
call system(cmd . ' -Z')
17+
call assert_match('E145:', join(readfile('Xrestrout')))
18+
19+
call delete('Xrestricted')
20+
call delete('Xrestrout')
21+
endfunc
22+
23+
func Run_restricted_test(ex_cmd, error)
24+
let cmd = GetVimCommand('Xrestricted')
25+
if cmd == ''
26+
return
27+
endif
28+
29+
call writefile([
30+
\ a:ex_cmd,
31+
\ "call writefile([v:errmsg], 'Xrestrout')",
32+
\ "qa!",
33+
\ ], 'Xrestricted')
34+
call system(cmd . ' -Z')
35+
call assert_match(a:error, join(readfile('Xrestrout')))
36+
37+
call delete('Xrestricted')
38+
call delete('Xrestrout')
39+
endfunc
40+
41+
func Test_restricted_lua()
42+
if !has('lua')
43+
throw 'Skipped: Lua is not supported'
44+
endif
45+
call Run_restricted_test('lua print("Hello, Vim!")', 'E981:')
46+
call Run_restricted_test('luado return "hello"', 'E981:')
47+
call Run_restricted_test('luafile somefile', 'E981:')
48+
call Run_restricted_test('call luaeval("expression")', 'E145:')
49+
endfunc
50+
51+
func Test_restricted_mzscheme()
52+
if !has('mzscheme')
53+
throw 'Skipped: MzScheme is not supported'
54+
endif
55+
call Run_restricted_test('mzscheme statement', 'E981:')
56+
call Run_restricted_test('mzfile somefile', 'E981:')
57+
call Run_restricted_test('call mzeval("expression")', 'E145:')
58+
endfunc
59+
60+
func Test_restricted_perl()
61+
if !has('perl')
62+
throw 'Skipped: Perl is not supported'
63+
endif
64+
" TODO: how to make Safe mode fail?
65+
" call Run_restricted_test('perl system("ls")', 'E981:')
66+
" call Run_restricted_test('perldo system("hello")', 'E981:')
67+
" call Run_restricted_test('perlfile somefile', 'E981:')
68+
" call Run_restricted_test('call perleval("system(\"ls\")")', 'E145:')
69+
endfunc
70+
71+
func Test_restricted_python()
72+
if !has('python')
73+
throw 'Skipped: Python is not supported'
74+
endif
75+
call Run_restricted_test('python print "hello"', 'E981:')
76+
call Run_restricted_test('pydo return "hello"', 'E981:')
77+
call Run_restricted_test('pyfile somefile', 'E981:')
78+
call Run_restricted_test('call pyeval("expression")', 'E145:')
79+
endfunc
80+
81+
func Test_restricted_python3()
82+
if !has('python3')
83+
throw 'Skipped: Python3 is not supported'
84+
endif
85+
call Run_restricted_test('py3 print "hello"', 'E981:')
86+
call Run_restricted_test('py3do return "hello"', 'E981:')
87+
call Run_restricted_test('py3file somefile', 'E981:')
88+
call Run_restricted_test('call py3eval("expression")', 'E145:')
89+
endfunc
90+
91+
func Test_restricted_ruby()
92+
if !has('ruby')
93+
throw 'Skipped: Ruby is not supported'
94+
endif
95+
call Run_restricted_test('ruby print "Hello"', 'E981:')
96+
call Run_restricted_test('rubydo print "Hello"', 'E981:')
97+
call Run_restricted_test('rubyfile somefile', 'E981:')
98+
endfunc
99+
100+
func Test_restricted_tcl()
101+
if !has('tcl')
102+
throw 'Skipped: Tcl is not supported'
103+
endif
104+
call Run_restricted_test('tcl puts "Hello"', 'E981:')
105+
call Run_restricted_test('tcldo puts "Hello"', 'E981:')
106+
call Run_restricted_test('tclfile somefile', 'E981:')
107+
endfunc

Diff for: src/version.c

+2
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,8 @@ static char *(features[]) =
783783

784784
static int included_patches[] =
785785
{ /* Add new patch number below this line */
786+
/**/
787+
881,
786788
/**/
787789
880,
788790
/**/

0 commit comments

Comments
 (0)