mirror of
https://git.yoctoproject.org/poky
synced 2026-05-30 12:29:55 +00:00
vim: fix for CVE-2026-39881
Pick patch from [1] also mentioned at Debian report in [2] [1] https://github.com/vim/vim/commit/7ab76a86048ed492374ac6b19c6cb52f89a365b4 [2] https://security-tracker.debian.org/tracker/CVE-2026-39881 More details: https://nvd.nist.gov/vuln/detail/CVE-2026-39881 (From OE-Core rev: e92dd3b16cd75d9c765f0ff4bc84fbdda8c3dca6) Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
committed by
Paul Barker
parent
5681810cc4
commit
27c18f15c0
@@ -0,0 +1,248 @@
|
||||
From 7ab76a86048ed492374ac6b19c6cb52f89a365b4 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 7 Apr 2026 17:32:02 +0000
|
||||
Subject: [PATCH] patch 9.2.0316: [security]: command injection in netbeans
|
||||
interface via defineAnnoType
|
||||
|
||||
Problem: [security]: The netbeans defineAnnoType command passes typeName, fg and bg
|
||||
unsanitized to coloncmd(), allowing a malicious server to inject
|
||||
arbitrary Ex commands via '|'. Similarly, specialKeys does not
|
||||
validate key tokens before building a map command.
|
||||
Solution: Validate typeName, fg and bg against an allowlist of safe
|
||||
characters before passing them to coloncmd()
|
||||
|
||||
Github Advisory:
|
||||
https://github.com/vim/vim/security/advisories/GHSA-mr87-rhgv-7pw6
|
||||
|
||||
Supported by AI
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
|
||||
CVE: CVE-2026-39881
|
||||
Upstream-Status: Backport [https://github.com/vim/vim/commit/7ab76a86048ed492374ac6b19c6cb52f89a365b4]
|
||||
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
|
||||
---
|
||||
runtime/doc/netbeans.txt | 4 +--
|
||||
runtime/doc/tags | 1 +
|
||||
src/errors.h | 3 ++-
|
||||
src/netbeans.c | 46 ++++++++++++++++++++++++++++++++++-
|
||||
src/po/vim.pot | 5 +++-
|
||||
src/testdir/test_netbeans.py | 4 ++-
|
||||
src/testdir/test_netbeans.vim | 38 +++++++++++++++++++++++++++++
|
||||
7 files changed, 96 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/runtime/doc/netbeans.txt b/runtime/doc/netbeans.txt
|
||||
index ca32f06f66..fa53eae784 100644
|
||||
--- a/runtime/doc/netbeans.txt
|
||||
+++ b/runtime/doc/netbeans.txt
|
||||
@@ -1,4 +1,4 @@
|
||||
-*netbeans.txt* For Vim version 9.1. Last change: 2025 Aug 10
|
||||
+*netbeans.txt* For Vim version 9.1. Last change: 2026 Apr 30
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Gordon Prieur et al.
|
||||
@@ -847,7 +847,7 @@ REJECT Not used.
|
||||
These errors occur when a message violates the protocol:
|
||||
*E627* *E628* *E629* *E632* *E633* *E634* *E635* *E636*
|
||||
*E637* *E638* *E639* *E640* *E641* *E642* *E643* *E644* *E645* *E646*
|
||||
-*E647* *E648* *E650* *E651* *E652*
|
||||
+*E647* *E648* *E649* *E650* *E651* *E652*
|
||||
|
||||
|
||||
==============================================================================
|
||||
diff --git a/runtime/doc/tags b/runtime/doc/tags
|
||||
index 8af54eae0a..300dfd18a6 100644
|
||||
--- a/runtime/doc/tags
|
||||
+++ b/runtime/doc/tags
|
||||
@@ -5236,6 +5236,7 @@ E645 netbeans.txt /*E645*
|
||||
E646 netbeans.txt /*E646*
|
||||
E647 netbeans.txt /*E647*
|
||||
E648 netbeans.txt /*E648*
|
||||
+E649 netbeans.txt /*E649*
|
||||
E65 pattern.txt /*E65*
|
||||
E650 netbeans.txt /*E650*
|
||||
E651 netbeans.txt /*E651*
|
||||
diff --git a/src/errors.h b/src/errors.h
|
||||
index 5d6867464b..01ed16a035 100644
|
||||
--- a/src/errors.h
|
||||
+++ b/src/errors.h
|
||||
@@ -1664,7 +1664,8 @@ EXTERN char e_invalid_buffer_identifier_in_setdot[]
|
||||
INIT(= N_("E647: Invalid buffer identifier in setDot"));
|
||||
EXTERN char e_invalid_buffer_identifier_in_close[]
|
||||
INIT(= N_("E648: Invalid buffer identifier in close"));
|
||||
-// E649 unused
|
||||
+EXTERN char e_invalid_identifier_in_defineannotype[]
|
||||
+ INIT(= N_("E649: Invalid identifier name in defineAnnoType"));
|
||||
EXTERN char e_invalid_buffer_identifier_in_defineannotype[]
|
||||
INIT(= N_("E650: Invalid buffer identifier in defineAnnoType"));
|
||||
EXTERN char e_invalid_buffer_identifier_in_addanno[]
|
||||
diff --git a/src/netbeans.c b/src/netbeans.c
|
||||
index 8a341a20be..599cdc1994 100644
|
||||
--- a/src/netbeans.c
|
||||
+++ b/src/netbeans.c
|
||||
@@ -40,6 +40,11 @@
|
||||
#define GUARDEDOFFSET 1000000 // base for "guarded" sign id's
|
||||
#define MAX_COLOR_LENGTH 32 // max length of color name in defineAnnoType
|
||||
|
||||
+// Characters valid in a sign/highlight group name
|
||||
+#define VALID_CHARS (char_u *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
+#define VALID_SIGNNAME_CHARS VALID_CHARS "_"
|
||||
+#define VALID_COLOR_CHARS VALID_CHARS "#"
|
||||
+
|
||||
// The first implementation (working only with Netbeans) returned "1.1". The
|
||||
// protocol implemented here also supports A-A-P.
|
||||
static char *ExtEdProtocolVersion = "2.5";
|
||||
@@ -77,6 +82,22 @@ static int dosetvisible = FALSE;
|
||||
static int needupdate = 0;
|
||||
static int inAtomic = 0;
|
||||
|
||||
+/*
|
||||
+ * Return TRUE if "str" contains only characters from "allowed".
|
||||
+ * Used to validate NetBeans-supplied strings before interpolating them
|
||||
+ * into Ex commands via coloncmd().
|
||||
+ */
|
||||
+ static int
|
||||
+nb_is_safe_string(char_u *str, char_u *allowed)
|
||||
+{
|
||||
+ if (str == NULL)
|
||||
+ return FALSE;
|
||||
+ for (char_u *p = str; *p != NUL; p++)
|
||||
+ if (vim_strchr(allowed, *p) == NULL)
|
||||
+ return FALSE;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Callback invoked when the channel is closed.
|
||||
*/
|
||||
@@ -1949,6 +1970,15 @@ nb_do_cmd(
|
||||
VIM_CLEAR(typeName);
|
||||
parse_error = TRUE;
|
||||
}
|
||||
+ else if (!nb_is_safe_string(typeName, VALID_SIGNNAME_CHARS) ||
|
||||
+ (*fg != NUL && !nb_is_safe_string(fg, VALID_COLOR_CHARS)) ||
|
||||
+ (*bg != NUL && !nb_is_safe_string(bg, VALID_COLOR_CHARS)))
|
||||
+ {
|
||||
+ nbdebug((" invalid chars in typeName/fg/bg in defineAnnoType\n"));
|
||||
+ emsg(_(e_invalid_identifier_in_defineannotype));
|
||||
+ VIM_CLEAR(typeName);
|
||||
+ parse_error = TRUE;
|
||||
+ }
|
||||
else if (typeName != NULL && tooltip != NULL && glyphFile != NULL)
|
||||
addsigntype(buf, typeNum, typeName, tooltip, glyphFile, fg, bg);
|
||||
|
||||
@@ -2321,11 +2351,25 @@ special_keys(char_u *args)
|
||||
|
||||
if (strlen(tok) + i < KEYBUFLEN)
|
||||
{
|
||||
- strcpy(&keybuf[i], tok);
|
||||
+ // Only allow alphanumeric and function-key name characters.
|
||||
+ // Reject anything else to prevent map command injection.
|
||||
+ int safe = TRUE;
|
||||
+ for (char_u *tp = (char_u *)tok; *tp != NUL; tp++)
|
||||
+ {
|
||||
+ if (!ASCII_ISALNUM(*tp) && *tp != '-')
|
||||
+ {
|
||||
+ safe = FALSE;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (safe)
|
||||
+ {
|
||||
+ vim_strncpy((char_u *)&keybuf[i], (char_u *)tok, KEYBUFLEN - i - 1);
|
||||
vim_snprintf(cmdbuf, sizeof(cmdbuf),
|
||||
"<silent><%s> :nbkey %s<CR>", keybuf, keybuf);
|
||||
do_map(MAPTYPE_MAP, (char_u *)cmdbuf, MODE_NORMAL, FALSE);
|
||||
}
|
||||
+ }
|
||||
tok = strtok(NULL, " ");
|
||||
}
|
||||
vim_free(save_str);
|
||||
diff --git a/src/po/vim.pot b/src/po/vim.pot
|
||||
index bf44567726..9608271418 100644
|
||||
--- a/src/po/vim.pot
|
||||
+++ b/src/po/vim.pot
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Vim\n"
|
||||
"Report-Msgid-Bugs-To: vim-dev@vim.org\n"
|
||||
-"POT-Creation-Date: 2025-08-23 16:16+0200\n"
|
||||
+"POT-Creation-Date: 2026-04-30 12:40+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -5866,6 +5866,9 @@ msgstr ""
|
||||
msgid "E648: Invalid buffer identifier in close"
|
||||
msgstr ""
|
||||
|
||||
+msgid "E649: Invalid identifier name in defineAnnoType"
|
||||
+msgstr ""
|
||||
+
|
||||
msgid "E650: Invalid buffer identifier in defineAnnoType"
|
||||
msgstr ""
|
||||
|
||||
diff --git a/src/testdir/test_netbeans.py b/src/testdir/test_netbeans.py
|
||||
index 585886fb40..ba5fd638ec 100644
|
||||
--- a/src/testdir/test_netbeans.py
|
||||
+++ b/src/testdir/test_netbeans.py
|
||||
@@ -113,7 +113,9 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
'endAtomic_Test' : '0:endAtomic!95\n',
|
||||
'AnnoScale_Test' : "".join(['2:defineAnnoType!60 ' + str(i) + ' "s' + str(i) + '" "x" "=>" blue none\n' for i in range(2, 26)]),
|
||||
'detach_Test' : '2:close!96\n1:close!97\nDETACH\n',
|
||||
- 'specialKeys_overflow_Test' : '0:specialKeys!200 "' + 'A'*80 + '-X"\n'
|
||||
+ 'specialKeys_overflow_Test' : '0:specialKeys!200 "' + 'A'*80 + '-X"\n',
|
||||
+ 'defineAnnoType_injection_Test': '1:defineAnnoType!1 "MySign guifg=red|call writefile([\'inject\'],\'Xinject\')|" "tooltip" "glyphFile" 1 2\n'
|
||||
+
|
||||
|
||||
}
|
||||
# execute the specified test
|
||||
diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim
|
||||
index d1be5066ef..a464c63acc 100644
|
||||
--- a/src/testdir/test_netbeans.vim
|
||||
+++ b/src/testdir/test_netbeans.vim
|
||||
@@ -1024,4 +1024,42 @@ func Test_nb_specialKeys_overflow()
|
||||
call s:run_server('Nb_specialKeys_overflow')
|
||||
endfunc
|
||||
|
||||
+func Nb_defineAnnoType_injection(port)
|
||||
+ call writefile([], "Xnetbeans", 'D')
|
||||
+ let g:last = 0
|
||||
+
|
||||
+ exe 'nbstart :localhost:' .. a:port .. ':bunny'
|
||||
+ call assert_true(has("netbeans_enabled"))
|
||||
+ call WaitFor('len(ReadXnetbeans()) > (g:last + 2)')
|
||||
+ let g:last += 3
|
||||
+
|
||||
+ split Xcmdbuf
|
||||
+ let cmdbufnr = bufnr()
|
||||
+ call WaitFor('len(ReadXnetbeans()) > (g:last + 2)')
|
||||
+ let g:last += 3
|
||||
+ hide
|
||||
+
|
||||
+ sleep 1m
|
||||
+
|
||||
+ call delete('Xinject')
|
||||
+ call appendbufline(cmdbufnr, '$', 'defineAnnoType_injection_Test')
|
||||
+ " E475 from :sign is expected — catch it before RunServer sees it.
|
||||
+ " give it a bit of time to process it
|
||||
+ try
|
||||
+ sleep 500m
|
||||
+ catch /E475/
|
||||
+ catch /E649/
|
||||
+ endtry
|
||||
+
|
||||
+ " Injected call must not have created this file
|
||||
+ call assert_false(filereadable('Xinject'))
|
||||
+ call delete('Xinject')
|
||||
+ bwipe! Xcmdbuf
|
||||
+ nbclose
|
||||
+endfunc
|
||||
+
|
||||
+func Test_nb_defineAnnoType_injection()
|
||||
+ call ch_log('Test_nb_defineAnnoType_injection')
|
||||
+ call s:run_server('Nb_defineAnnoType_injection')
|
||||
+endfunc
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
--
|
||||
2.50.1
|
||||
|
||||
@@ -21,6 +21,7 @@ SRC_URI = "git://github.com/vim/vim.git;branch=master;protocol=https \
|
||||
file://CVE-2026-33412.patch \
|
||||
file://CVE-2026-28418.patch \
|
||||
file://CVE-2026-28419.patch \
|
||||
file://CVE-2026-39881.patch \
|
||||
"
|
||||
|
||||
PV .= ".1683"
|
||||
|
||||
Reference in New Issue
Block a user