mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
fix(api): avoid open_win UAF if target buf deleted by autocmds
Problem: WinNew and win_enter autocommands can delete the target buffer to switch to, causing a heap-use-after-free. Solution: store a bufref to the buffer, check it before attempting to switch.
This commit is contained in:
parent
e55a502ed4
commit
b1e24f240b
@ -12,6 +12,7 @@
|
|||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/autocmd.h"
|
#include "nvim/autocmd.h"
|
||||||
#include "nvim/autocmd_defs.h"
|
#include "nvim/autocmd_defs.h"
|
||||||
|
#include "nvim/buffer.h"
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/decoration_defs.h"
|
#include "nvim/decoration_defs.h"
|
||||||
@ -279,6 +280,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
|
|||||||
|
|
||||||
// Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each
|
// Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each
|
||||||
// event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail.
|
// event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail.
|
||||||
|
// Also, autocommands may free the `buf` to switch to, so store a bufref to check.
|
||||||
|
bufref_T bufref;
|
||||||
|
set_bufref(&bufref, buf);
|
||||||
switchwin_T switchwin;
|
switchwin_T switchwin;
|
||||||
{
|
{
|
||||||
const int result = switch_win_noblock(&switchwin, wp, tp, true);
|
const int result = switch_win_noblock(&switchwin, wp, tp, true);
|
||||||
@ -293,7 +297,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
|
|||||||
goto_tabpage_win(tp, wp);
|
goto_tabpage_win(tp, wp);
|
||||||
tp = win_find_tabpage(wp);
|
tp = win_find_tabpage(wp);
|
||||||
}
|
}
|
||||||
if (tp && buf != wp->w_buffer) {
|
if (tp && bufref_valid(&bufref) && buf != wp->w_buffer) {
|
||||||
const bool noautocmd = curwin != wp || fconfig.noautocmd;
|
const bool noautocmd = curwin != wp || fconfig.noautocmd;
|
||||||
win_set_buf(wp, buf, noautocmd, err);
|
win_set_buf(wp, buf, noautocmd, err);
|
||||||
if (!noautocmd) {
|
if (!noautocmd) {
|
||||||
|
@ -1581,6 +1581,14 @@ describe('API/win', function()
|
|||||||
api.nvim_open_win(api.nvim_create_buf(true, true), false, { split = 'left' })
|
api.nvim_open_win(api.nvim_create_buf(true, true), false, { split = 'left' })
|
||||||
eq(true, eval('fired'))
|
eq(true, eval('fired'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('no heap-use-after-free if target buffer deleted by autocommands', function()
|
||||||
|
local cur_buf = api.nvim_get_current_buf()
|
||||||
|
local new_buf = api.nvim_create_buf(true, true)
|
||||||
|
command('autocmd WinNew * ++once call nvim_buf_delete(' .. new_buf .. ', #{force: 1})')
|
||||||
|
api.nvim_open_win(new_buf, true, { split = 'left' })
|
||||||
|
eq(cur_buf, api.nvim_get_current_buf())
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set_config', function()
|
describe('set_config', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user