Fix CVE-2026-52858: possible code execution with python3complete
Backport fix for CVE-2026-52858 to vim on c8s. Two upstream patches are applied: - Patch 3059 (upstream 9.2.0561): Disables execution of import/from statements in python3complete.vim and pythoncomplete.vim unless g:pythoncomplete_allow_import is explicitly set by the user. - Patch 3060 (upstream 9.2.0568): Follow-up fix adding missing 'import vim' in evalsource() so the opt-in variable is actually honored. Both patches had src/version.c hunks stripped per maintainer rules. Minor conflicts in filetype.txt and test_popup.vim were resolved manually due to differences between vim 8.0 and upstream. CVE: CVE-2026-52858 Upstream patches: -4b850457e1.patch -868ad62cb8.patch Resolves: RHEL-186648 This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent. Assisted-by: Ymir
This commit is contained in:
parent
9aca0db7e7
commit
4e3ff3d4fe
141
0001-patch-9.2.0561-security-possible-code-execution-with.patch
Normal file
141
0001-patch-9.2.0561-security-possible-code-execution-with.patch
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
From d883881dfd546a59763be7bb253ac1165b6b5256 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Brabandt <cb@256bit.org>
|
||||||
|
Date: Fri, 29 May 2026 19:05:53 +0000
|
||||||
|
Subject: [PATCH] patch 9.2.0561: [security]: possible code execution with
|
||||||
|
python3complete
|
||||||
|
|
||||||
|
Problem: [security]: possible code execution with python3complete
|
||||||
|
Solution: Disable execution of import/from statements
|
||||||
|
|
||||||
|
Github Security Advisory:
|
||||||
|
https://github.com/vim/vim/security/advisories/GHSA-52mc-rq6p-rc7c
|
||||||
|
|
||||||
|
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||||
|
---
|
||||||
|
runtime/autoload/README.txt | 1 +
|
||||||
|
runtime/autoload/python3complete.vim | 13 ++++++++++---
|
||||||
|
runtime/autoload/pythoncomplete.vim | 13 ++++++++++---
|
||||||
|
runtime/doc/filetype.txt | 15 ++++++++++++++-
|
||||||
|
4 files changed, 35 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/runtime/autoload/README.txt b/runtime/autoload/README.txt
|
||||||
|
index 3b18d3d..b225819 100644
|
||||||
|
--- a/runtime/autoload/README.txt
|
||||||
|
+++ b/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)
|
||||||
|
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
|
||||||
|
index f0f3aad..5dcfb73 100644
|
||||||
|
--- a/runtime/autoload/python3complete.vim
|
||||||
|
+++ b/runtime/autoload/python3complete.vim
|
||||||
|
@@ -128,11 +128,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))
|
||||||
|
|
||||||
|
@@ -296,13 +305,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
|
||||||
|
|
||||||
|
diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim
|
||||||
|
index ecc3664..6f72b11 100644
|
||||||
|
--- a/runtime/autoload/pythoncomplete.vim
|
||||||
|
+++ b/runtime/autoload/pythoncomplete.vim
|
||||||
|
@@ -145,11 +145,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))
|
||||||
|
|
||||||
|
@@ -314,13 +323,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
|
||||||
|
|
||||||
|
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
|
||||||
|
index a5f2a1c..8ebe52a 100644
|
||||||
|
--- a/runtime/doc/filetype.txt
|
||||||
|
+++ b/runtime/doc/filetype.txt
|
||||||
|
@@ -641,7 +641,20 @@ By default the following options are set, in accordance with PEP8: >
|
||||||
|
To disable this behaviour, 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.
|
||||||
|
|
||||||
|
RPM SPEC *ft-spec-plugin*
|
||||||
|
|
||||||
|
--
|
||||||
|
2.52.0
|
||||||
|
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
From 864113433a67171b3292b9e9dc8ca0f1e4249529 Mon Sep 17 00:00:00 2001
|
||||||
|
From: thinca <thinca@gmail.com>
|
||||||
|
Date: Sun, 31 May 2026 12:33:07 +0000
|
||||||
|
Subject: [PATCH] patch 9.2.0568: pythoncomplete: g:pythoncomplete_allow_import
|
||||||
|
had no effect
|
||||||
|
|
||||||
|
Problem: The security patch 9.2.0561 added a vim.eval() call inside
|
||||||
|
Completer.evalsource() to honor g:pythoncomplete_allow_import.
|
||||||
|
But the 'vim' module is only imported inside the outer
|
||||||
|
vimcomplete() / vimpy3complete() function, not at the script's
|
||||||
|
top level, so referring to it from a Completer method raises
|
||||||
|
NameError. The surrounding bare 'except' silently swallows
|
||||||
|
the error and leaves allow_imports at 0, meaning the opt-in
|
||||||
|
never takes effect -- 'import os' (and any other
|
||||||
|
buffer-level import) is always skipped, no candidates are
|
||||||
|
produced for 'os.<...>' and
|
||||||
|
Test_popup_and_preview_autocommand() fails on the Windows
|
||||||
|
CI matrix (Linux skips the test because Python 2 is absent).
|
||||||
|
Solution: Re-import 'vim' at the top of evalsource() in both
|
||||||
|
pythoncomplete.vim and python3complete.vim so the eval reads
|
||||||
|
the global, and set g:pythoncomplete_allow_import = 1 in the
|
||||||
|
test (it is the opt-in intended for callers that trust the
|
||||||
|
buffer contents) (thinca).
|
||||||
|
|
||||||
|
closes: #20386
|
||||||
|
|
||||||
|
Signed-off-by: thinca <thinca@gmail.com>
|
||||||
|
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||||
|
---
|
||||||
|
runtime/autoload/python3complete.vim | 3 +++
|
||||||
|
runtime/autoload/pythoncomplete.vim | 3 +++
|
||||||
|
src/testdir/test_popup.vim | 4 ++++
|
||||||
|
3 files changed, 10 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
|
||||||
|
index 5dcfb73..cd8786d 100644
|
||||||
|
--- a/runtime/autoload/python3complete.vim
|
||||||
|
+++ b/runtime/autoload/python3complete.vim
|
||||||
|
@@ -127,6 +127,9 @@ class Completer(object):
|
||||||
|
self.parser = PyParser()
|
||||||
|
|
||||||
|
def evalsource(self,text,line=0):
|
||||||
|
+ # vim is imported locally in vimpy3complete(); re-import here so the
|
||||||
|
+ # vim.eval() below works (otherwise NameError, silently caught).
|
||||||
|
+ import vim
|
||||||
|
sc = self.parser.parse(text,line)
|
||||||
|
try: allow_imports = int(
|
||||||
|
vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
|
||||||
|
diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim
|
||||||
|
index 6f72b11..a4dc18c 100644
|
||||||
|
--- a/runtime/autoload/pythoncomplete.vim
|
||||||
|
+++ b/runtime/autoload/pythoncomplete.vim
|
||||||
|
@@ -144,6 +144,9 @@ class Completer(object):
|
||||||
|
self.parser = PyParser()
|
||||||
|
|
||||||
|
def evalsource(self,text,line=0):
|
||||||
|
+ # vim is imported locally in vimcomplete(); re-import here so the
|
||||||
|
+ # vim.eval() below works (otherwise NameError, silently caught).
|
||||||
|
+ import vim
|
||||||
|
sc = self.parser.parse(text,line)
|
||||||
|
try: allow_imports = int(
|
||||||
|
vim.eval("get(g:, 'pythoncomplete_allow_import', 0)"))
|
||||||
|
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
|
||||||
|
index ed31985..49ea6c6 100644
|
||||||
|
--- a/src/testdir/test_popup.vim
|
||||||
|
+++ b/src/testdir/test_popup.vim
|
||||||
|
@@ -680,6 +680,9 @@ func Test_popup_and_preview_autocommand()
|
||||||
|
au!
|
||||||
|
au BufAdd * nested tab sball
|
||||||
|
augroup END
|
||||||
|
+ " Let pythoncomplete follow the buffer's 'import os' (off by default
|
||||||
|
+ " since v9.2.0561) so 'os.' can be completed.
|
||||||
|
+ let g:pythoncomplete_allow_import = 1
|
||||||
|
set omnifunc=pythoncomplete#Complete
|
||||||
|
call setline(1, 'import os')
|
||||||
|
" make the line long
|
||||||
|
@@ -702,6 +705,7 @@ func Test_popup_and_preview_autocommand()
|
||||||
|
augroup END
|
||||||
|
augroup! MyBufAdd
|
||||||
|
bw!
|
||||||
|
+ unlet g:pythoncomplete_allow_import
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_balloon_split()
|
||||||
|
--
|
||||||
|
2.52.0
|
||||||
|
|
||||||
11
vim.spec
11
vim.spec
@ -185,6 +185,14 @@ Patch3060: 0001-patch-9.2.0496-security-Code-Injection-in-cucumber-f.patch
|
|||||||
# Adapted for vim 8.0: netrw.vim path differs, setline uses (cnt+lastline),
|
# Adapted for vim 8.0: netrw.vim path differs, setline uses (cnt+lastline),
|
||||||
# stripped src/version.c and Last Change comment, created minimal test file
|
# stripped src/version.c and Last Change comment, created minimal test file
|
||||||
Patch3061: 0001-patch-9.2.0495-security-runtime-netrw-code-injection.patch
|
Patch3061: 0001-patch-9.2.0495-security-runtime-netrw-code-injection.patch
|
||||||
|
# RHEL-186648 CVE-2026-52858 possible code execution with python3complete
|
||||||
|
# https://redhat.atlassian.net/browse/RHEL-186648
|
||||||
|
# https://github.com/vim/vim/commit/4b850457e12e1a678dd209f2868154f7553cbf8d
|
||||||
|
# stripped src/version.c hunk and omitted v0.10 changelog comments
|
||||||
|
Patch3062: 0001-patch-9.2.0561-security-possible-code-execution-with.patch
|
||||||
|
# https://github.com/vim/vim/commit/868ad62cb8bf8038322eab2badd31bd98b02b9df
|
||||||
|
# stripped src/version.c hunk
|
||||||
|
Patch3063: 0001-patch-9.2.0568-pythoncomplete-g-pythoncomplete_allow.patch
|
||||||
|
|
||||||
|
|
||||||
# gcc is no longer in buildroot by default
|
# gcc is no longer in buildroot by default
|
||||||
@ -428,6 +436,8 @@ perl -pi -e "s,bin/nawk,bin/awk,g" runtime/tools/mve.awk
|
|||||||
%patch -P 3059 -p1 -b .tar-shellescape-fix
|
%patch -P 3059 -p1 -b .tar-shellescape-fix
|
||||||
%patch -P 3060 -p1 -b .cucumber-code-injection
|
%patch -P 3060 -p1 -b .cucumber-code-injection
|
||||||
%patch -P 3061 -p1 -b .netrw-injection
|
%patch -P 3061 -p1 -b .netrw-injection
|
||||||
|
%patch -P 3062 -p1 -b .CVE-2026-52858
|
||||||
|
%patch -P 3063 -p1 -b .CVE-2026-52858-fix
|
||||||
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
@ -949,6 +959,7 @@ touch %{buildroot}/%{_datadir}/%{name}/vimfiles/doc/tags
|
|||||||
%changelog
|
%changelog
|
||||||
* Wed Jul 01 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.0.1763-27
|
* Wed Jul 01 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.0.1763-27
|
||||||
- RHEL-186656 CVE-2026-47162 vim: netrw code injection via NetrwBookHistSave
|
- RHEL-186656 CVE-2026-47162 vim: netrw code injection via NetrwBookHistSave
|
||||||
|
- RHEL-186648 CVE-2026-52858 vim: possible code execution with python3complete
|
||||||
|
|
||||||
* Tue Jun 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.0.1763-26
|
* Tue Jun 30 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:8.0.1763-26
|
||||||
- CVE-2026-47167 vim: Code Injection in cucumber filetype plugin
|
- CVE-2026-47167 vim: Code Injection in cucumber filetype plugin
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user