comparison src/buffer.c @ 34454:f8fed6c8bb60 v9.1.0143

patch 9.1.0143: [security]: autocmd causes use-after-free in set_curbuf() Commit: https://github.com/vim/vim/commit/55f8bba73be5f9c3a5a4d0d6c5f56e65f2c7d3fc Author: Christian Brabandt <cb@256bit.org> Date: Wed Feb 28 23:32:00 2024 +0100 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>
author Christian Brabandt <cb@256bit.org>
date Wed, 28 Feb 2024 23:45:03 +0100
parents 0a458b49e1e6
children dd8f5311cee5
comparison
equal deleted inserted replaced
34453:607deb7b6a3b 34454:f8fed6c8bb60
1788 long old_tw = curbuf->b_p_tw; 1788 long old_tw = curbuf->b_p_tw;
1789 #endif 1789 #endif
1790 bufref_T newbufref; 1790 bufref_T newbufref;
1791 bufref_T prevbufref; 1791 bufref_T prevbufref;
1792 int valid; 1792 int valid;
1793 int last_winid = get_last_winid();
1793 1794
1794 setpcmark(); 1795 setpcmark();
1795 if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) 1796 if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
1796 curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file 1797 curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file
1797 buflist_altfpos(curwin); // remember curpos 1798 buflist_altfpos(curwin); // remember curpos
1816 { 1817 {
1817 #ifdef FEAT_SYN_HL 1818 #ifdef FEAT_SYN_HL
1818 if (prevbuf == curwin->w_buffer) 1819 if (prevbuf == curwin->w_buffer)
1819 reset_synblock(curwin); 1820 reset_synblock(curwin);
1820 #endif 1821 #endif
1821 if (unload) 1822 // autocommands may have opened a new window
1823 // with prevbuf, grr
1824 if (unload ||
1825 (last_winid != get_last_winid() &&
1826 strchr((char *)"wdu", prevbuf->b_p_bh[0]) != NULL))
1822 close_windows(prevbuf, FALSE); 1827 close_windows(prevbuf, FALSE);
1823 #if defined(FEAT_EVAL) 1828 #if defined(FEAT_EVAL)
1824 if (bufref_valid(&prevbufref) && !aborting()) 1829 if (bufref_valid(&prevbufref) && !aborting())
1825 #else 1830 #else
1826 if (bufref_valid(&prevbufref)) 1831 if (bufref_valid(&prevbufref))
1852 #ifdef FEAT_EVAL 1857 #ifdef FEAT_EVAL
1853 && !aborting() 1858 && !aborting()
1854 #endif 1859 #endif
1855 ) || curwin->w_buffer == NULL) 1860 ) || curwin->w_buffer == NULL)
1856 { 1861 {
1862 // autocommands changed curbuf and we will move to another
1863 // buffer soon, so decrement curbuf->b_nwindows
1864 if (curbuf != NULL && prevbuf != curbuf)
1865 curbuf->b_nwindows--;
1857 // If the buffer is not valid but curwin->w_buffer is NULL we must 1866 // If the buffer is not valid but curwin->w_buffer is NULL we must
1858 // enter some buffer. Using the last one is hopefully OK. 1867 // enter some buffer. Using the last one is hopefully OK.
1859 if (!valid) 1868 if (!valid)
1860 enter_buffer(lastbuf); 1869 enter_buffer(lastbuf);
1861 else 1870 else