diff options
-rw-r--r-- | src/nvim/buffer.c | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 19 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 16 | ||||
-rw-r--r-- | src/nvim/testdir/test_python2.vim | 84 | ||||
-rw-r--r-- | src/nvim/testdir/test_python3.vim | 84 |
6 files changed, 208 insertions, 2 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e333f552a8..d67783baa0 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -4943,7 +4943,12 @@ chk_modeline ( if (*s != NUL) { /* skip over an empty "::" */ save_SID = current_SID; current_SID = SID_MODELINE; + // Make sure no risky things are executed as a side effect. + sandbox++; + retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); + + sandbox--; current_SID = save_SID; if (retval == FAIL) /* stop if error found */ break; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index df677a3a13..0961e5fd92 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -241,13 +241,14 @@ typedef enum { ///< the value (prevents error message). } GetLvalFlags; -// function flags +// flags used in uf_flags #define FC_ABORT 0x01 // abort function on error #define FC_RANGE 0x02 // function accepts range #define FC_DICT 0x04 // Dict function, uses "self" #define FC_CLOSURE 0x08 // closure, uses outer scope variables #define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 #define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 +#define FC_SANDBOX 0x40 // function defined in the sandbox // The names of packages that once were loaded are remembered. static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; @@ -5853,6 +5854,9 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate) if (prof_def_func()) { func_do_profile(fp); } + if (sandbox) { + flags |= FC_SANDBOX; + } fp->uf_varargs = true; fp->uf_flags = flags; fp->uf_calls = 0; @@ -20352,6 +20356,9 @@ void ex_function(exarg_T *eap) if (prof_def_func()) func_do_profile(fp); fp->uf_varargs = varargs; + if (sandbox) { + flags |= FC_SANDBOX; + } fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ID = current_SID; @@ -21342,6 +21349,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, char_u *save_sourcing_name; linenr_T save_sourcing_lnum; scid_T save_current_SID; + bool using_sandbox = false; funccall_T *fc; int save_did_emsg; static int depth = 0; @@ -21499,6 +21507,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, save_sourcing_name = sourcing_name; save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 1; + + if (fp->uf_flags & FC_SANDBOX) { + using_sandbox = true; + sandbox++; + } + // need space for new sourcing_name: // * save_sourcing_name // * "["number"].." or "function " @@ -21659,6 +21673,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, if (do_profiling_yes) { script_prof_restore(&wait_start); } + if (using_sandbox) { + sandbox--; + } if (p_verbose >= 12 && sourcing_name != NULL) { ++no_wait_return; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 4806eff1b4..0f69d476f9 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1004,7 +1004,7 @@ return { }, { command='function', - flags=bit.bor(EXTRA, BANG, CMDWIN), + flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN), addr_type=ADDR_LINES, func='ex_function', }, diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 824baffbc9..c0faf1acdc 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1049,3 +1049,19 @@ func Test_func_range_with_edit() call delete('Xfuncrange2') bwipe! endfunc + +sandbox function Fsandbox() + normal ix +endfunc + +func Test_func_sandbox() + sandbox let F = {-> 'hello'} + call assert_equal('hello', F()) + + sandbox let F = {-> execute("normal ix\<Esc>")} + call assert_fails('call F()', 'E48:') + unlet F + + call assert_fails('call Fsandbox()', 'E48:') + delfunc Fsandbox +endfunc diff --git a/src/nvim/testdir/test_python2.vim b/src/nvim/testdir/test_python2.vim index 5ba9fd68cf..448785db6d 100644 --- a/src/nvim/testdir/test_python2.vim +++ b/src/nvim/testdir/test_python2.vim @@ -52,3 +52,87 @@ func Test_vim_function() py del f delfunc s:foo endfunc + +func _SetUpHiddenBuffer() + py import vim + new + edit hidden + setlocal bufhidden=hide + + enew + let lnum = 0 + while lnum < 10 + call append( 1, string( lnum ) ) + let lnum = lnum + 1 + endwhile + normal G + + call assert_equal( line( '.' ), 11 ) +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Clear() + call _SetUpHiddenBuffer() + py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = None + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_List() + call _SetUpHiddenBuffer() + py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = [ 'test' ] + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Str() + call _SetUpHiddenBuffer() + py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = 'test' + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine() + call _SetUpHiddenBuffer() + py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = None + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func _SetUpVisibleBuffer() + py import vim + new + let lnum = 0 + while lnum < 10 + call append( 1, string( lnum ) ) + let lnum = lnum + 1 + endwhile + normal G + call assert_equal( line( '.' ), 11 ) +endfunc + +func Test_Write_To_Current_Buffer_Fixes_Cursor_Clear() + call _SetUpVisibleBuffer() + + py vim.current.buffer[:] = None + call assert_equal( line( '.' ), 1 ) + + bwipe! +endfunc + +func Test_Write_To_Current_Buffer_Fixes_Cursor_List() + call _SetUpVisibleBuffer() + + py vim.current.buffer[:] = [ 'test' ] + call assert_equal( line( '.' ), 1 ) + + bwipe! +endfunction + +func Test_Write_To_Current_Buffer_Fixes_Cursor_Str() + call _SetUpVisibleBuffer() + + py vim.current.buffer[-1] = None + call assert_equal( line( '.' ), 10 ) + + bwipe! +endfunction diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim index 2e3fc93674..d5b1cb1b34 100644 --- a/src/nvim/testdir/test_python3.vim +++ b/src/nvim/testdir/test_python3.vim @@ -52,3 +52,87 @@ func Test_vim_function() py3 del f delfunc s:foo endfunc + +func _SetUpHiddenBuffer() + py3 import vim + new + edit hidden + setlocal bufhidden=hide + + enew + let lnum = 0 + while lnum < 10 + call append( 1, string( lnum ) ) + let lnum = lnum + 1 + endwhile + normal G + + call assert_equal( line( '.' ), 11 ) +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Clear() + call _SetUpHiddenBuffer() + py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = None + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_List() + call _SetUpHiddenBuffer() + py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = [ 'test' ] + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Str() + call _SetUpHiddenBuffer() + py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = 'test' + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine() + call _SetUpHiddenBuffer() + py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = None + call assert_equal( line( '.' ), 11 ) + bwipe! +endfunc + +func _SetUpVisibleBuffer() + py3 import vim + new + let lnum = 0 + while lnum < 10 + call append( 1, string( lnum ) ) + let lnum = lnum + 1 + endwhile + normal G + call assert_equal( line( '.' ), 11 ) +endfunc + +func Test_Write_To_Current_Buffer_Fixes_Cursor_Clear() + call _SetUpVisibleBuffer() + + py3 vim.current.buffer[:] = None + call assert_equal( line( '.' ), 1 ) + + bwipe! +endfunc + +func Test_Write_To_Current_Buffer_Fixes_Cursor_List() + call _SetUpVisibleBuffer() + + py3 vim.current.buffer[:] = [ 'test' ] + call assert_equal( line( '.' ), 1 ) + + bwipe! +endfunction + +func Test_Write_To_Current_Buffer_Fixes_Cursor_Str() + call _SetUpVisibleBuffer() + + py3 vim.current.buffer[-1] = None + call assert_equal( line( '.' ), 10 ) + + bwipe! +endfunction |