From 3c102303f5381b87fac2016409073ff97e49ea44 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 10 May 2025 16:24:43 +0100 Subject: [PATCH] vim-patch:9.1.1375: [security]: possible heap UAF with quickfix dummy buffer Problem: heap use-after-free possible when autocommands switch away from the quickfix dummy buffer, but leave it open in a window. Solution: close its windows first before attempting the wipe. (Sean Dewar) related: vim/vim#17283 https://github.com/vim/vim/commit/b4074ead5cd8751f0460e157471028dbb77ca1e9 Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> (cherry picked from commit 05dab80d8d8f582c28a2e54e3b3e32f018571b57) --- src/nvim/quickfix.c | 25 +++++++++++++++---------- test/old/testdir/test_quickfix.vim | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 44b66c4f73..dd135a8105 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -5789,7 +5789,9 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin aucmd_restbuf(&aco); if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) { - wipe_buffer(newbuf_to_wipe.br_buf, false); + block_autocmds(); + wipe_dummy_buffer(newbuf_to_wipe.br_buf, NULL); + unblock_autocmds(); } // Add back the "dummy" flag, otherwise buflist_findname_file_id() @@ -5813,11 +5815,11 @@ static buf_T *load_dummy_buffer(char *fname, char *dirname_start, char *resultin return newbuf; } -// Wipe out the dummy buffer that load_dummy_buffer() created. Restores -// directory to "dirname_start" prior to returning, if autocmds or the -// 'autochdir' option have changed it. +/// Wipe out the dummy buffer that load_dummy_buffer() created. Restores +/// directory to "dirname_start" if not NULL prior to returning, if autocmds or +/// the 'autochdir' option have changed it. static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1) { // If any autocommand opened a window on the dummy buffer, close that // window. If we can't close them all then give up. @@ -5852,14 +5854,17 @@ static void wipe_dummy_buffer(buf_T *buf, char *dirname_start) // Restore the error/interrupt/exception state if not discarded by a // new aborting error, interrupt, or uncaught exception. leave_cleanup(&cs); - // When autocommands/'autochdir' option changed directory: go back. - restore_start_dir(dirname_start); + + if (dirname_start != NULL) { + // When autocommands/'autochdir' option changed directory: go back. + restore_start_dir(dirname_start); + } } } -// Unload the dummy buffer that load_dummy_buffer() created. Restores -// directory to "dirname_start" prior to returning, if autocmds or the -// 'autochdir' option have changed it. +/// Unload the dummy buffer that load_dummy_buffer() created. Restores +/// directory to "dirname_start" prior to returning, if autocmds or the +/// 'autochdir' option have changed it. static void unload_dummy_buffer(buf_T *buf, char *dirname_start) { if (curbuf == buf) { // safety check diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index ca48812e7d..5f548bdfa6 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -6596,4 +6596,26 @@ func Test_hardlink_fname() call Xtest_hardlink_fname('l') endfunc +func Test_vimgrep_dummy_buffer_crash() + augroup DummyCrash + autocmd! + " Make the dummy buffer non-current, but still open in a window. + autocmd BufReadCmd * ++once let s:dummy_buf = bufnr() + \| split | wincmd p | enew + + " Autocmds from cleaning up the dummy buffer in this case should be blocked. + autocmd BufWipeout * + \ call assert_notequal(s:dummy_buf, str2nr(expand(''))) + augroup END + + silent! vimgrep /./ . + redraw! " Window to freed dummy buffer used to remain; heap UAF. + call assert_equal([], win_findbuf(s:dummy_buf)) + call assert_equal(0, bufexists(s:dummy_buf)) + + unlet! s:dummy_buf + autocmd! DummyCrash + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab