mirror of
https://github.com/neovim/neovim.git
synced 2026-08-28 01:51:52 +00:00
vim-patch:9.2.0400: sandbox callbacks selected through 'complete' (#39452)
Problem: Modeline-tainted 'complete' values can invoke completion
callbacks outside the sandbox.
Solution: Enter the sandbox for both 'complete' callback phases and add
a regression test (Barrett Ruth)
closes: vim/vim#20078
dd9b31fb62
This commit is contained in:
@@ -3203,6 +3203,7 @@ static void expand_by_function(int type, char *base, Callback *cb)
|
||||
assert(curbuf != NULL);
|
||||
|
||||
const bool is_cpt_function = (cb != NULL);
|
||||
const bool use_sandbox = is_cpt_function && was_set_insecurely(curwin, kOptComplete, OPT_LOCAL);
|
||||
if (!is_cpt_function) {
|
||||
char *funcname = get_complete_funcname(type);
|
||||
if (*funcname == NUL) {
|
||||
@@ -3224,9 +3225,16 @@ static void expand_by_function(int type, char *base, Callback *cb)
|
||||
// switching to another window, it should not be needed and may end up in
|
||||
// Insert mode in another buffer.
|
||||
textlock++;
|
||||
if (use_sandbox) {
|
||||
sandbox++;
|
||||
}
|
||||
|
||||
// Call a function, which returns a list or dict.
|
||||
if (callback_call(cb, 2, args, &rettv)) {
|
||||
const bool called = callback_call(cb, 2, args, &rettv);
|
||||
if (use_sandbox) {
|
||||
sandbox--;
|
||||
}
|
||||
if (called) {
|
||||
switch (rettv.v_type) {
|
||||
case VAR_LIST:
|
||||
matchlist = rettv.vval.v_list;
|
||||
@@ -5796,6 +5804,7 @@ static int get_userdefined_compl_info(colnr_T curs_col, Callback *cb, int *start
|
||||
const int save_State = State;
|
||||
|
||||
const bool is_cpt_function = (cb != NULL);
|
||||
const bool use_sandbox = is_cpt_function && was_set_insecurely(curwin, kOptComplete, OPT_LOCAL);
|
||||
if (!is_cpt_function) {
|
||||
// Call 'completefunc' or 'omnifunc' or 'thesaurusfunc' and get pattern
|
||||
// length as a string
|
||||
@@ -5816,7 +5825,13 @@ static int get_userdefined_compl_info(colnr_T curs_col, Callback *cb, int *start
|
||||
|
||||
pos_T pos = curwin->w_cursor;
|
||||
textlock++;
|
||||
if (use_sandbox) {
|
||||
sandbox++;
|
||||
}
|
||||
colnr_T col = (colnr_T)callback_call_retnr(cb, 2, args);
|
||||
if (use_sandbox) {
|
||||
sandbox--;
|
||||
}
|
||||
textlock--;
|
||||
|
||||
State = save_State;
|
||||
|
||||
@@ -289,6 +289,59 @@ func Test_modeline_fails_modelineexpr()
|
||||
call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:')
|
||||
endfunc
|
||||
|
||||
func Test_modeline_complete_uses_sandbox()
|
||||
let modeline = &modeline
|
||||
let modelineexpr = &modelineexpr
|
||||
|
||||
func! ModelineCompletePwnFindstart(findstart, base)
|
||||
if a:findstart
|
||||
call writefile(['findstart'], 'Xmodeline_complete_proof')
|
||||
return 0
|
||||
endif
|
||||
return ['match']
|
||||
endfunc
|
||||
|
||||
func! ModelineCompletePwnMatches(findstart, base)
|
||||
if a:findstart
|
||||
return 0
|
||||
endif
|
||||
call writefile(['matches'], 'Xmodeline_complete_proof')
|
||||
return ['match']
|
||||
endfunc
|
||||
|
||||
try
|
||||
set modeline modelineexpr
|
||||
|
||||
call writefile([
|
||||
\ 'vim: set complete=FModelineCompletePwnFindstart :',
|
||||
\ 'body',
|
||||
\ ], 'Xmodeline_complete_attack', 'D')
|
||||
call delete('Xmodeline_complete_proof')
|
||||
edit Xmodeline_complete_attack
|
||||
call cursor(2, 1)
|
||||
call assert_fails('call feedkeys("i\<C-N>\<Esc>", "xt")', 'E48:')
|
||||
call assert_false(filereadable('Xmodeline_complete_proof'))
|
||||
bwipe!
|
||||
|
||||
call writefile([
|
||||
\ 'vim: set complete=FModelineCompletePwnMatches :',
|
||||
\ 'body',
|
||||
\ ], 'Xmodeline_complete_attack', 'D')
|
||||
call delete('Xmodeline_complete_proof')
|
||||
edit Xmodeline_complete_attack
|
||||
call cursor(2, 1)
|
||||
call assert_fails('call feedkeys("i\<C-N>\<Esc>", "xt")', 'E48:')
|
||||
call assert_false(filereadable('Xmodeline_complete_proof'))
|
||||
bwipe!
|
||||
finally
|
||||
let &modeline = modeline
|
||||
let &modelineexpr = modelineexpr
|
||||
call delete('Xmodeline_complete_proof')
|
||||
delfunc ModelineCompletePwnFindstart
|
||||
delfunc ModelineCompletePwnMatches
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func Test_modeline_setoption_verbose()
|
||||
let modeline = &modeline
|
||||
set modeline
|
||||
|
||||
Reference in New Issue
Block a user