From ba1ed1514599e33ccf012c808e23cdca0a32e3aa Mon Sep 17 00:00:00 2001 From: RHEL Packaging Agent Date: Wed, 29 Jul 2026 12:36:33 +0000 Subject: [PATCH] Fix CVE-2026-59858: arbitrary Ex command execution in C omni-completion Backport upstream patch fixing CVE-2026-59858, where a crafted tags file could execute arbitrary Ex commands during C omni-completion (struct/union member completion via ccomplete.vim). Patch 1 (upstream 6b611b0d) escapes the typeref field with escape(typename, '/\') before interpolating it into the :vimgrep pattern. Patch is adapted to the legacy Vimscript style used in the RHEL 8.2 codebase. A new test file test_plugin_ccomplete.vim is added covering both injection vectors and normal typeref completion. CVE: CVE-2026-59858 Upstream patches: - https://github.com/vim/vim/commit/6b611b0d15603c52ebdad17172b0232b4f65704e.patch Resolves: RHEL-203984 This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent. Assisted-by: Ymir --- ...ecurity-arbitrary-Ex-command-executi.patch | 127 ++++++++++++++++++ vim.spec | 12 +- 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 0001-patch-9.2.0735-security-arbitrary-Ex-command-executi.patch diff --git a/0001-patch-9.2.0735-security-arbitrary-Ex-command-executi.patch b/0001-patch-9.2.0735-security-arbitrary-Ex-command-executi.patch new file mode 100644 index 00000000..6a468093 --- /dev/null +++ b/0001-patch-9.2.0735-security-arbitrary-Ex-command-executi.patch @@ -0,0 +1,127 @@ +From a3304c9e3252a9e74bb114d5f72bd4df35017229 Mon Sep 17 00:00:00 2001 +From: Hirohito Higashi +Date: Fri, 26 Jun 2026 15:41:24 +0900 +Subject: [PATCH] patch 9.2.0735: [security]: arbitrary Ex command execution + during C omni-completion + +Problem: [security]: With C omni-completion, a crafted tags file can execute + arbitrary Ex commands when completing a struct/union member + (cipher-creator) +Solution: Escape the type field before inserting it into the :vimgrep + pattern so it cannot close the pattern and start a new command + (Hirohito Higashi). + +Github Security Advisory: +https://github.com/vim/vim/security/advisories/GHSA-mf92-v4xw-j45x + +Co-Authored-By: Claude Opus 4.8 (1M context) " +Signed-off-by: Hirohito Higashi +Signed-off-by: Christian Brabandt +--- + runtime/autoload/ccomplete.vim | 2 +- + src/testdir/Make_all.mak | 2 + + src/testdir/test_plugin_ccomplete.vim | 62 +++++++++++++++++++++++++++ + 3 files changed, 65 insertions(+), 1 deletion(-) + create mode 100644 src/testdir/test_plugin_ccomplete.vim + +diff --git a/runtime/autoload/ccomplete.vim b/runtime/autoload/ccomplete.vim +index 95a20e16b..ae1fcf7d6 100644 +--- a/runtime/autoload/ccomplete.vim ++++ b/runtime/autoload/ccomplete.vim +@@ -514,7 +514,7 @@ func s:StructMembers(typename, items, all) + endif + if !cached + while 1 +- exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames ++ exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . escape(typename, '/\') . '\(\t\|$\)/j ' . fnames + + let qflist = getqflist() + if len(qflist) > 0 || match(typename, "::") < 0 +diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak +index 7fd4e89a2..2430bc78c 100644 +--- a/src/testdir/Make_all.mak ++++ b/src/testdir/Make_all.mak +@@ -209,6 +209,7 @@ NEW_TESTS = \ + test_partial \ + test_paste \ + test_perl \ ++ test_plugin_ccomplete \ + test_plugin_tar \ + test_plus_arg_edit \ + test_popup \ +@@ -448,6 +449,7 @@ NEW_TESTS_RES = \ + test_partial.res \ + test_paste.res \ + test_perl.res \ ++ test_plugin_ccomplete.res \ + test_plugin_tar.res \ + test_plus_arg_edit.res \ + test_popup.res \ +diff --git a/src/testdir/test_plugin_ccomplete.vim b/src/testdir/test_plugin_ccomplete.vim +new file mode 100644 +index 000000000..a635bd50b +--- /dev/null ++++ b/src/testdir/test_plugin_ccomplete.vim +@@ -0,0 +1,62 @@ ++" Tests for the C omni-completion plugin (runtime/autoload/ccomplete.vim). ++ ++func s:WriteTags(lines) ++ " Mark unsorted so lookup is a linear scan regardless of entry order. ++ let tagsfile = tempname() ++ call writefile(["!_TAG_FILE_SORTED\t0\t/0/"] + a:lines, tagsfile) ++ return tagsfile ++endfunc ++ ++" A crafted typeref field is interpolated into the :vimgrep pattern in ++" StructMembers(). Without escaping, "/" closes the pattern and "|" starts a ++" new Ex command, so the field runs as an Ex command during completion. ++func Test_ccomplete_no_exec_via_typeref() ++ unlet! g:ccomplete_injected ++ let tagsfile = s:WriteTags([ ++ \ "myvar\tmain.c\t/^x$/;\"\tv\ttyperef:x/|let g:ccomplete_injected = 1|\"", ++ \ ]) ++ ++ let save_tags = &tags ++ let &tags = tagsfile ++ ++ new ++ call ccomplete#Complete(1, '') ++ call ccomplete#Complete(0, 'myvar.x') ++ ++ call assert_false(exists('g:ccomplete_injected'), ++ \ 'typeref field was executed as an Ex command during omni-completion') ++ ++ bwipe! ++ let &tags = save_tags ++ unlet! g:ccomplete_injected ++endfunc ++ ++" A legitimate typeref must still drive struct-member completion: escaping the ++" field value must not break the normal path. ++func Test_ccomplete_typeref_completion_still_works() ++ let tagsfile = s:WriteTags([ ++ \ "myvar\tmain.c\t/^x$/;\"\tv\ttyperef:struct:mystruct", ++ \ "alpha\tmain.c\t/^x$/;\"\tm\tstruct:mystruct", ++ \ "beta\tmain.c\t/^x$/;\"\tm\tstruct:mystruct", ++ \ ]) ++ ++ let save_tags = &tags ++ let &tags = tagsfile ++ ++ new ++ call ccomplete#Complete(1, '') ++ let items = ccomplete#Complete(0, 'myvar.') ++ ++ call assert_equal(type([]), type(items), ++ \ 'ccomplete#Complete did not return a list') ++ let names = map(copy(items), 'v:val.word') ++ call assert_true(index(names, 'alpha') >= 0, ++ \ 'struct member "alpha" missing from completion: ' . string(names)) ++ call assert_true(index(names, 'beta') >= 0, ++ \ 'struct member "beta" missing from completion: ' . string(names)) ++ ++ bwipe! ++ let &tags = save_tags ++endfunc ++ ++" vim: shiftwidth=2 sts=2 expandtab diff --git a/vim.spec b/vim.spec index 02775b85..58afa57e 100644 --- a/vim.spec +++ b/vim.spec @@ -27,7 +27,7 @@ Summary: The VIM editor URL: http://www.vim.org/ Name: vim Version: %{baseversion}.%{patchlevel} -Release: 33%{?dist} +Release: 34%{?dist} License: Vim and MIT Source0: ftp://ftp.vim.org/pub/vim/unix/vim-%{baseversion}-%{patchlevel}.tar.bz2 Source1: virc @@ -206,6 +206,11 @@ Patch3072: 0001-patch-9.2.0479-security-runtime-tar-command-injectio.patch # https://redhat.atlassian.net/browse/RHEL-185873 # https://github.com/vim/vim/commit/a65a52d684bc58535ad28a4ae824d22e76399934 Patch3073: 0001-patch-9.2.0496-security-Code-Injection-in-cucumber-f.patch +# RHEL-203984 CVE-2026-59858 arbitrary Ex command execution during C omni-completion +# https://redhat.atlassian.net/browse/RHEL-203984 +# https://github.com/vim/vim/commit/6b611b0d15603c52ebdad17172b0232b4f65704e +# adjusted: kept legacy Vimscript style (exe/keepj/.); added source check.vim for CheckUnix +Patch3074: 0001-patch-9.2.0735-security-arbitrary-Ex-command-executi.patch # gcc is no longer in buildroot by default @@ -467,6 +472,7 @@ perl -pi -e "s,bin/nawk,bin/awk,g" runtime/tools/mve.awk %patch -P 3071 -p1 -b .modeline-tests %patch -P 3072 -p1 -b .tar-cmd-inject %patch -P 3073 -p1 -b .cucumber-code-inject +%patch -P 3074 -p1 -b .ccomplete-typeref-escape %build cd src @@ -1019,6 +1025,10 @@ touch %{buildroot}/%{_datadir}/%{name}/vimfiles/doc/tags %endif %changelog +* Wed Jul 29 2026 RHEL Packaging Agent - 2:8.2.2637-34 +- RHEL-203984 CVE-2026-59858 vim: arbitrary Ex command execution during C + omni-completion + * Thu Jul 16 2026 Zdenek Dohnal - 2:8.2.2637-33 - RHEL-185873 CVE-2026-47167 vim: Code Injection in cucumber filetype plugin