]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1164: [security]: code execution with tar.vim and special crafted tar files v9.1.1164
authorChristian Brabandt <cb@256bit.org>
Sun, 2 Mar 2025 18:33:51 +0000 (19:33 +0100)
committerChristian Brabandt <cb@256bit.org>
Sun, 2 Mar 2025 18:37:29 +0000 (19:37 +0100)
Problem:  editing a special crafted tar file allows code execution
          (RyotaK, after 129a8446d23cd9cb4445fcfea259cba5e0487d29)
Solution: escape the filename before feeding it to the `:read` command

Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-wfmf-8626-q3r3

Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/autoload/tar.vim
src/version.c

index 1c2ed78c1907b4256d54839e196b4f369e6e89c8..14e68b7899c728b4ac93dda9ddcb430e403f8c9f 100644 (file)
@@ -11,6 +11,7 @@
 "   2025 Feb 06 by Vim Project: add support for lz4 (#16591)
 "   2025 Feb 28 by Vim Project: add support for bzip3 (#16755)
 "   2025 Mar 01 by Vim Project: fix syntax error in tar#Read()
+"   2025 Mar 02 by Vim Project: escape the filename before using :read
 "
 "      Contains many ideas from Michael Toren's <tar.vim>
 "
@@ -284,6 +285,8 @@ fun! tar#Read(fname,mode)
   set report=10
   let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
   let fname   = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
+  " be careful not to execute special crafted files
+  let escape_file = fname->fnameescape()
 
   " changing the directory to the temporary earlier to allow tar to extract the file with permissions intact
   if !exists("*mkdir")
@@ -361,13 +364,13 @@ fun! tar#Read(fname,mode)
 
   if tarfile =~# '\.bz2$'
    exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\.bz3$'
    exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\.\(gz\)$'
    exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)'
    if has("unix") && executable("file")
     let filekind= system("file ".shellescape(tarfile,1))
@@ -376,40 +379,40 @@ fun! tar#Read(fname,mode)
    endif
    if filekind =~ "bzip2"
     exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-    exe "read ".fname
+    exe "read ".escape_file
    elseif filekind =~ "bzip3"
     exe "sil! r! bzip3 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-    exe "read ".fname
+    exe "read ".escape_file
    elseif filekind =~ "XZ"
     exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-    exe "read ".fname
+    exe "read ".escape_file
    elseif filekind =~ "Zstandard"
     exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-    exe "read ".fname
+    exe "read ".escape_file
    else
     exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-    exe "read ".fname
+    exe "read ".escape_file
    endif
 
   elseif tarfile =~# '\.lrp$'
    exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\.lzma$'
    exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\.\(xz\|txz\)$'
    exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   elseif tarfile =~# '\.\(lz4\|tlz4\)$'
    exe "sil! r! lz4 --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   else
    if tarfile =~ '^\s*-'
     " A file name starting with a dash is taken as an option.  Prepend ./ to avoid that.
     let tarfile = substitute(tarfile, '-', './-', '')
    endif
    exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp
-   exe "read ".fname
+   exe "read ".escape_file
   endif
 
    redraw!
index 25c29256c82955a0d92c1ec813106f2749f4312d..6fd80d6b125d9d72e41c51637bdeaa4d7a786551 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1164,
 /**/
     1163,
 /**/