diff --git a/0001-patch-8.1.1366-using-expressions-in-modeline-is-unsafe.patch b/0001-patch-8.1.1366-using-expressions-in-modeline-is-unsafe.patch new file mode 100644 index 00000000..6a6b1d6e --- /dev/null +++ b/0001-patch-8.1.1366-using-expressions-in-modeline-is-unsafe.patch @@ -0,0 +1,500 @@ +diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt +index b7f9869..2558f17 100644 +--- a/runtime/doc/options.txt ++++ b/runtime/doc/options.txt +@@ -589,13 +589,17 @@ backslash in front of the ':' will be removed. Example: + This sets the 'dir' option to "c:\tmp". Only a single backslash before the + ':' is removed. Thus to include "\:" you have to specify "\\:". + ++ *E992* + No other commands than "set" are supported, for security reasons (somebody + might create a Trojan horse text file with modelines). And not all options +-can be set. For some options a flag is set, so that when it's used the +-|sandbox| is effective. Still, there is always a small risk that a modeline +-causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines +-are wrapped unexpectedly. So disable modelines before editing untrusted text. +-The mail ftplugin does this, for example. ++can be set. For some options a flag is set, so that when the value is used ++the |sandbox| is effective. Some options can only be set from the modeline ++when 'modelineexpr' is set (the default is off). ++ ++Still, there is always a small risk that a modeline causes trouble. E.g., ++when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly. ++So disable modelines before editing untrusted text. The mail ftplugin does ++this, for example. + + Hint: If you would like to do something else than setting an option, you could + define an autocommand that checks the file for a specific string. For +@@ -1177,6 +1181,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'balloonexpr' |textlock|. +@@ -3290,7 +3295,7 @@ A jump table for the options with a short description can be found at |Q_op|. + The expression will be evaluated in the |sandbox| if set from a + modeline, see |sandbox-option|. + This option can't be set from a |modeline| when the 'diff' option is +- on. ++ on or the 'modelineexpr' option is off. + + It is not allowed to change text or jump to another window while + evaluating 'foldexpr' |textlock|. +@@ -3432,6 +3437,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The expression will be evaluated in the |sandbox| if set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'foldtext' |textlock|. +@@ -3470,6 +3476,7 @@ A jump table for the options with a short description can be found at |Q_op|. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. That stops the option from working, + since changing the buffer text is not allowed. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + NOTE: This option is set to "" when 'compatible' is set. + + *'formatoptions'* *'fo'* +@@ -3530,6 +3537,8 @@ A jump table for the options with a short description can be found at |Q_op|. + Also see 'swapsync' for controlling fsync() on swap files. + 'fsync' also applies to |writefile()|, unless a flag is used to + overrule it. ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. + + *'gdefault'* *'gd'* *'nogdefault'* *'nogd'* + 'gdefault' 'gd' boolean (default off) +@@ -3985,6 +3994,7 @@ A jump table for the options with a short description can be found at |Q_op|. + 'guitabtooltip' is used for the tooltip, see below. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + Only used when the GUI tab pages line is displayed. 'e' must be + present in 'guioptions'. For the non-GUI tab pages line 'tabline' is +@@ -4246,6 +4256,7 @@ A jump table for the options with a short description can be found at |Q_op|. + When this option contains printf-style '%' items, they will be + expanded according to the rules used for 'statusline'. See + 'titlestring' for example settings. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + {not available when compiled without the |+statusline| feature} + + *'ignorecase'* *'ic'* *'noignorecase'* *'noic'* +@@ -4265,6 +4276,8 @@ A jump table for the options with a short description can be found at |Q_op|. + This option specifies a function that will be called to + activate or deactivate the Input Method. + It is not used in the GUI. ++ The expression will be evaluated in the |sandbox| when set from a ++ modeline, see |sandbox-option|. + + Example: > + function ImActivateFunc(active) +@@ -5296,6 +5309,19 @@ A jump table for the options with a short description can be found at |Q_op|. + Vi default: off) + local to buffer + *'modelines'* *'mls'* ++ If 'modeline' is on 'modelines' gives the number of lines that is ++ checked for set commands. If 'modeline' is off or 'modelines' is zero ++ no lines are checked. See |modeline|. ++ ++ *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'* ++'modelineexpr' 'mle' boolean (default: off) ++ global ++ When on allow some options that are an expression to be set in the ++ modeline. Check the option for whether it is affected by ++ 'modelineexpr'. Also see |modeline|. ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. ++ + 'modelines' 'mls' number (default 5) + global + {not in Vi} +@@ -5306,9 +5332,9 @@ A jump table for the options with a short description can be found at |Q_op|. + set and to the Vim default value when 'compatible' is reset. + + *'modifiable'* *'ma'* *'nomodifiable'* *'noma'* ++ *E21* + 'modifiable' 'ma' boolean (default on) + local to buffer +- {not in Vi} *E21* + When off the buffer contents cannot be changed. The 'fileformat' and + 'fileencoding' options also can't be changed. + Can be reset on startup with the |-M| command line argument. +@@ -6357,6 +6383,8 @@ A jump table for the options with a short description can be found at |Q_op|. + When this option is not empty, it determines the content of the ruler + string, as displayed for the 'ruler' option. + The format of this option is like that of 'statusline'. ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + The default ruler width is 17 characters. To make the ruler 15 + characters wide, put "%15(" at the start and "%)" at the end. + Example: > +@@ -6911,7 +6939,8 @@ A jump table for the options with a short description can be found at |Q_op|. + "Pattern not found", "Back at original", etc. + q use "recording" instead of "recording @a" + F don't give the file info when editing a file, like `:silent` +- was used for the command ++ was used for the command; note that this also affects messages ++ from autocommands + + This gives you the opportunity to avoid that a change between buffers + requires you to hit , but still gives as useful a message as +@@ -7488,6 +7517,7 @@ A jump table for the options with a short description can be found at |Q_op|. + + The 'statusline' option will be evaluated in the |sandbox| if set from + a modeline, see |sandbox-option|. ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + It is not allowed to change text or jump to another window while + evaluating 'statusline' |textlock|. +@@ -7672,6 +7702,8 @@ A jump table for the options with a short description can be found at |Q_op|. + the text to be displayed. Use "%1T" for the first label, "%2T" for + the second one, etc. Use "%X" items for closing labels. + ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + Keep in mind that only one of the tab pages is the current one, others + are invisible and you can't jump to their windows. + +@@ -8188,8 +8220,11 @@ A jump table for the options with a short description can be found at |Q_op|. + non-empty 't_ts' option). + When Vim was compiled with HAVE_X11 defined, the original title will + be restored if possible, see |X11|. ++ + When this option contains printf-style '%' items, they will be + expanded according to the rules used for 'statusline'. ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + Example: > + :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p") + :set title titlestring=%<%F%=%l/%L-%P titlelen=70 +@@ -8378,6 +8413,8 @@ A jump table for the options with a short description can be found at |Q_op|. + undo file that exists is used. When it cannot be read an error is + given, no further entry is used. + See |undo-persistence|. ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. + + *'undofile'* *'noundofile'* *'udf'* *'noudf'* + 'undofile' 'udf' boolean (default off) +@@ -8663,6 +8700,8 @@ A jump table for the options with a short description can be found at |Q_op|. + When equal to "NONE" no viminfo file will be read or written. + This option can be set with the |-i| command line flag. The |--clean| + command line flag sets it to "NONE". ++ This option cannot be set from a |modeline| or in the |sandbox|, for ++ security reasons. + + *'virtualedit'* *'ve'* + 'virtualedit' 've' string (default "") +diff --git a/src/Makefile b/src/Makefile +index 85de383..1e9ab0d 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -2236,6 +2236,7 @@ test_arglist \ + test_messages \ + test_mksession \ + test_mksession_utf8 \ ++ test_modeline \ + test_nested_function \ + test_netbeans \ + test_normal \ +diff --git a/src/option.c b/src/option.c +index 31aec7e..74ad244 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -458,6 +458,7 @@ struct vimoption + * there is a redraw flag */ + #define P_NDNAME 0x8000000L /* only normal dir name chars allowed */ + #define P_RWINONLY 0x10000000L /* only redraw current window */ ++#define P_MLE 0x20000000L /* under control of 'modelineexpr' */ + + #define ISK_LATIN1 (char_u *)"@,48-57,_,192-255" + +@@ -647,7 +648,7 @@ static struct vimoption options[] = + {(char_u *)0L, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, ++ {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, + #if defined(FEAT_BEVAL) && defined(FEAT_EVAL) + (char_u *)&p_bexpr, PV_BEXPR, + {(char_u *)"", (char_u *)0L} +@@ -733,7 +734,7 @@ static struct vimoption options[] = + {(char_u *)0L, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP, ++ {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE|P_COMMA|P_NODUP, + #ifdef FEAT_SEARCHPATH + (char_u *)&p_cdpath, PV_NONE, + {(char_u *)",,", (char_u *)0L} +@@ -1209,7 +1210,7 @@ static struct vimoption options[] = + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN, ++ {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE, + #if defined(FEAT_FOLDING) && defined(FEAT_EVAL) + (char_u *)VAR_WIN, PV_FDE, + {(char_u *)"0", (char_u *)NULL} +@@ -1292,7 +1293,7 @@ static struct vimoption options[] = + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN, ++ {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE, + #if defined(FEAT_FOLDING) && defined(FEAT_EVAL) + (char_u *)VAR_WIN, PV_FDT, + {(char_u *)"foldtext()", (char_u *)NULL} +@@ -1301,7 +1302,7 @@ static struct vimoption options[] = + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, ++ {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, + #ifdef FEAT_EVAL + (char_u *)&p_fex, PV_FEX, + {(char_u *)"", (char_u *)0L} +@@ -1440,7 +1441,7 @@ static struct vimoption options[] = + (char_u *)NULL, PV_NONE, + #endif + {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT}, +- {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN, ++ {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN|P_MLE, + #if defined(FEAT_GUI_TABLINE) + (char_u *)&p_gtl, PV_NONE, + {(char_u *)"", (char_u *)0L} +@@ -1511,7 +1512,7 @@ static struct vimoption options[] = + (char_u *)NULL, PV_NONE, + #endif + {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, +- {"iconstring", NULL, P_STRING|P_VI_DEF, ++ {"iconstring", NULL, P_STRING|P_VI_DEF|P_MLE, + #ifdef FEAT_TITLE + (char_u *)&p_iconstring, PV_NONE, + #else +@@ -1591,7 +1592,7 @@ static struct vimoption options[] = + {(char_u *)0L, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF, ++ {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF|P_MLE, + #if defined(FEAT_FIND_ID) && defined(FEAT_EVAL) + (char_u *)&p_inex, PV_INEX, + {(char_u *)"", (char_u *)0L} +@@ -1603,7 +1604,7 @@ static struct vimoption options[] = + {"incsearch", "is", P_BOOL|P_VI_DEF|P_VIM, + (char_u *)&p_is, PV_NONE, + {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, +- {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, ++ {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, + #if defined(FEAT_CINDENT) && defined(FEAT_EVAL) + (char_u *)&p_inde, PV_INDE, + {(char_u *)"", (char_u *)0L} +@@ -1939,6 +1940,9 @@ static struct vimoption options[] = + {"modeline", "ml", P_BOOL|P_VIM, + (char_u *)&p_ml, PV_ML, + {(char_u *)FALSE, (char_u *)TRUE} SCRIPTID_INIT}, ++ {"modelineexpr", "mle", P_BOOL|P_VI_DEF|P_SECURE, ++ (char_u *)&p_mle, PV_NONE, ++ {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, + {"modelines", "mls", P_NUM|P_VI_DEF, + (char_u *)&p_mls, PV_NONE, + {(char_u *)5L, (char_u *)0L} SCRIPTID_INIT}, +@@ -2362,7 +2366,7 @@ static struct vimoption options[] = + (char_u *)NULL, PV_NONE, + #endif + {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, +- {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT, ++ {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE, + #ifdef FEAT_STL_OPT + (char_u *)&p_ruf, PV_NONE, + #else +@@ -2628,7 +2632,7 @@ static struct vimoption options[] = + {"startofline", "sol", P_BOOL|P_VI_DEF|P_VIM, + (char_u *)&p_sol, PV_NONE, + {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT}, +- {"statusline" ,"stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT, ++ {"statusline" ,"stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE, + #ifdef FEAT_STL_OPT + (char_u *)&p_stl, PV_STL, + #else +@@ -2675,7 +2679,7 @@ static struct vimoption options[] = + {(char_u *)0L, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL, ++ {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL|P_MLE, + #ifdef FEAT_STL_OPT + (char_u *)&p_tal, PV_NONE, + #else +@@ -2870,7 +2874,7 @@ static struct vimoption options[] = + {(char_u *)0L, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"titlestring", NULL, P_STRING|P_VI_DEF, ++ {"titlestring", NULL, P_STRING|P_VI_DEF|P_MLE, + #ifdef FEAT_TITLE + (char_u *)&p_titlestring, PV_NONE, + #else +@@ -4608,6 +4612,11 @@ do_set( + errmsg = (char_u *)_("E520: Not allowed in a modeline"); + goto skip; + } ++ if ((flags & P_MLE) && !p_mle) ++ { ++ errmsg = _("E992: Not allowed in a modeline when 'modelineexpr' is off"); ++ goto skip; ++ } + #ifdef FEAT_DIFF + /* In diff mode some options are overruled. This avoids that + * 'foldmethod' becomes "marker" instead of "diff" and that +diff --git a/src/option.h b/src/option.h +index 8f492c3..dfec21e 100644 +--- a/src/option.h ++++ b/src/option.h +@@ -659,6 +659,7 @@ EXTERN long p_mis; /* 'menuitems' */ + #ifdef FEAT_SPELL + EXTERN char_u *p_msm; /* 'mkspellmem' */ + #endif ++EXTERN long p_mle; /* 'modelineexpr' */ + EXTERN long p_mls; /* 'modelines' */ + EXTERN char_u *p_mouse; /* 'mouse' */ + #ifdef FEAT_GUI +diff --git a/src/testdir/test49.in b/src/testdir/test49.in +index 79f13f6..a0c9e0d 100644 +--- a/src/testdir/test49.in ++++ b/src/testdir/test49.in +@@ -5,7 +5,7 @@ test49.failed, try to add one or more "G"s at the line ending in "test.out" + + STARTTEST + :so small.vim +-:se nocp nomore viminfo+=nviminfo ++:se nocp nomore viminfo+=nviminfo modelineexpr + :lang mess C + :so test49.vim + :" Go back to this file and append the results from register r. +diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim +index b8a5650..018a507 100644 +--- a/src/testdir/test_alot.vim ++++ b/src/testdir/test_alot.vim +@@ -36,6 +36,7 @@ source test_mapping.vim + source test_match.vim + source test_menu.vim + source test_messages.vim ++source test_modeline.vim + source test_partial.vim + source test_popup.vim + source test_put.vim +diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim +new file mode 100644 +index 0000000..d2c3233 +--- /dev/null ++++ b/src/testdir/test_modeline.vim +@@ -0,0 +1,103 @@ ++" Tests for parsing the modeline. ++ ++func s:modeline_fails(what, text, error) ++ if !exists('+' . a:what) ++ return ++ endif ++ let fname = "Xmodeline_fails_" . a:what ++ call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) ++ let modeline = &modeline ++ set modeline ++ filetype plugin on ++ syntax enable ++ call assert_fails('split ' . fname, a:error) ++ call assert_equal("", &filetype) ++ call assert_equal("", &syntax) ++ ++ " Some options set a mark, don't let them cause a failure. ++ wviminfo! Xviminfo ++ bwipe! ++ call delete(fname) ++ call delete('Xviminfo') ++ let &modeline = modeline ++ filetype plugin off ++ syntax off ++endfunc ++ ++func Test_modeline_fails_always() ++ call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') ++ call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') ++ call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') ++ call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') ++ call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') ++ call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') ++ call s:modeline_fails('directory', 'directory=Something()', 'E520:') ++ call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') ++ call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') ++ call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') ++ call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') ++ call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') ++ call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') ++ call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') ++ call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') ++ call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') ++ call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') ++ call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') ++ call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') ++ call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') ++ call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') ++ call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') ++ call s:modeline_fails('makespellmem', 'makespellmem=Something()', 'E520:') ++ call s:modeline_fails('modelineexpr', 'modelineexpr', 'E520:') ++ call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') ++ call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') ++ call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') ++ call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') ++ call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') ++ call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') ++ call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') ++ call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') ++ call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') ++ call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:') ++ call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') ++ call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') ++ call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') ++ call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') ++ call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') ++ call s:modeline_fails('secure', 'secure=Something()', 'E520:') ++ call s:modeline_fails('shell', 'shell=Something()', 'E520:') ++ call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') ++ call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') ++ call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') ++ call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') ++ call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') ++ call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') ++ call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') ++ call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') ++ call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') ++ call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') ++ call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') ++ call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') ++ call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') ++ call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') ++ " only check a few terminal options ++ call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') ++ call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') ++ call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') ++ call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') ++endfunc ++ ++func Test_modeline_fails_modelineexpr() ++ call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') ++ call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') ++ call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') ++ call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') ++ call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') ++ call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') ++ call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') ++ call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') ++ call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') ++ call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') ++ call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') ++ call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') ++endfunc diff --git a/0001-patch-8.1.1401-misspelled-mkspellmem.patch b/0001-patch-8.1.1401-misspelled-mkspellmem.patch new file mode 100644 index 00000000..df967675 --- /dev/null +++ b/0001-patch-8.1.1401-misspelled-mkspellmem.patch @@ -0,0 +1,26 @@ +diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt +index f3ba03c..cb8f482 100644 +--- a/runtime/doc/options.txt ++++ b/runtime/doc/options.txt +@@ -5304,6 +5304,8 @@ A jump table for the options with a short description can be found at |Q_op|. + < If you have less than 512 Mbyte |:mkspell| may fail for some + languages, no matter what you set 'mkspellmem' to. + ++ This option cannot be set from a |modeline| or in the |sandbox|. ++ + *'modeline'* *'ml'* *'nomodeline'* *'noml'* + 'modeline' 'ml' boolean (Vim default: on (off for root), + Vi default: off) +diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim +index 3140b07..ec986f4 100644 +--- a/src/testdir/test_modeline.vim ++++ b/src/testdir/test_modeline.vim +@@ -45,7 +45,7 @@ func Test_modeline_fails_always() + call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') + call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') + call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') +- call s:modeline_fails('makespellmem', 'makespellmem=Something()', 'E520:') ++ call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:') + call s:modeline_fails('modelineexpr', 'modelineexpr', 'E520:') + call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') + call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') diff --git a/0001-patch-9.2.0276-security-modeline-security-bypass.patch b/0001-patch-9.2.0276-security-modeline-security-bypass.patch new file mode 100644 index 00000000..eb1fae23 --- /dev/null +++ b/0001-patch-9.2.0276-security-modeline-security-bypass.patch @@ -0,0 +1,52 @@ +From 75661a66a1db1e1f3f1245c615f13a7de44c0587 Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +Date: Tue, 31 Mar 2026 18:29:00 +0000 +Subject: [PATCH] patch 9.2.0276: [security]: modeline security bypass + +Problem: [security]: modeline security bypass +Solution: set the P_MLE flag for the 'complete', 'guitabtooltip' and + 'printheader' options. + +Github Advisory: +https://github.com/vim/vim/security/advisories/GHSA-8h6p-m6gr-mpw9 + +Signed-off-by: Christian Brabandt + +Backported for vim 8.0.1763 - only option changes (mapset doesn't exist) +--- + src/option.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/option.c b/src/option.c +index abc..def 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -852,7 +852,7 @@ static struct vimoption options[] = + {"compatible", "cp", P_BOOL|P_RALL, + (char_u *)&p_cp, PV_NONE, + {(char_u *)TRUE, (char_u *)FALSE} SCRIPTID_INIT}, +- {"complete", "cpt", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP, ++ {"complete", "cpt", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP|P_MLE, + #ifdef FEAT_INS_EXPAND + (char_u *)&p_cpt, PV_CPT, + {(char_u *)".,w,b,u,t,i", (char_u *)0L} +@@ -1449,7 +1449,7 @@ static struct vimoption options[] = + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN, ++ {"guitabtooltip", "gtt", P_STRING|P_VI_DEF|P_RWIN|P_MLE, + #if defined(FEAT_GUI_TABLINE) + (char_u *)&p_gtt, PV_NONE, + {(char_u *)"", (char_u *)0L} +@@ -2180,7 +2180,7 @@ static struct vimoption options[] = + {(char_u *)NULL, (char_u *)0L} + #endif + SCRIPTID_INIT}, +- {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT, ++ {"printheader", "pheader", P_STRING|P_VI_DEF|P_GETTEXT|P_MLE, + #ifdef FEAT_PRINTER + (char_u *)&p_header, PV_NONE, + /* untranslated to avoid problems when 'encoding' +-- +2.53.0 diff --git a/0001-patch-9.2.0277-tests-test_modeline.vim-fails.patch b/0001-patch-9.2.0277-tests-test_modeline.vim-fails.patch new file mode 100644 index 00000000..74cdf27e --- /dev/null +++ b/0001-patch-9.2.0277-tests-test_modeline.vim-fails.patch @@ -0,0 +1,49 @@ +diff -up vim80/runtime/doc/options.txt.modeline-tests vim80/runtime/doc/options.txt +--- vim80/runtime/doc/options.txt.modeline-tests 2018-04-24 17:10:42.000000000 +0200 ++++ vim80/runtime/doc/options.txt 2026-04-13 17:23:09.505443053 +0200 +@@ -1912,6 +1912,8 @@ A jump table for the options with a shor + based expansion (e.g., dictionary |i_CTRL-X_CTRL-K|, included patterns + |i_CTRL-X_CTRL-I|, tags |i_CTRL-X_CTRL-]| and normal expansions). + ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + *'completefunc'* *'cfu'* + 'completefunc' 'cfu' string (default: empty) + local to buffer +@@ -4002,6 +4004,7 @@ A jump table for the options with a shor + You can include a line break. Simplest method is to use |:let|: > + :let &guitabtooltip = "line one\nline two" + < ++ This option cannot be set in a modeline when 'modelineexpr' is off. + + *'helpfile'* *'hf'* + 'helpfile' 'hf' string (default (MSDOS) "$VIMRUNTIME\doc\help.txt" +@@ -5925,6 +5928,8 @@ A jump table for the options with a shor + The format of the header produced in |:hardcopy| output. + See |pheader-option|. + ++ This option cannot be set in a modeline when 'modelineexpr' is off. ++ + *'printmbcharset'* *'pmbcs'* + 'printmbcharset' 'pmbcs' string (default "") + global +diff -up vim80/src/testdir/test_modeline.vim.modeline-tests vim80/src/testdir/test_modeline.vim +--- vim80/src/testdir/test_modeline.vim.modeline-tests 2026-04-13 17:24:08.663314798 +0200 ++++ vim80/src/testdir/test_modeline.vim 2026-04-13 17:25:03.653205200 +0200 +@@ -87,13 +87,16 @@ endfunc + + func Test_modeline_fails_modelineexpr() + call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') ++ call s:modeline_fails('complete', "complete=FSomething", 'E992:') + call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') + call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') + call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') + call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') ++ call s:modeline_fails('guitabtooltip', 'guitabtooltip=Something()', 'E992:') + call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') + call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') + call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') ++ call s:modeline_fails('printheader', 'printheader=Something()', 'E992:') + call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') + call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') + call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') diff --git a/vim.spec b/vim.spec index bb55d98b..4d6187b1 100644 --- a/vim.spec +++ b/vim.spec @@ -24,7 +24,7 @@ Summary: The VIM editor URL: http://www.vim.org/ Name: vim Version: %{baseversion}.%{patchlevel} -Release: 22%{?dist}.1 +Release: 22%{?dist}.2 License: Vim and MIT Source0: ftp://ftp.vim.org/pub/vim/unix/vim-%{baseversion}-%{patchlevel}.tar.bz2 Source1: vim.sh @@ -136,6 +136,18 @@ Patch3048: 0001-patch-9.2.0089-netrw-does-not-take-port-into-account.patch # untrusted swap file before passing it to read and allocation functions Patch3049: 0001-patch-9.0.1477-crash-when-recovering-from-corrupted-.patch Patch3050: 0001-patch-9.2.0077-security-Crash-when-recovering-a-corr.patch +# RHEL-164956 CVE-2026-34982 vim: arbitrary command execution via modeline sandbox bypass +# https://redhat.atlassian.net/browse/RHEL-164956 +# first two patches include modelineexpr implementation, which is required for security fix, +# and related tests +# https://github.com/vim/vim/commit/110289e78195b6d01e1e6ad26ad450de476d41c1 +# https://github.com/vim/vim/commit/076073950c44ea0e35bc39d539dc7ab41bf9c7ec +# https://github.com/vim/vim/commit/75661a66a1db1e1f3f1245c615f13a7de44c0587 +# https://github.com/vim/vim/commit/8c8772c6b321d4955c8f09926e3eda2b4cd83680 +Patch3051: 0001-patch-8.1.1366-using-expressions-in-modeline-is-unsafe.patch +Patch3052: 0001-patch-8.1.1401-misspelled-mkspellmem.patch +Patch3053: 0001-patch-9.2.0276-security-modeline-security-bypass.patch +Patch3054: 0001-patch-9.2.0277-tests-test_modeline.vim-fails.patch # gcc is no longer in buildroot by default BuildRequires: gcc @@ -367,6 +379,10 @@ perl -pi -e "s,bin/nawk,bin/awk,g" runtime/tools/mve.awk %patch -P 3048 -p1 -b .validateportnum %patch -P 3049 -p1 -b .check-page-count %patch -P 3050 -p1 -b .CVE-2026-28421 +%patch -P 3051 -p1 -b .modelineexpr +%patch -P 3052 -p1 -b .mkspellmem-fix +%patch -P 3053 -p1 -b .modeline-bypass +%patch -P 3054 -p1 -b .modeline-tests %build %if 0%{?rhel} > 7 @@ -885,6 +901,9 @@ touch %{buildroot}/%{_datadir}/%{name}/vimfiles/doc/tags %{_datadir}/icons/locolor/*/apps/* %changelog +* Mon Apr 13 2026 Zdenek Dohnal - 2:8.0.1763-22.2 +- Resolves: RHEL-164956 vim: arbitrary command execution via modeline sandbox bypass + * Tue Mar 31 2026 Petr Dancak - 2:8.0.1763-22.1 - RHEL-159620 CVE-2026-33412 vim: Vim: Arbitrary code execution via command injection in glob() function - RHEL-155428 CVE-2026-28417 vim: Vim: Arbitrary code execution via OS command injection in the netrw plugin