mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00: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:
		| @@ -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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sean Dewar
					Sean Dewar