Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
vim (2:9.2.0461-1deepin2) unstable; urgency=medium

* Fix CVE-2026-47162: Code injection in netrw NetrwBookHistSave function
- Properly quote directory names using string() to prevent injection
* Fix CVE-2026-47167: Code injection in cucumber filetype plugin
- Use Ruby Regexp.new() with untrusted pattern to prevent injection
* Fix memory safety issues in spellfile.c
- Add recursion limit to read_tree_node(), add length limit check
in tree_count_words(), use alloc_clear() in spell_read_tree()
* Fix CVE-2026-52858: possible code execution with python3complete
- Disable execution of import/from statements
* Fix CVE-2026-52860: possible code execution with python complete
- Strip default expressions and annotations from generated source
* Fix out-of-bounds read in update_snapshot()
- Bound the loop with i < VTERM_MAX_CHARS_PER_CELL to prevent
reading past array bounds
* Fix shellescape() calls in getscript/vimball/rust
- Pass 1 as second argument to shellescape() in :! command contexts
to prevent potential command injection
* Fix unbounded strcat/strcpy in ccfilter.c
- Replace strcat()/strcpy() with snprintf() bounded by LINELENGTH
to prevent buffer overflow

-- deepin-ci-robot <packages@deepin.org> Thu, 11 Jun 2026 22:41:37 +0800

vim (2:9.2.0461-1deepin1) unstable; urgency=medium

* Set-NoDisplay-true-for-vim-desktop.patch
Expand Down
51 changes: 51 additions & 0 deletions debian/patches/CVE-2026-47162-netrw-book-history-injection.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Index: vim/runtime/pack/dist/opt/netrw/autoload/netrw.vim
===================================================================
--- vim.orig/runtime/pack/dist/opt/netrw/autoload/netrw.vim
+++ vim/runtime/pack/dist/opt/netrw/autoload/netrw.vim
@@ -1,7 +1,7 @@
" Creator: Charles E Campbell
" Previous Maintainer: Luca Saccarola <github.e41mv@aleeas.com>
" Maintainer: This runtime file is looking for a new maintainer.
-" Last Change: 2026 May 14
+" Last Change: 2026 May 17
" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
@@ -2935,7 +2935,7 @@ function s:NetrwBookHistSave()
while ( first || cnt != g:netrw_dirhistcnt )
let lastline= lastline + 1
if exists("g:netrw_dirhist_{cnt}")
- call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'")
+ call setline(lastline,'let g:netrw_dirhist_'.cnt.'='.string(g:netrw_dirhist_{cnt}))
endif
let first = 0
let cnt = ( cnt - 1 ) % g:netrw_dirhistmax
Index: vim/src/testdir/test_plugin_netrw.vim
===================================================================
--- vim.orig/src/testdir/test_plugin_netrw.vim
+++ vim/src/testdir/test_plugin_netrw.vim
@@ -760,4 +760,24 @@ function Test_netrw_NetrwMaps_CR_dirname()
unlet! g:netrw_pwn
bw!
endfunction
+
+func Test_netrw_injection()
+ let g:netrw_home = getcwd()
+ let savefile = g:netrw_home . '/.netrwhist'
+ let g:netrw_dirhistmax = 10
+ let g:netrw_dirhistcnt = 1
+ let g:netrw_dirhist_1 = "x'|let g:injected = 1|let y='z"
+ call delete(savefile)
+ try
+ call netrw#Call('NetrwBookHistSave')
+ call assert_true(filereadable(savefile), savefile . ' must be written')
+ unlet g:netrw_dirhist_1
+ execute 'source ' . fnameescape(savefile)
+ call assert_false(exists("g:injected"), 'injected statement must not execute')
+ call assert_equal("x'|let g:injected = 1|let y='z", g:netrw_dirhist_1, 'dirname must round-trip')
+ finally
+ call delete(savefile)
+ unlet! g:netrw_home g:netrw_dirhistmax g:netrw_dirhistcnt g:netrw_dirhist_1 g:injected
+ endtry
+endfunc
" vim:ts=8 sts=2 sw=2 et
62 changes: 62 additions & 0 deletions debian/patches/CVE-2026-47167-cucumber-code-injection.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
Index: vim/runtime/ftplugin/cucumber.vim
===================================================================
--- vim.orig/runtime/ftplugin/cucumber.vim
+++ vim/runtime/ftplugin/cucumber.vim
@@ -2,6 +2,8 @@
" Language: Cucumber
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Last Change: 2016 Aug 29
+" 2026 May 26 by Vim Project: prevent Code Injection
+" https://github.com/vim/vim/security/advisories/GHSA-4473-94jm-w5x9

" Only do this when not done yet for this buffer
if (exists("b:did_ftplugin"))
@@ -96,7 +98,8 @@ function! s:stepmatch(receiver,target)
catch
endtry
if has("ruby") && pattern !~ '\\\@<!#{'
- ruby VIM.command("return #{if (begin; Kernel.eval('/'+VIM.evaluate('pattern')+'/'); rescue SyntaxError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
+ " Use Regexp.new, so the pattern stays untrusted data and cannot inject Ruby
+ ruby VIM.command("return #{if (begin; Regexp.new(VIM.evaluate('pattern')); rescue RegexpError; end) === VIM.evaluate('a:target') then 1 else 0 end}")
else
return 0
endif
Index: vim/src/testdir/test_filetype.vim
===================================================================
--- vim.orig/src/testdir/test_filetype.vim
+++ vim/src/testdir/test_filetype.vim
@@ -3477,4 +3477,34 @@ func Test_app_file()
filetype off
endfunc

+func Test_cucumber_code_injection()
+ CheckFeature ruby
+ filetype plugin on
+
+ call mkdir('Xcucu/features/step_definitions', 'pR')
+ call writefile([
+ \ 'Feature: demo',
+ \ ' Scenario: trigger',
+ \ ' Given xyzzy',
+ \ ], 'Xcucu/features/test.feature')
+ let marker = getcwd() . '/Xcucu/MARKER'
+ " Malicious step: terminates the regex literal, injects Ruby system(),
+ " comments the trailing slash. With the fix, the pattern is passed to
+ " Regexp.new() instead of Kernel.eval() and the payload is inert.
+ call writefile([
+ \ 'Given /xyzzy/; system("touch ' . marker . '"); #/ do',
+ \ 'end',
+ \ ], 'Xcucu/features/step_definitions/poc.rb')
+
+ new Xcucu/features/test.feature
+ call assert_equal('cucumber', &filetype)
+ call cursor(3, 1)
+ " Triggers s:jump -> s:steps -> s:stepmatch on every discovered step,
+ " including the malicious one. Suppress preview and error messages.
+ silent! normal [d
+ call assert_false(filereadable(marker), 'Ruby injection executed')
+ bwipe!
+ filetype plugin off
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
140 changes: 140 additions & 0 deletions debian/patches/CVE-2026-52858-python3complete-code-execution.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
Index: vim/runtime/autoload/README.txt
===================================================================
--- vim.orig/runtime/autoload/README.txt
+++ vim/runtime/autoload/README.txt
@@ -17,6 +17,7 @@ htmlcomplete.vim HTML
javascriptcomplete.vim Javascript
phpcomplete.vim PHP
pythoncomplete.vim Python
+python3complete.vim Python
rubycomplete.vim Ruby
syntaxcomplete.vim from syntax highlighting
xmlcomplete.vim XML (uses files in the xml directory)
Index: vim/runtime/autoload/python3complete.vim
===================================================================
--- vim.orig/runtime/autoload/python3complete.vim
+++ vim/runtime/autoload/python3complete.vim
@@ -14,6 +14,10 @@
" i.e. "import url<c-x,c-o>"
" Continue parsing on invalid line??
"
+" v 0.10 by Vim project
+" * disables importing local modules, unless the global Vim variable
+" g:pythoncomplete_allow_import is set to non-zero
+"
" v 0.9
" * Fixed docstring parsing for classes and functions
" * Fixed parsing of *args and **kwargs type arguments
@@ -132,11 +136,20 @@ class Completer(object):

def evalsource(self,text,line=0):
sc = self.parser.parse(text,line)
+ try: allow_imports = int(
+ vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
+ except Exception:
+ allow_imports = 0
src = sc.get_code()
dbg("source: %s" % src)
try: exec(src,self.compldict)
except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
for l in sc.locals:
+ # Executing import/from statements harvested from the buffer runs
+ # arbitrary package code; only do so when the user opted in.
+ if not allow_imports and (l.startswith('import')
+ or l.startswith('from ')):
+ continue
try: exec(l,self.compldict)
except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))

@@ -300,13 +313,11 @@ class Scope(object):
def get_code(self):
str = ""
if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n'
- for l in self.locals:
- if l.startswith('import'): str += l+'\n'
str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
for sub in self.subscopes:
str += sub.get_code()
for l in self.locals:
- if not l.startswith('import'): str += l+'\n'
+ if not l.startswith('import') and not l.startswith('from '): str += l+'\n'

return str

Index: vim/runtime/autoload/pythoncomplete.vim
===================================================================
--- vim.orig/runtime/autoload/pythoncomplete.vim
+++ vim/runtime/autoload/pythoncomplete.vim
@@ -12,6 +12,10 @@
" i.e. "import url<c-x,c-o>"
" Continue parsing on invalid line??
"
+" v 0.10 by Vim project
+" * disables importing local modules, unless the global Vim variable
+" g:pythoncomplete_allow_import is set to non-zero
+"
" v 0.9
" * Fixed docstring parsing for classes and functions
" * Fixed parsing of *args and **kwargs type arguments
@@ -146,11 +150,20 @@ class Completer(object):

def evalsource(self,text,line=0):
sc = self.parser.parse(text,line)
+ try: allow_imports = int(
+ vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
+ except Exception:
+ allow_imports = 0
src = sc.get_code()
dbg("source: %s" % src)
try: exec(src) in self.compldict
except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
for l in sc.locals:
+ # Executing import/from statements harvested from the buffer runs
+ # arbitrary package code; only do so when the user opted in.
+ if not allow_imports and (l.startswith('import')
+ or l.startswith('from ')):
+ continue
try: exec(l) in self.compldict
except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))

@@ -315,13 +328,11 @@ class Scope(object):
def get_code(self):
str = ""
if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n'
- for l in self.locals:
- if l.startswith('import'): str += l+'\n'
str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
for sub in self.subscopes:
str += sub.get_code()
for l in self.locals:
- if not l.startswith('import'): str += l+'\n'
+ if not l.startswith('import') and not l.startswith('from '): str += l+'\n'

return str

Index: vim/runtime/doc/filetype.txt
===================================================================
--- vim.orig/runtime/doc/filetype.txt
+++ vim/runtime/doc/filetype.txt
@@ -976,7 +976,20 @@ By default the following options are set, in accordance with PEP8: >
To disable this behavior, set the following variable in your vimrc: >

let g:python_recommended_style = 0
-
+<
+Python omni-completion |compl-omni| is provided by python3complete.vim (or
+pythoncomplete.vim) for Vim builds with the |+python|/|+python3| interpreter.
+By default it does not inspect the import / from statements found in the
+buffer. This means completion of names defined in the buffer itself (classes,
+functions, variables) works, but completion of members of imported modules is
+not offered.
+
+To enable completion of imported module members, set: >
+ let g:pythoncomplete_allow_import = 1
+<
+WARNING: enabling this causes omni-completion to execute the import statements
+found in the buffer through Python's import machinery, which runs the imported
+modules' top-level code. Only enable this for code you trust.

QF QUICKFIX *qf.vim* *ft-qf-plugin*

Loading
Loading