168 lines
6.7 KiB
Diff
168 lines
6.7 KiB
Diff
From 816fbcc262687b81fc46f82f7bbeb1453addfe0c Mon Sep 17 00:00:00 2001
|
|
From: Christian Brabandt <cb@256bit.org>
|
|
Date: Thu, 31 Aug 2023 23:52:30 +0200
|
|
Subject: [PATCH] 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 <cb@256bit.org>
|
|
---
|
|
runtime/autoload/gzip.vim | 7 +++-
|
|
runtime/autoload/zip.vim | 4 +++
|
|
runtime/ftplugin/perl.vim | 3 +-
|
|
runtime/ftplugin/ruby.vim | 68 ++++++++++++++++++++++-----------------
|
|
4 files changed, 51 insertions(+), 31 deletions(-)
|
|
|
|
diff --git a/runtime/autoload/gzip.vim b/runtime/autoload/gzip.vim
|
|
index 95dd9067945af..ac9e37bf85e7e 100644
|
|
--- a/runtime/autoload/gzip.vim
|
|
+++ b/runtime/autoload/gzip.vim
|
|
@@ -9,12 +9,17 @@
|
|
fun s:check(cmd)
|
|
let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
|
|
if !exists("s:have_" . name)
|
|
+ " safety check, don't execute anything from the current directory
|
|
+ let f = fnamemodify(exepath(name), ":p:h") !=# getcwd()
|
|
+ if !f
|
|
+ echoerr "Warning: NOT executing " .. name .. " from current directory!"
|
|
+ endif
|
|
let e = executable(name)
|
|
if e < 0
|
|
let r = system(name . " --version")
|
|
let e = (r !~ "not found" && r != "")
|
|
endif
|
|
- exe "let s:have_" . name . "=" . e
|
|
+ exe "let s:have_" . name . "=" . (e && f)
|
|
endif
|
|
exe "return s:have_" . name
|
|
endfun
|
|
diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim
|
|
index 8dda30c418838..0331a542aca40 100644
|
|
--- a/runtime/autoload/zip.vim
|
|
+++ b/runtime/autoload/zip.vim
|
|
@@ -57,6 +57,10 @@ if !exists("g:zip_extractcmd")
|
|
let g:zip_extractcmd= g:zip_unzipcmd
|
|
endif
|
|
|
|
+if fnamemodify(exepath(g:zip_unzipcmd), ":p:h") ==# getcwd()
|
|
+ echoerr "Warning: NOT executing " .. g:zip_unzipcmd .. " from current directory!"
|
|
+ finish
|
|
+endif
|
|
" ----------------
|
|
" Functions: {{{1
|
|
" ----------------
|
|
diff --git a/runtime/ftplugin/perl.vim b/runtime/ftplugin/perl.vim
|
|
index d0bdbc0cfb158..edc7b960f12f9 100644
|
|
--- a/runtime/ftplugin/perl.vim
|
|
+++ b/runtime/ftplugin/perl.vim
|
|
@@ -54,7 +54,8 @@ endif
|
|
|
|
" Set this once, globally.
|
|
if !exists("perlpath")
|
|
- if executable("perl")
|
|
+ " safety check: don't execute perl from current directory
|
|
+ if executable("perl") && fnamemodify(exepath("perl"), ":p:h") != getcwd()
|
|
try
|
|
if &shellxquote != '"'
|
|
let perlpath = system('perl -e "print join(q/,/,@INC)"')
|
|
diff --git a/runtime/ftplugin/ruby.vim b/runtime/ftplugin/ruby.vim
|
|
index 8c1f47731c351..f4e1f60438921 100644
|
|
--- a/runtime/ftplugin/ruby.vim
|
|
+++ b/runtime/ftplugin/ruby.vim
|
|
@@ -99,41 +99,51 @@ function! s:build_path(path) abort
|
|
return path
|
|
endfunction
|
|
|
|
-if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
|
|
- let s:version_file = findfile('.ruby-version', '.;')
|
|
- if !empty(s:version_file) && filereadable(s:version_file)
|
|
- let b:ruby_version = get(readfile(s:version_file, '', 1), '')
|
|
- if !has_key(g:ruby_version_paths, b:ruby_version)
|
|
- let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
|
|
+let s:execute_ruby = 1
|
|
+" Security Check, don't execute ruby from the current directory
|
|
+if fnamemodify(exepath("ruby"), ":p:h") ==# getcwd()
|
|
+ let s:execute_ruby = 0
|
|
+endif
|
|
+
|
|
+function SetRubyPath()
|
|
+ if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
|
|
+ let s:version_file = findfile('.ruby-version', '.;')
|
|
+ if !empty(s:version_file) && filereadable(s:version_file) && s:execute_ruby
|
|
+ let b:ruby_version = get(readfile(s:version_file, '', 1), '')
|
|
+ if !has_key(g:ruby_version_paths, b:ruby_version)
|
|
+ let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
|
|
+ endif
|
|
endif
|
|
endif
|
|
-endif
|
|
|
|
-if exists("g:ruby_path")
|
|
- let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
|
|
-elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', ''))
|
|
- let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
|
|
- let s:ruby_path = s:build_path(s:ruby_paths)
|
|
-else
|
|
- if !exists('g:ruby_default_path')
|
|
- if has("ruby") && has("win32")
|
|
- ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
|
|
- elseif executable('ruby') && !empty($HOME)
|
|
- let g:ruby_default_path = s:query_path($HOME)
|
|
- else
|
|
- let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
|
|
+ if exists("g:ruby_path")
|
|
+ let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
|
|
+ elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', '')) && s:execute_ruby
|
|
+ let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
|
|
+ let s:ruby_path = s:build_path(s:ruby_paths)
|
|
+ else
|
|
+ if !exists('g:ruby_default_path')
|
|
+ if has("ruby") && has("win32")
|
|
+ ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
|
|
+ elseif executable('ruby') && !empty($HOME) && s:execute_ruby
|
|
+ let g:ruby_default_path = s:query_path($HOME)
|
|
+ else
|
|
+ let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
|
|
+ endif
|
|
endif
|
|
+ let s:ruby_paths = g:ruby_default_path
|
|
+ let s:ruby_path = s:build_path(s:ruby_paths)
|
|
endif
|
|
- let s:ruby_paths = g:ruby_default_path
|
|
- let s:ruby_path = s:build_path(s:ruby_paths)
|
|
-endif
|
|
|
|
-if stridx(&l:path, s:ruby_path) == -1
|
|
- let &l:path = s:ruby_path
|
|
-endif
|
|
-if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
|
|
- let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
|
|
-endif
|
|
+ if stridx(&l:path, s:ruby_path) == -1
|
|
+ let &l:path = s:ruby_path
|
|
+ endif
|
|
+ if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
|
|
+ let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
|
|
+ endif
|
|
+endfunction
|
|
+
|
|
+call SetRubyPath()
|
|
|
|
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
|
|
let b:browsefilter = "Ruby Source Files (*.rb)\t*.rb\n" .
|