From d47d317a791bbedb67a923487052e271ebfb5225 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:16:39 +0000 Subject: [PATCH] vim-patch:9.1.2128: Heap use after free in buf_check_timestamp() Problem: heap UAF if autocommands from reloading a file changed outside of Vim wipe its buffer. Solution: Validate the bufref after buf_reload (Sean Dewar) closes: vim/vim#19317 https://github.com/vim/vim/commit/392b428d1239e963020b73682cd03f17ffb538b3 Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> (cherry picked from commit fede5686929139ff6cf72e171718326d72c57857) --- src/nvim/fileio.c | 2 +- test/old/testdir/test_filechanged.vim | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6aa68fe2db..eb306b7fa9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3060,7 +3060,7 @@ int buf_check_timestamp(buf_T *buf) if (reload != RELOAD_NONE) { // Reload the buffer. buf_reload(buf, orig_mode, reload == RELOAD_DETECT); - if (buf->b_p_udf && buf->b_ffname != NULL) { + if (bufref_valid(&bufref) && buf->b_p_udf && buf->b_ffname != NULL) { uint8_t hash[UNDO_HASH_SIZE]; // Any existing undo file is unusable, write it now. diff --git a/test/old/testdir/test_filechanged.vim b/test/old/testdir/test_filechanged.vim index a8fc78ff90..0bb20f2ddb 100644 --- a/test/old/testdir/test_filechanged.vim +++ b/test/old/testdir/test_filechanged.vim @@ -289,4 +289,27 @@ func Test_FileChangedShell_newbuf() call delete('Xfile') endfunc +func Test_file_changed_wipeout() + call writefile(['foo'], 'Xchanged_bw', 'D') + edit Xchanged_bw + augroup FileChangedWipeout + autocmd FileChangedShell * ++once let v:fcs_choice = 'reload' + autocmd BufReadPost * ++once %bw! + augroup END + + " Need to wait until the timestamp would change. + if has('nanotime') + sleep 10m + else + sleep 2 + endif + call writefile(['bar'], 'Xchanged_bw') + call assert_equal(1, bufexists('Xchanged_bw')) + checktime " used to be a heap UAF + call assert_equal(0, bufexists('Xchanged_bw')) + + au! FileChangedWipeout + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab