diff mbox series

[wrynose,1/3] vim: Fix for CVE-2026-73076

Message ID 20260901122727.85327-1-hprajapati@mvista.com
State New
Delegated to: Yoann Congal
Headers show
Series [wrynose,1/3] vim: Fix for CVE-2026-73076 | expand

Commit Message

Hitendra Prajapati Sept. 1, 2026, 12:27 p.m. UTC
Pick the patch from [1], also referenced in the NVD report [2].

[1] https://github.com/vim/vim/commit/581a2f3ac9c6f96a26324f6b2c8c11415fd0d452
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-73076

Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
 .../vim/files/CVE-2026-73076.patch            | 167 ++++++++++++++++++
 meta/recipes-support/vim/vim.inc              |   1 +
 2 files changed, 168 insertions(+)
 create mode 100644 meta/recipes-support/vim/files/CVE-2026-73076.patch
diff mbox series

Patch

diff --git a/meta/recipes-support/vim/files/CVE-2026-73076.patch b/meta/recipes-support/vim/files/CVE-2026-73076.patch
new file mode 100644
index 0000000000..5f5c92b168
--- /dev/null
+++ b/meta/recipes-support/vim/files/CVE-2026-73076.patch
@@ -0,0 +1,167 @@ 
+From 581a2f3ac9c6f96a26324f6b2c8c11415fd0d452 Mon Sep 17 00:00:00 2001
+From: Christian Brabandt <cb@256bit.org>
+Date: Fri, 24 Jul 2026 17:43:51 +0200
+Subject: [PATCH] patch 9.2.0847: [security]: vimball: code execution via
+ .VimballRecord file
+
+Problem:  [security]: vimball: code execution via .VimballRecord file
+          (tdjackey)
+Solution: Forbid arbitrary commands, fix broken directory deletion code,
+          refactor code
+
+Github Security Advisory:
+https://github.com/vim/vim/security/advisories/GHSA-r22p-fhw4-84p2
+
+Signed-off-by: Christian Brabandt <cb@256bit.org>
+
+CVE: CVE-2026-73076
+Upstream-Status: Backport [https://github.com/vim/vim/commit/581a2f3ac9c6f96a26324f6b2c8c11415fd0d452]
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ runtime/autoload/vimball.vim        | 50 ++++++++++++++++++++---------
+ src/testdir/test_plugin_vimball.vim | 16 ++++++++-
+ 2 files changed, 50 insertions(+), 16 deletions(-)
+
+diff --git a/runtime/autoload/vimball.vim b/runtime/autoload/vimball.vim
+index d661ded631..20ce55cd69 100644
+--- a/runtime/autoload/vimball.vim
++++ b/runtime/autoload/vimball.vim
+@@ -20,9 +20,9 @@ if &cp || exists("g:loaded_vimball")
+  finish
+ endif
+ let g:loaded_vimball = "v37"
+-if v:version < 704
++if v:version < 900
+  echohl WarningMsg
+- echo "***warning*** this version of vimball needs vim 7.4"
++ echo "***warning*** this version of vimball needs vim 9.0"
+  echohl Normal
+  finish
+ endif
+@@ -237,6 +237,12 @@ fun! vimball#Vimball(really,...)
+      bw! Vimball
+      call s:ChgDir(curdir)
+      return
++   elseif fname =~? '\%(^\|/\)\.VimballRecord$'
++     echomsg "(Vimball) Forbidding .VimballRecord filename, aborting..."
++     exe "tabn ".curtabnr
++     bw! Vimball
++     call s:ChgDir(curdir)
++     return
+    endif
+ 
+    if a:really
+@@ -264,7 +270,7 @@ fun! vimball#Vimball(really,...)
+      let fnamebuf = substitute(fnamebuf,'^.\{-}/\(.*\)$','\1','')
+      if !isdirectory(dirname)
+       call mkdir(dirname)
+-      call s:RecordInVar(home,"rmdir('".dirname."')")
++      call s:RecordDirInVar(dirname)
+      endif
+     endwhile
+    endif
+@@ -295,7 +301,7 @@ fun! vimball#Vimball(really,...)
+       exe "silent w! ".fnameescape(fnamepath)
+     endif
+     echo "wrote ".fnameescape(fnamepath)
+-    call s:RecordInVar(home,"call delete('".fnamepath."')")
++    call s:RecordInVar(fnamepath)
+     endif
+ 
+     " return to tab with vimball
+@@ -394,10 +400,17 @@ fun! vimball#RmVimball(...)
+     endif
+     let s:VBRstring= substitute(exestring,'call delete(','','g')
+     let s:VBRstring= substitute(s:VBRstring,"[')]",'','g')
+-    sil! keepalt keepjumps exe exestring
++    let nr_files= 0
++    for line in split(exestring, '|')
++      if line !~ '^call delete(''[^'']\{-}''\(,"d"\)\?)$'
++        echomsg "ignoring .VimballRecord entry: " line
++      else
++        sil! keepalt keepjumps exe line
++        let nr_files+= 1
++      endif
++    endfor
+     sil! keepalt keepjumps d
+-    let exestring= strlen(substitute(exestring,'call delete(.\{-})|\=',"D","g"))
+-    echomsg "removed ".exestring." files"
++    echomsg "removed ".nr_files." files"
+    else
+     let s:VBRstring= ''
+     let curfile    = substitute(curfile,'\.vmb','','')
+@@ -539,13 +552,20 @@ fun! s:ChgDir(newdir)
+ endfun
+ 
+ " ---------------------------------------------------------------------
+-" s:RecordInVar: record a un-vimball command in the .VimballRecord file {{{2
+-fun! s:RecordInVar(home,cmd)
++" s:RecordInVar: record a un-vimball file deletion in the .VimballRecord file {{{2
++fun! s:RecordInVar(file)
+   if !exists("s:recordfile")
+-   let s:recordfile= a:cmd
+-  else
+-   let s:recordfile= s:recordfile."|".a:cmd
++    let s:recordfile=[]
++  endif
++  call add(s:recordfile, $'call delete({string(a:file)})')
++endfun
++
++" s:RecordDirInVar: record a un-vimball dir deletion in the .VimballRecord file {{{2
++fun! s:RecordDirInVar(dir)
++  if !exists("s:recorddir")
++    let s:recorddir = []
+   endif
++  call add(s:recorddir, $'call delete({string(a:dir)},"d")')
+ endfun
+ 
+ " ---------------------------------------------------------------------
+@@ -566,11 +586,11 @@ fun! s:RecordInFile(home)
+    setlocal ma
+    $
+    if exists("s:recordfile") && exists("s:recorddir")
+-    let cmd= cmd.s:recordfile."|".s:recorddir
++    let cmd= cmd.join(s:recordfile, '|')."|".join(s:recorddir, '|')
+    elseif exists("s:recorddir")
+-    let cmd= cmd.s:recorddir
++    let cmd= cmd.join(s:recorddir, '|')
+    elseif exists("s:recordfile")
+-    let cmd= cmd.s:recordfile
++    let cmd= cmd.join(s:recordfile, '|')
+    else
+     return
+    endif
+diff --git a/src/testdir/test_plugin_vimball.vim b/src/testdir/test_plugin_vimball.vim
+index 2d5b4ba768..8025846694 100644
+--- a/src/testdir/test_plugin_vimball.vim
++++ b/src/testdir/test_plugin_vimball.vim
+@@ -65,7 +65,7 @@ func Test_vimball_basic()
+   call assert_true(filereadable('.VimballRecord'))
+   let record = readfile('.VimballRecord')
+   call assert_equal(1, record->len())
+-  call assert_match('^Xtest.vmb: rmdir.*call delete(', record[0])
++  call assert_match('^Xtest.vmb: call delete(''.\{-}'')|call delete(''.\{-}'',"d")$', record[0])
+   call s:teardown()
+ endfunc
+ 
+@@ -83,3 +83,17 @@ func Test_vimball_path_traversal()
+   call assert_false(filereadable('../XVimball/Xtest.txt'))
+   call s:teardown()
+ endfunc
++
++func Test_vimball_VimballRecord_filenames()
++  call s:Mkvimball()
++  call delete('XVimball', 'rf')
++  sp Xtest.vmb
++  4s#.*\ze\t#.VimballRecord#
++  so %
++  call feedkeys("\<cr>", "it")
++
++  let mess = execute(':mess')->split('\n')[-1]
++  call assert_match('(Vimball) Forbidding .VimballRecord filename.* aborting\.\.\.', mess)
++  call assert_false(filereadable('.VimballRecord'))
++  call s:teardown()
++endfunc
+-- 
+2.34.1
+
diff --git a/meta/recipes-support/vim/vim.inc b/meta/recipes-support/vim/vim.inc
index 9dda2c0be5..f0524ba730 100644
--- a/meta/recipes-support/vim/vim.inc
+++ b/meta/recipes-support/vim/vim.inc
@@ -42,6 +42,7 @@  SRC_URI = "git://github.com/vim/vim.git;branch=master;protocol=https;tag=v${PV}
            file://CVE-2026-73072.patch \
            file://CVE-2026-73073.patch \
            file://CVE-2026-73074.patch \
+           file://CVE-2026-73076.patch \
            "
 
 PV .= ".0340"