Commit: patch 9.2.0076: [security]: buffer-overflow in terminal handling

1 view
Skip to first unread message

Christian Brabandt

unread,
Feb 27, 2026, 4:16:54 PM (5 days ago) Feb 27
to vim...@googlegroups.com
patch 9.2.0076: [security]: buffer-overflow in terminal handling

Commit: https://github.com/vim/vim/commit/bb6de2105b160e729c340631435cd62f3e69bd32
Author: Christian Brabandt <c...@256bit.org>
Date: Mon Feb 23 20:29:43 2026 +0000

patch 9.2.0076: [security]: buffer-overflow in terminal handling

Problem: When processing terminal output with many combining characters
from supplementary planes (4-byte UTF-8), a heap-buffer
overflow occurs. Additionally, the loop iterating over
cell characters can read past the end of the vterm array
(ehdgks0627, un3xploitable).
Solution: Use VTERM_MAX_CHARS_PER_CELL * 4 for ga_grow() to ensure
sufficient space. Add a boundary check to the character
loop to prevent index out-of-bounds access.

Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-rvj2-jrf9-2phg

Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/terminal.c b/src/terminal.c
index 0753c2892..02ca5d6d9 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3570,12 +3570,13 @@ handle_pushline(int cols, const VTermScreenCell *cells, void *user)
{
for (col = 0; col < len; col += cells[col].width)
{
- if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
+ if (ga_grow(&ga, VTERM_MAX_CHARS_PER_CELL * 4) == FAIL)
{
ga.ga_len = 0;
break;
}
- for (i = 0; (c = cells[col].chars[i]) > 0 || i == 0; ++i)
+ for (i = 0; i < VTERM_MAX_CHARS_PER_CELL &&
+ ((c = cells[col].chars[i]) > 0 || i == 0); ++i)
ga.ga_len += utf_char2bytes(c == NUL ? ' ' : c,
(char_u *)ga.ga_data + ga.ga_len);
cell2cellattr(&cells[col], &p[col]);
diff --git a/src/testdir/samples/terminal_max_combining_chars.txt b/src/testdir/samples/terminal_max_combining_chars.txt
new file mode 100644
index 000000000..a4f508d54
--- /dev/null
+++ b/src/testdir/samples/terminal_max_combining_chars.txt
@@ -0,0 +1,80 @@
+padding line 000
+padding line 001
+padding line 002
+padding line 003
+padding line 004
+padding line 005
+padding line 006
+padding line 007
+padding line 008
+padding line 009
+padding line 010
+padding line 011
+padding line 012
+padding line 013
+padding line 014
+padding line 015
+padding line 016
+padding line 017
+padding line 018
+padding line 019
+padding line 020
+padding line 021
+padding line 022
+padding line 023
+padding line 024
+padding line 025
+padding line 026
+padding line 027
+padding line 028
+padding line 029
+padding line 030
+padding line 031
+padding line 032
+padding line 033
+padding line 034
+padding line 035
+padding line 036
+padding line 037
+padding line 038
+padding line 039
+padding line 040
+padding line 041
+padding line 042
+padding line 043
+padding line 044
+padding line 045
+padding line 046
+padding line 047
+padding line 048
+padding line 049
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
+AAAAAAAAAAAAAAAAAAAAAAAAAAAA𐀀
diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim
index b637a6652..7deb0eaaf 100644
--- a/src/testdir/test_terminal3.vim
+++ b/src/testdir/test_terminal3.vim
@@ -1148,4 +1148,18 @@ func Test_terminal_split_utf8()
exe buf .. "bwipe!"
endfunc

+func Test_terminal_max_combining_chars()
+ " somehow doesn't work on MS-Windows
+ CheckUnix
+ let cmd = "cat samples/terminal_max_combining_chars.txt\<CR>"
+ let buf = Run_shell_in_terminal({'term_rows': 15, 'term_cols': 35})
+ call TermWait(buf)
+ call term_sendkeys(buf, cmd)
+ " last char is a space with many combining chars
+ call WaitForAssert({-> assert_match("AAAAAAAAAAAAAAAAAAAAAAAAAAAA.", term_getline(buf, 14))})
+
+ call term_sendkeys(buf, "exit
")
+ exe buf . "bwipe!"
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index f2809216a..21a1f3207 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 76,
/**/
75,
/**/
Reply all
Reply to author
Forward
0 new messages