patch 9.2.0565: [security]: out-of-bounds read in update_snapshot()

Problem:  Out-of-bounds read in update_snapshot() when a terminal cell
          fills all VTERM_MAX_CHARS_PER_CELL slots (a base character
          plus five combining marks): the loop over cell.chars[] has no
          upper bound and libvterm leaves the array unterminated when full, so
          it reads past the array and appends out-of-bounds values to a
          buffer sized for only VTERM_MAX_CHARS_PER_CELL characters.
Solution: Bound the loop with i < VTERM_MAX_CHARS_PER_CELL, mirroring
          the loop in handle_pushline() (Christian Brabandt).

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Christian Brabandt
2026-05-30 16:34:40 +00:00
parent 2c5b383807
commit 63680c6d3d
4 changed files with 219 additions and 1 deletions
+2 -1
View File
@@ -2265,7 +2265,8 @@ update_snapshot(term_T *term)
int i;
int c;
for (i = 0; (c = cell.chars[i]) > 0 || i == 0; ++i)
for (i = 0; i < VTERM_MAX_CHARS_PER_CELL &&
((c = cell.chars[i]) > 0 || i == 0); ++i)
ga.ga_len += utf_char2bytes(c == NUL ? ' ' : c,
(char_u *)ga.ga_data + ga.ga_len);
}
+200
View File
@@ -0,0 +1,200 @@
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
á́́́́ጁ
+15
View File
@@ -1241,4 +1241,19 @@ func Test_terminal_csi_args_overflow()
call StopVimInTerminal(buf)
endfunc
func Test_terminal_output_combining_chars()
CheckUnix
new
let cmd = "cat samples/combining_chars.txt"
let buf = term_start(cmd, {'curwin': 1, 'term_finish': 'open', 'term_rows': 10, 'term_cols': 30})
call WaitForAssert({-> assert_match('finished', term_getstatus(buf))})
call TermWait(buf)
let lines = getbufline(buf, 1, '$')
" get byte lengths to confirm combining chars present
let lens = map(copy(lines), 'len(v:val)')
let expected = repeat([11], 190) + repeat([14], 10)
call assert_equal(expected, lens)
bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
565,
/**/
564,
/**/