vim-patch:f7ac0ef50988

runtime: don't execute external commands when loading ftplugins

This is a followup to 816fbcc262687b81fc46f82f7bbeb1453addfe0c (patch
9.0.1833: [security] runtime file fixes)

It basically disables that external commands are run on loading of the
filetype plugin, **unless** the user has set the `g:plugin_exec = 1`
global variable in their configuration or for a specific filetype the
variable g:<filetype>_exec=1.

There are a few more plugins, that may execute system commands like
debchangelog, gitcommit, sh, racket, zsh, ps1 but those do at least
do not run those commands by default during loading of the filetype plugin
(there the command is mostly run as convenience for auto-completion or
to provide documentation lookup).

closes: vim/vim#13034

f7ac0ef509

Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Tim Pope <vim@tpope.org>
This commit is contained in:
Christian Clason 2023-09-06 23:50:17 +02:00
parent 5d1c1da3c9
commit ec753cf40d
6 changed files with 45 additions and 17 deletions

View File

@ -382,11 +382,24 @@ ways to change this:
3. Docs for the default filetype plugins. *ftplugin-docs*
*plugin_exec* *g:plugin_exec*
Enable executing of external commands. This was done historically for e.g.
the perl filetype plugin (and a few others) to set the search path.
Disabled by default for security reasons: >
:let g:plugin_exec = 1
It is also possible to enable this only for certain filetypes: >
:let g:<filetype>_exec = 1
So to enable this only for ruby, set the following variable: >
:let g:ruby_exec = 1
If both, the global `plugin_exec` and the `<filetype>_exec` specific variable
are set, the filetpe specific variable should have precedent.
AWK *ft-awk-plugin*
Support for features specific to GNU Awk, like @include, can be enabled by
setting: >
let g:awk_is_gawk = 1
:let g:awk_is_gawk = 1
CHANGELOG *ft-changelog-plugin*

View File

@ -37,11 +37,14 @@ if exists("g:awk_is_gawk")
let b:undo_ftplugin .= " | setl fp<"
endif
" Disabled by default for security reasons.
if get(g:, 'awk_exec', get(g:, 'plugin_exec', 0))
let path = system("gawk 'BEGIN { printf ENVIRON[\"AWKPATH\"] }'")
let path = substitute(path, '^\.\=:\|:\.\=$\|:\.\=:', ',,', 'g') " POSIX cwd
let path = substitute(path, ':', ',', 'g')
let &l:path = path
endif
let b:undo_ftplugin .= " | setl inc< path<"
endif

View File

@ -55,13 +55,19 @@ if &filetype == 'changelog'
elseif $EMAIL_ADDRESS != ""
return $EMAIL_ADDRESS
endif
let s:default_login = 'unknown'
" Disabled by default for security reasons.
if get(g:, 'changelog_exec', get(g:, 'plugin_exec', 0))
let login = s:login()
else
let login = s:default_login
endif
return printf('%s <%s@%s>', s:name(login), login, s:hostname())
endfunction
function! s:login()
return s:trimmed_system_with_default('whoami', 'unknown')
return s:trimmed_system_with_default('whoami', s:default_login)
endfunction
function! s:trimmed_system_with_default(command, default)
@ -71,7 +77,7 @@ if &filetype == 'changelog'
function! s:system_with_default(command, default)
let output = system(a:command)
if v:shell_error
return default
return a:default
endif
return output
endfunction

View File

@ -54,10 +54,12 @@ endif
" Set this once, globally.
if !exists("perlpath")
" safety check: don't execute perl from current directory
let s:tmp_cwd = getcwd()
if executable("perl") && (fnamemodify(exepath("perl"), ":p:h") != s:tmp_cwd
\ || (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) != -1 && s:tmp_cwd != '.'))
" safety check: don't execute perl binary by default
if executable("perl") && get(g:, 'perl_exec', get(g:, 'plugin_exec', 0))
\ && (fnamemodify(exepath("perl"), ":p:h") != s:tmp_cwd
\ || (index(split($PATH, has("win32") ? ';' : ':'), s:tmp_cwd) != -1
\ && s:tmp_cwd != '.'))
try
if &shellxquote != '"'
let perlpath = system('perl -e "print join(q/,/,@INC)"')
@ -73,7 +75,7 @@ if !exists("perlpath")
" current directory and the directory of the current file.
let perlpath = ".,,"
endif
unlet s:tmp_cwd
unlet! s:tmp_cwd
endif
" Append perlpath to the existing path value, if it is set. Since we don't

View File

@ -61,6 +61,10 @@ if !exists('g:ruby_version_paths')
endif
function! s:query_path(root) abort
" Disabled by default for security reasons.
if !get(g:, 'ruby_exec', get(g:, 'plugin_exec', 0))
return []
endif
let code = "print $:.join %q{,}"
if &shell =~# 'sh' && empty(&shellxquote)
let prefix = 'env PATH='.shellescape($PATH).' '
@ -84,7 +88,7 @@ function! s:query_path(root) abort
else
let path = split(system(path_check),',')
endif
unlet s:tmp_cwd
unlet! s:tmp_cwd
exe cd cwd
return path
finally

View File

@ -40,9 +40,9 @@ endif
let &l:define='\v(<fn>|<const>|<var>|^\s*\#\s*define)'
" Safety check: don't execute zip from current directory
let s:tmp_cwd = getcwd()
if !exists('g:zig_std_dir') && exists('*json_decode') &&
\ executable('zig') && (fnamemodify(exepath("zig"), ":p:h") != s:tmp_cwd
\ executable('zig') && get(g:, 'zig_exec', get(g:, 'plugin_exec', 0))
\ && (fnamemodify(exepath("zig"), ":p:h") != s:tmp_cwd
\ || (index(split($PATH,has("win32")? ';' : ':'), s:tmp_cwd) != -1 && s:tmp_cwd != '.'))
silent let s:env = system('zig env')
if v:shell_error == 0
@ -50,7 +50,7 @@ if !exists('g:zig_std_dir') && exists('*json_decode') &&
endif
unlet! s:env
endif
unlet s:tmp_cwd
unlet! s:tmp_cwd
if exists('g:zig_std_dir')
let &l:path = &l:path . ',' . g:zig_std_dir