vim-patch:9.2.0276: [security]: modeline security bypass (#38657)

Problem:  [security]: modeline security bypass
Solution: disallow mapset() from secure mode, 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

75661a66a1

Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit c7604323e3)
This commit is contained in:
zeertzjq
2026-04-01 08:00:33 +08:00
committed by github-actions[bot]
parent dd85c13382
commit c084ab9f57
3 changed files with 32 additions and 0 deletions

View File

@@ -26,6 +26,7 @@
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_session.h"
#include "nvim/fuzzy.h"
@@ -2277,6 +2278,10 @@ static int get_map_mode_string(const char *const mode_string, const bool abbr)
/// "mapset()" function
void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
}
const char *which;
char buf[NUMBUFLEN];
int is_abbr;

View File

@@ -1545,6 +1545,7 @@ local options = {
(CTRL-N) and is ignored during backward completion (CTRL-P).
]=],
full_name = 'complete',
modelineexpr = true,
list = 'onecomma',
scope = { 'buf' },
short_desc = N_('specify how Insert mode completion works'),
@@ -4256,6 +4257,7 @@ local options = {
<
]=],
full_name = 'guitabtooltip',
modelineexpr = true,
redraw = { 'current_window' },
scope = { 'global' },
short_desc = N_('GUI: custom tooltip for a tab page'),

View File

@@ -503,4 +503,29 @@ func Test_modeline_nowrap_lcs_extends()
set equalalways&
endfunc
func Test_modeline_forbidden()
let tempfile = tempname()
let lines =<< trim END
some test text for completion
vim: set complete=F{->system('touch_should_not_run')} :
END
call writefile(lines, tempfile, 'D')
call assert_fails($'new {tempfile}', 'E992:')
bw!
let lines =<< trim END
some text
vim: set guitabtooltip=%{%mapset()%}:
END
call writefile(lines, tempfile)
call assert_fails($'new {tempfile}', 'E992:')
bw!
let lines =<< trim END
some text
vim: set printheader=%{mapset('n',0,{})%)%}:
END
call writefile(lines, tempfile, 'D')
"call assert_fails($'new {tempfile}', 'E992:')
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab