Skip to content

Commit 816fbcc

Browse files
committed
patch 9.0.1833: [security] runtime file fixes
Problem: runtime files may execute code in current dir Solution: only execute, if not run from current directory The perl, zig and ruby filetype plugins and the zip and gzip autoload plugins may try to load malicious executable files from the current working directory. This is especially a problem on windows, where the current directory is implicitly in your $PATH and windows may even run a file with the extension `.bat` because of $PATHEXT. So make sure that we are not trying to execute a file from the current directory. If this would be the case, error out (for the zip and gzip) plugins or silently do not run those commands (for the ftplugins). This assumes, that only the current working directory is bad. For all other directories, it is assumed that those directories were intentionally set to the $PATH by the user. Signed-off-by: Christian Brabandt <[email protected]>
1 parent 0ffa97e commit 816fbcc

6 files changed

Lines changed: 56 additions & 32 deletions

File tree

runtime/autoload/gzip.vim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@
1010
fun s:check(cmd)
1111
let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
1212
if !exists("s:have_" . name)
13+
" safety check, don't execute anything from the current directory
14+
let f = fnamemodify(exepath(name), ":p:h") !=# getcwd()
15+
if !f
16+
echoerr "Warning: NOT executing " .. name .. " from current directory!"
17+
endif
1318
let e = executable(name)
1419
if e < 0
1520
let r = system(name . " --version")
1621
let e = (r !~ "not found" && r != "")
1722
endif
18-
exe "let s:have_" . name . "=" . e
23+
exe "let s:have_" . name . "=" . (e && f)
1924
endif
2025
exe "return s:have_" . name
2126
endfun

runtime/autoload/zip.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ if !exists("g:zip_extractcmd")
5757
let g:zip_extractcmd= g:zip_unzipcmd
5858
endif
5959

60+
if fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd()
61+
echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!"
62+
finish
63+
endif
6064
" ----------------
6165
" Functions: {{{1
6266
" ----------------

runtime/ftplugin/perl.vim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ endif
5454

5555
" Set this once, globally.
5656
if !exists("perlpath")
57-
if executable("perl")
57+
" safety check: don't execute perl from current directory
58+
if executable("perl") && fnamemodify(exepath("perl"), ":p:h") != getcwd()
5859
try
5960
if &shellxquote != '"'
6061
let perlpath = system('perl -e "print join(q/,/,@INC)"')

runtime/ftplugin/ruby.vim

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -99,41 +99,51 @@ function! s:build_path(path) abort
9999
return path
100100
endfunction
101101

102-
if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
103-
let s:version_file = findfile('.ruby-version', '.;')
104-
if !empty(s:version_file) && filereadable(s:version_file)
105-
let b:ruby_version = get(readfile(s:version_file, '', 1), '')
106-
if !has_key(g:ruby_version_paths, b:ruby_version)
107-
let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
102+
let s:execute_ruby = 1
103+
" Security Check, don't execute ruby from the current directory
104+
if fnamemodify(exepath("ruby"), ":p:h") ==# getcwd()
105+
let s:execute_ruby = 0
106+
endif
107+
108+
function SetRubyPath()
109+
if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
110+
let s:version_file = findfile('.ruby-version', '.;')
111+
if !empty(s:version_file) && filereadable(s:version_file) && s:execute_ruby
112+
let b:ruby_version = get(readfile(s:version_file, '', 1), '')
113+
if !has_key(g:ruby_version_paths, b:ruby_version)
114+
let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
115+
endif
108116
endif
109117
endif
110-
endif
111118

112-
if exists("g:ruby_path")
113-
let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
114-
elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', ''))
115-
let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
116-
let s:ruby_path = s:build_path(s:ruby_paths)
117-
else
118-
if !exists('g:ruby_default_path')
119-
if has("ruby") && has("win32")
120-
ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
121-
elseif executable('ruby') && !empty($HOME)
122-
let g:ruby_default_path = s:query_path($HOME)
123-
else
124-
let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
119+
if exists("g:ruby_path")
120+
let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
121+
elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', '')) && s:execute_ruby
122+
let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
123+
let s:ruby_path = s:build_path(s:ruby_paths)
124+
else
125+
if !exists('g:ruby_default_path')
126+
if has("ruby") && has("win32")
127+
ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
128+
elseif executable('ruby') && !empty($HOME) && s:execute_ruby
129+
let g:ruby_default_path = s:query_path($HOME)
130+
else
131+
let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
132+
endif
125133
endif
134+
let s:ruby_paths = g:ruby_default_path
135+
let s:ruby_path = s:build_path(s:ruby_paths)
126136
endif
127-
let s:ruby_paths = g:ruby_default_path
128-
let s:ruby_path = s:build_path(s:ruby_paths)
129-
endif
130137

131-
if stridx(&l:path, s:ruby_path) == -1
132-
let &l:path = s:ruby_path
133-
endif
134-
if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
135-
let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
136-
endif
138+
if stridx(&l:path, s:ruby_path) == -1
139+
let &l:path = s:ruby_path
140+
endif
141+
if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
142+
let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
143+
endif
144+
endfunction
145+
146+
call SetRubyPath()
137147

138148
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
139149
let b:browsefilter = "Ruby Source Files (*.rb)\t*.rb\n" .

runtime/ftplugin/zig.vim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ endif
3939

4040
let &l:define='\v(<fn>|<const>|<var>|^\s*\#\s*define)'
4141

42-
if !exists('g:zig_std_dir') && exists('*json_decode') && executable('zig')
42+
" Safety check: don't execute zip from current directory
43+
if !exists('g:zig_std_dir') && exists('*json_decode') &&
44+
\ executable('zig') && fnamemodify(exepath("zig"), ":p:h") != getcwd()
4345
silent let s:env = system('zig env')
4446
if v:shell_error == 0
4547
let g:zig_std_dir = json_decode(s:env)['std_dir']

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
1833,
702704
/**/
703705
1832,
704706
/**/

0 commit comments

Comments
 (0)