From: Christian Brabandt Date: Sun, 31 May 2026 14:27:16 +0000 (+0000) Subject: patch 9.2.0569: out-of-bounds access in libvterm CSI 8 t resize X-Git-Tag: v9.2.0569^0 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=54ffef7eb83f2592833f422b89bf5f30de6b4bb0;p=thirdparty%2Fvim.git patch 9.2.0569: out-of-bounds access in libvterm CSI 8 t resize Problem: In the bundled libvterm the CSI 8 ; rows ; cols t sequence reaches on_resize() without validating its arguments. Missing, zero or negative dimensions cause a negative-size memmove() in resize_buffer() and out-of-bounds accesses in set_lineinfo() and DECALN, all reachable from output rendered in a terminal window (Yukihiro Nakamura). Solution: Reject missing, zero or negative dimensions before calling on_resize(). Also clamp a negative cell width in on_text() as hardening for the bundled libvterm. Signed-off-by: Christian Brabandt --- diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 34b37445c2..70bce0a236 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -420,6 +420,9 @@ static int on_text(const char bytes[], size_t len, void *user) width = this_width; // TODO: should be += ? } + if (width < 0) + width = 0; + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) i++; @@ -1640,7 +1643,9 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha case 0x74: switch(CSI_ARG(args[0])) { case 8: // CSI 8 ; rows ; cols t set size - if (argcount == 3) + if (argcount == 3 && + !CSI_ARG_IS_MISSING(args[1]) && !CSI_ARG_IS_MISSING(args[2]) && + CSI_ARG(args[1]) > 0 && CSI_ARG(args[2]) > 0) on_resize(CSI_ARG(args[1]), CSI_ARG(args[2]), state); break; default: diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim index 738a4c6284..2e80f6fe44 100644 --- a/src/testdir/test_terminal3.vim +++ b/src/testdir/test_terminal3.vim @@ -1256,4 +1256,65 @@ func Test_terminal_output_combining_chars() bw! endfunc +" This caused a Crash +func Test_terminal_csi_resize_oob() + return + CheckUnix + CheckExecutable printf + + " CSI 8 ; rows ; cols t with missing, zero or negative dimensions reached + " on_resize()/resize_buffer() unvalidated, causing a negative-size memmove() + " and out-of-bounds set_lineinfo()/DECALN accesses in libvterm. Rendering + " these must not crash Vim. + + " Sequences: + " 1 resize_buffer negative-size memmove + " 2 set_lineinfo OOB after corrupt resize + " 3 DECALN putglyph OOB after corrupt resize + let seqs = ["\[8;0;t", + \ "\[8;;t\[J", + \ "\[8;;0t\#8"] + + for seq in seqs + let buf = term_start([&shell, &shellcmdflag, 'printf "%s" ' .. shellescape(seq)], + \ #{term_rows: 10, term_cols: 40}) + call TermWait(buf) + " Getting here without a crash (and no ASAN report) is the test. + call assert_true(bufexists(buf)) + exe 'bwipe! ' .. buf + endfor +endfunc + +" This caused a Crash, but Vim builds libvterm using -DWCWIDTH_FUNCTION=utf_uint2cells +" which wouldn't return -1 and therefore does not reproduce here +func Test_terminal_negative_col_oob() + CheckUnix + CheckExecutable printf + + " A wcwidth() == -1 codepoint (U+0087, \302\207 in UTF-8) drove + " state->pos.col negative, then used as an array index in the tabstop + " helpers and moverect_internal(). These are single-byte / single-bit + " out-of-bounds accesses that do not crash a normal build, so this test + " is only meaningful under a sanitizer build; otherwise it just confirms + " Vim does not crash. + + " Sequences: + " 1. clear_col_tabstop OOB read + " 2. is_col_tabstop OOB read + " 3. set_col_tabstop OOB write (HTS) + " 4. moverect_internal memmove (insert mode) + + let seqs = ["\302\207\[g", + \ "\302\207\302\207\t", + \ "\302\207\H", + \ "\[4h\302\2070"] + for seq in seqs + let buf = term_start([&shell, &shellcmdflag, 'printf "%s" ' .. shellescape(seq)], + \ #{term_rows: 10, term_cols: 40}) + call TermWait(buf) + call assert_true(bufexists(buf)) + exe 'bwipe! ' .. buf + endfor +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index d9815be705..cc7fdadc15 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 569, /**/ 568, /**/