mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 04:42:03 +00:00
fix(autocmd): potential TabClosed UAF, always set abuf
Problem: win_free_mem can free w_buffer (via qf_free_all), which may cause a heap use-after-free if used as TabClosed's <abuf>. I think TabClosed is also the only event to conditionally set <abuf> not based on event type. Solution: use the buffer saved by the bufref. Fall back to curbuf if invalid, like WinResized/WinScrolled. NOTE: Not always equivalent if close_buffer autocmds switch buffers at the last moment; previously <abuf> would be set to that buffer. Fixed in next commit. https://github.com/neovim/neovim/actions/runs/21765657455/job/62800643599?pr=37758#step:9:159 for an example of qf_free_all being a nuisance.
This commit is contained in:
@@ -3263,7 +3263,6 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|
||||
}
|
||||
|
||||
// Free the memory used for the window.
|
||||
buf_T *buf = win->w_buffer;
|
||||
int dir;
|
||||
win_free_mem(win, &dir, tp);
|
||||
|
||||
@@ -3276,7 +3275,8 @@ bool win_close_othertab(win_T *win, int free_buf, tabpage_T *tp, bool force)
|
||||
if (has_event(EVENT_TABCLOSED)) {
|
||||
char prev_idx[NUMBUFLEN];
|
||||
vim_snprintf(prev_idx, NUMBUFLEN, "%i", free_tp_idx);
|
||||
apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, buf);
|
||||
apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false,
|
||||
bufref.br_buf && bufref_valid(&bufref) ? bufref.br_buf : curbuf);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -59,13 +59,14 @@ describe('TabClosed', function()
|
||||
setlocal bufhidden=wipe
|
||||
tabnew
|
||||
au TabClosed * ++once let g:tp_valid = nvim_tabpage_is_valid(s:tp)
|
||||
\| let g:curbuf = bufnr()
|
||||
\| let g:abuf = expand('<abuf>')
|
||||
|
||||
call nvim_buf_delete(g:buf, #{force: 1})
|
||||
]])
|
||||
eq(false, eval('g:tp_valid'))
|
||||
eq(false, eval('nvim_buf_is_valid(g:buf)'))
|
||||
eq('', eval('g:abuf'))
|
||||
eq(eval('g:curbuf'), tonumber(eval('g:abuf'))) -- Falls back to curbuf.
|
||||
|
||||
exec([[
|
||||
tabnew
|
||||
|
||||
Reference in New Issue
Block a user