diff --git a/SOURCES/0001-patch-8.1.0881-can-execute-shell-commands-in-rvim-th.patch b/SOURCES/0001-patch-8.1.0881-can-execute-shell-commands-in-rvim-th.patch new file mode 100644 index 0000000..e74d837 --- /dev/null +++ b/SOURCES/0001-patch-8.1.0881-can-execute-shell-commands-in-rvim-th.patch @@ -0,0 +1,461 @@ +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 diff --git a/SPECS/vim.spec b/SPECS/vim.spec index fd65122..40f0fae 100644 --- a/SPECS/vim.spec +++ b/SPECS/vim.spec @@ -24,7 +24,7 @@ Summary: The VIM editor URL: http://www.vim.org/ Name: vim Version: %{baseversion}.%{patchlevel} -Release: 13%{?dist} +Release: 15%{?dist} License: Vim and MIT Source0: ftp://ftp.vim.org/pub/vim/unix/vim-%{baseversion}-%{patchlevel}.tar.bz2 Source1: vim.sh @@ -73,6 +73,8 @@ Patch3018: vim-covscan.patch Patch3019: 0001-patch-8.1.1365-source-command-doesn-t-check-for-the-.patch # 1605095 - vim: should not re-implement crypto Patch3020: vim-crypto-warning.patch +# 1842755 - CVE-2019-20807 +Patch3021: 0001-patch-8.1.0881-can-execute-shell-commands-in-rvim-th.patch # gcc is no longer in buildroot by default BuildRequires: gcc @@ -270,6 +272,7 @@ perl -pi -e "s,bin/nawk,bin/awk,g" runtime/tools/mve.awk %patch3018 -p1 %patch3019 -p1 -b .cve %patch3020 -p1 -b .crypto-warning +%patch3021 -p1 -b .rvim %build %if 0%{?rhel} > 7 @@ -549,16 +552,6 @@ rm -f %{buildroot}/%{_datadir}/vim/%{vimdir}/macros/maze/maze*.c rm -rf %{buildroot}/%{_datadir}/vim/%{vimdir}/tools rm -rf %{buildroot}/%{_datadir}/vim/%{vimdir}/doc/vim2html.pl rm -f %{buildroot}/%{_datadir}/vim/%{vimdir}/tutor/tutor.gr.utf-8~ -( cd %{buildroot}/%{_mandir} - for i in `find ??/ -type f`; do - if [[ "`file $i`" == *UTF-8\ Unicode\ text* ]]; then - continue - fi - bi=`basename $i` - iconv -f latin1 -t UTF8 $i > %{buildroot}/$bi - mv -f %{buildroot}/$bi $i - done -) # Remove not UTF-8 manpages for i in pl.ISO8859-2 it.ISO8859-1 ru.KOI8-R fr.ISO8859-1; do @@ -798,6 +791,12 @@ touch %{buildroot}/%{_datadir}/%{name}/vimfiles/doc/tags %{_datadir}/icons/locolor/*/apps/* %changelog +* Tue Jun 02 2020 Zdenek Dohnal - 2:8.0.1763-15 +- 1842755 - CVE-2019-20807 + +* Mon Feb 10 2020 Zdenek Dohnal - 2:8.0.1763-14 +- 1745476 - manpage of vim is garbled in Japanese locale + * Tue Jul 23 2019 Zdenek Dohnal - 2:8.0.1763-13 - fixing covscan issues raised by previous commit