forked from aniani/vim
patch 9.1.0143: [security]: autocmd causes use-after-free in set_curbuf()
Problem: [security]: autocmd cause use-after-free in set_curbuf() (kawarimidoll) Solution: check side-effect of BufLeave autocommand, when the number of windows changed, close windows containing buffers that will be wiped, if curbuf changed unexpectedly make sure b_nwindows is decremented otherwise it cannot be wiped set_curbuf() already makes some efforts to ensure the BufLeave autocommands do not cause issues. However there are still 2 issues that are not taken care of: 1) If a BufLeave autocommand opens a new window containing the same buffer as that is going got be closed in close_buffer() a bit later, we suddenly have another window open, containing a free'd buffer. So we must check if the number of windows changed and if it does (and the current buffer is going to be wiped (according to the 'bufhidden' setting), let's immediately close all windows containing the current buffer using close_windows() 2) If a BufLeave autocommand changes our current buffer (displays it in the current window), buf->b_nwindow will be incremented. As part of set_curbuf() we will however enter another buffer soon, which means, the newly created curbuf will have b_nwindows still have set, even so the buffer is no longer displayed in a window. This causes later problems, because it will no longer be possible to wipe such a buffer. So just before entering the final buffer, check if the curbuf changed when calling the BufLeave autocommand and if it does (and curbuf is still valid), decrement curbuf->b_nwindows. Both issues can be verified using the provided test (however the second issue only because such an impacted buffer won't be wiped, causing futher issues in later tests). fixes: #13839 closes: #14104 Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
11
src/buffer.c
11
src/buffer.c
@@ -1790,6 +1790,7 @@ set_curbuf(buf_T *buf, int action)
|
||||
bufref_T newbufref;
|
||||
bufref_T prevbufref;
|
||||
int valid;
|
||||
int last_winid = get_last_winid();
|
||||
|
||||
setpcmark();
|
||||
if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
|
||||
@@ -1818,7 +1819,11 @@ set_curbuf(buf_T *buf, int action)
|
||||
if (prevbuf == curwin->w_buffer)
|
||||
reset_synblock(curwin);
|
||||
#endif
|
||||
if (unload)
|
||||
// autocommands may have opened a new window
|
||||
// with prevbuf, grr
|
||||
if (unload ||
|
||||
(last_winid != get_last_winid() &&
|
||||
strchr((char *)"wdu", prevbuf->b_p_bh[0]) != NULL))
|
||||
close_windows(prevbuf, FALSE);
|
||||
#if defined(FEAT_EVAL)
|
||||
if (bufref_valid(&prevbufref) && !aborting())
|
||||
@@ -1854,6 +1859,10 @@ set_curbuf(buf_T *buf, int action)
|
||||
#endif
|
||||
) || curwin->w_buffer == NULL)
|
||||
{
|
||||
// autocommands changed curbuf and we will move to another
|
||||
// buffer soon, so decrement curbuf->b_nwindows
|
||||
if (curbuf != NULL && prevbuf != curbuf)
|
||||
curbuf->b_nwindows--;
|
||||
// If the buffer is not valid but curwin->w_buffer is NULL we must
|
||||
// enter some buffer. Using the last one is hopefully OK.
|
||||
if (!valid)
|
||||
|
@@ -96,4 +96,5 @@ int win_hasvertsplit(void);
|
||||
int get_win_number(win_T *wp, win_T *first_win);
|
||||
int get_tab_number(tabpage_T *tp);
|
||||
char *check_colorcolumn(win_T *wp);
|
||||
int get_last_winid(void);
|
||||
/* vim: set ft=c : */
|
||||
|
@@ -4441,4 +4441,16 @@ func Test_autocmd_invalidates_undo_on_textchanged()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_creates_new_buffer_on_bufleave()
|
||||
e a.txt
|
||||
e b.txt
|
||||
setlocal bufhidden=wipe
|
||||
autocmd BufLeave <buffer> diffsplit c.txt
|
||||
bn
|
||||
call assert_equal(1, winnr('$'))
|
||||
call assert_equal('a.txt', bufname('%'))
|
||||
bw a.txt
|
||||
bw c.txt
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
143,
|
||||
/**/
|
||||
142,
|
||||
/**/
|
||||
|
@@ -7941,3 +7941,9 @@ skip:
|
||||
return NULL; // no error
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
get_last_winid(void)
|
||||
{
|
||||
return last_win_id;
|
||||
}
|
||||
|
Reference in New Issue
Block a user