# HG changeset patch # User Christian Brabandt # Date 1693765802 -7200 # Node ID cdc797578b8b8f25769614dbb90d3ab4c29d2d14 # Parent f566f2aae66bba1f9049394dc4a2f16194e88f23 patch 9.0.1857: [security] heap-use-after-free in is_qf_win() Commit: https://github.com/vim/vim/commit/fc68299d436cf87453e432daa77b6d545df4d7ed Author: Christian Brabandt Date: Sun Sep 3 20:20:52 2023 +0200 patch 9.0.1857: [security] heap-use-after-free in is_qf_win() Problem: heap-use-after-free in is_qf_win() Solution: Check buffer is valid before accessing it Signed-off-by: Christian Brabandt diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -1646,7 +1646,7 @@ getout(int exitval) next_tp = tp->tp_next; FOR_ALL_WINDOWS_IN_TAB(tp, wp) { - if (wp->w_buffer == NULL) + if (wp->w_buffer == NULL || !buf_valid(wp->w_buffer)) // Autocmd must have close the buffer already, skip. continue; buf = wp->w_buffer; diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4492,7 +4492,7 @@ is_qf_win(win_T *win, qf_info_T *qi) // set to NULL. // A window displaying a location list buffer will have the w_llist_ref // pointing to the location list. - if (bt_quickfix(win->w_buffer)) + if (buf_valid(win->w_buffer) && bt_quickfix(win->w_buffer)) if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL) || (IS_LL_STACK(qi) && win->w_llist_ref == qi)) return TRUE; diff --git a/src/testdir/crash/bt_quickfix_poc b/src/testdir/crash/bt_quickfix_poc new file mode 100644 --- /dev/null +++ b/src/testdir/crash/bt_quickfix_poc @@ -0,0 +1,9 @@ +comman!-narg=* Xexpr lex +auto BufReadPre * exe"sn" ..expand("") +fu Xautocmd_changelist() +cal writefile(['Xtestfile2:4:4'],'Xerr') + sil! edi Xerr +Xexpr 'Xtestfile:4:4' +endf +call Xautocmd_changelist() +call Xautocmd_changelist() \ No newline at end of file diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim --- a/src/testdir/test_crash.vim +++ b/src/testdir/test_crash.vim @@ -5,38 +5,58 @@ source screendump.vim CheckScreendump func Test_crash1() + if !executable('sh') + throw 'Skipped: sh not executable!' + endif " The following used to crash Vim - " let opts = #{wait_for_ruler: 0, rows: 20, cmd: 'sh'} let opts = #{cmd: 'sh'} - let args = 'bash' let vim = GetVimProg() - let buf = RunVimInTerminal(args, opts) + let buf = RunVimInTerminal('sh', opts) let file = 'crash/poc_huaf1' let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'" let args = printf(cmn_args, vim, file) call term_sendkeys(buf, args .. - \ ' && echo "crash 1: [OK]" >> X_crash1_result.txt' .. "\") + \ ' && echo "crash 1: [OK]" > X_crash1_result.txt' .. "\") + call TermWait(buf, 50) let file = 'crash/poc_huaf2' let args = printf(cmn_args, vim, file) call term_sendkeys(buf, args .. \ ' && echo "crash 2: [OK]" >> X_crash1_result.txt' .. "\") + call TermWait(buf, 50) let file = 'crash/poc_huaf3' let args = printf(cmn_args, vim, file) call term_sendkeys(buf, args .. \ ' && echo "crash 3: [OK]" >> X_crash1_result.txt' .. "\") + call TermWait(buf, 100) - call TermWait(buf, 50) + let file = 'crash/bt_quickfix_poc' + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args .. + \ ' && echo "crash 4: [OK]" >> X_crash1_result.txt' .. "\") + " clean up + call delete('Xerr') + + " This test takes a bit longer + call TermWait(buf, 200) " clean up + call delete('Xerr') exe buf .. "bw!" sp X_crash1_result.txt - call assert_equal(['crash 1: [OK]', 'crash 2: [OK]', 'crash 3: [OK]'], - \ getline(1, '$')) + + let expected = [ + \ 'crash 1: [OK]', + \ 'crash 2: [OK]', + \ 'crash 3: [OK]', + \ 'crash 4: [OK]', + \ ] + + call assert_equal(expected, getline(1, '$')) bw! call delete('X_crash1_result.txt') diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1857, +/**/ 1856, /**/ 1855,