diff --git a/debian/changelog b/debian/changelog index 0e17b8070cc667892fc8cc64e463d5dc781e7820..ed23c1ca3e4ed46bb467eba063e78207a836a07e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +vim (2:9.1.0016-ok2) nile; urgency=medium + + * 修复漏洞:CVE-2024-43802 CVE-2024-43374 CVE-2024-47814 + + -- zoey Tue, 07 Jan 2025 13:49:58 +0800 + vim (2:9.1.0016-ok1) nile; urgency=medium * Rebuild for openkylin diff --git a/debian/source/include-binaries b/debian/source/include-binaries new file mode 100644 index 0000000000000000000000000000000000000000..23957ec27b0f0cb81c420a99d327c0fa6addc935 --- /dev/null +++ b/debian/source/include-binaries @@ -0,0 +1 @@ +src/testdir/crash/heap_overflow3 diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000000000000000000000000000000000000..06e1ae9c8a7e8ccbe1ae874153f09735802631df --- /dev/null +++ b/debian/source/options @@ -0,0 +1 @@ +include-binaries diff --git a/src/arglist.c b/src/arglist.c index d28b31da438c5589907cb2e2f227b374c92dc58d..6c30075654b8b83b8f4dec75fd54872980dd1f98 100644 --- a/src/arglist.c +++ b/src/arglist.c @@ -184,6 +184,8 @@ alist_set( /* * Add file "fname" to argument list "al". * "fname" must have been allocated and "al" must have been checked for room. + * + * May trigger Buf* autocommands */ void alist_add( @@ -196,6 +198,7 @@ alist_add( if (check_arglist_locked() == FAIL) return; arglist_locked = TRUE; + curwin->w_locked = TRUE; #ifdef BACKSLASH_IN_FILENAME slash_adjust(fname); @@ -207,6 +210,7 @@ alist_add( ++al->al_ga.ga_len; arglist_locked = FALSE; + curwin->w_locked = FALSE; } #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) @@ -365,6 +369,7 @@ alist_add_list( mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), (ARGCOUNT - after) * sizeof(aentry_T)); arglist_locked = TRUE; + curwin->w_locked = TRUE; for (i = 0; i < count; ++i) { int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); @@ -373,6 +378,7 @@ alist_add_list( ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); } arglist_locked = FALSE; + curwin->w_locked = FALSE; ALIST(curwin)->al_ga.ga_len += count; if (old_argcount > 0 && curwin->w_arg_idx >= after) curwin->w_arg_idx += count; diff --git a/src/buffer.c b/src/buffer.c index fabf5d7068597fa232d0555ce8d1394afb55e63a..210a0e80e79b16f97611e4a15ee7e049f1a49f27 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -495,13 +495,11 @@ can_unload_buffer(buf_T *buf) } return can_unload; } - int buf_locked(buf_T *buf) { return buf->b_locked || buf->b_locked_split; } - /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. @@ -1457,7 +1455,7 @@ do_buffer_ext( // (unless it's the only window). Repeat this so long as we end up in // a window with this buffer. while (buf == curbuf - && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) + && !(win_locked(curwin) || curwin->w_buffer->b_locked > 0) && (!ONE_WINDOW || first_tabpage->tp_next != NULL)) { if (win_close(curwin, FALSE) == FAIL) @@ -5444,7 +5442,7 @@ ex_buffer_all(exarg_T *eap) : wp->w_width != Columns) || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW - && !(wp->w_closing || wp->w_buffer->b_locked > 0) + && !(win_locked(wp) || wp->w_buffer->b_locked > 0) && !win_unlisted(wp)) { if (win_close(wp, FALSE) == FAIL) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 45cb6248e9d684cd0609218b2e560e3b6e55307a..459ab279488fea00ad34da8d3e2f14d4151e3e8d 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2839,7 +2839,7 @@ do_ecmd( // Set the w_closing flag to avoid that autocommands close the // window. And set b_locked for the same reason. - the_curwin->w_closing = TRUE; + the_curwin->w_locked = TRUE; ++buf->b_locked; if (curbuf == old_curbuf.br_buf) @@ -2853,7 +2853,7 @@ do_ecmd( // Autocommands may have closed the window. if (win_valid(the_curwin)) - the_curwin->w_closing = FALSE; + the_curwin->w_locked = FALSE; --buf->b_locked; #ifdef FEAT_EVAL diff --git a/src/getchar.c b/src/getchar.c index 3427a9f8da63fa65ef24b08e4eb5ff97627265b1..51842632ac9c7ec3e161cc630e10dca85b39401f 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -438,9 +438,18 @@ flush_buffers(flush_buffers_T flush_typeahead) if (flush_typeahead == FLUSH_MINIMAL) { - // remove mapped characters at the start only - typebuf.tb_off += typebuf.tb_maplen; - typebuf.tb_len -= typebuf.tb_maplen; + // remove mapped characters at the start only, + // but only when enough space left in typebuf + if (typebuf.tb_off + typebuf.tb_maplen >= typebuf.tb_buflen) + { + typebuf.tb_off = MAXMAPLEN; + typebuf.tb_len = 0; + } + else + { + typebuf.tb_off += typebuf.tb_maplen; + typebuf.tb_len -= typebuf.tb_maplen; + } #if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL) if (typebuf.tb_len == 0) typebuf_was_filled = FALSE; diff --git a/src/proto/window.pro b/src/proto/window.pro index cfb771d08e4f8a0db907d9d41711d2d0cd2f8b06..12edf0b4d387584f049f81290c9e03dd0fe9ca58 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -93,4 +93,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 win_locked(win_T *wp); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h index 3b51e0c8f18b7f8297a359eeaba87441f115028b..91f1d17a27b2d64429e7e3b92ceb17655b6a8b0d 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3744,7 +3744,7 @@ struct window_S synblock_T *w_s; // for :ownsyntax #endif - int w_closing; // window is being closed, don't let + int w_locked; // window is being closed, don't let // autocommands close it too. frame_T *w_frame; // frame containing this window diff --git a/src/terminal.c b/src/terminal.c index a641a850b0c943b963a22ba70fcdb22ad181dcb3..b7ca2b5e5f4eb43bcbbddf7067b56493ce0e0b37 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3669,10 +3669,10 @@ term_after_channel_closed(term_T *term) if (is_aucmd_win(curwin)) do_set_w_closing = TRUE; if (do_set_w_closing) - curwin->w_closing = TRUE; + curwin->w_locked = TRUE; do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); if (do_set_w_closing) - curwin->w_closing = FALSE; + curwin->w_locked = FALSE; aucmd_restbuf(&aco); } #ifdef FEAT_PROP_POPUP diff --git a/src/testdir/crash/heap_overflow3 b/src/testdir/crash/heap_overflow3 new file mode 100644 index 0000000000000000000000000000000000000000..c40adbec4d07a66bcc9aa51e40dbbb90fdc36623 Binary files /dev/null and b/src/testdir/crash/heap_overflow3 differ diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim index edc8b77429e20ac6c68c5434bb35a621b9888484..4a5d86d0ffc6ffcaa94cb35592b73b417dfc4e65 100644 --- a/src/testdir/test_arglist.vim +++ b/src/testdir/test_arglist.vim @@ -359,6 +359,7 @@ func Test_argv() call assert_equal('', argv(1, 100)) call assert_equal([], argv(-1, 100)) call assert_equal('', argv(10, -1)) + %argdelete endfunc " Test for the :argedit command @@ -744,4 +745,27 @@ func Test_all_command() %bw! endfunc +" Test for deleting buffer when creating an arglist. This was accessing freed +" memory +func Test_crash_arglist_uaf() + "%argdelete + new one + au BufAdd XUAFlocal :bw + "call assert_fails(':arglocal XUAFlocal', 'E163:') + arglocal XUAFlocal + au! BufAdd + bw! XUAFlocal + + au BufAdd XUAFlocal2 :bw + new two + new three + arglocal + argadd XUAFlocal2 Xfoobar + bw! XUAFlocal2 + bw! two + + au! BufAdd +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim index d9d9d1b439a98fe9155025e563962e7ba4784e0e..e21e484594d4b18e5cdff0010065b4f544ad13e0 100644 --- a/src/testdir/test_crash.vim +++ b/src/testdir/test_crash.vim @@ -190,6 +190,12 @@ func Test_crash1_3() call term_sendkeys(buf, args) call TermWait(buf, 150) + let file = 'crash/heap_overflow3' + let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'" + let args = printf(cmn_args, vim, file) + call term_sendkeys(buf, args) + call TermWait(buf, 150) + let file = 'crash/ex_redraw_crash' let cmn_args = "%s -u NONE -i NONE -n -m -X -Z -e -s -S %s -c ':qa!'" let args = printf(cmn_args, vim, file) diff --git a/src/version.c b/src/version.c index 2e178f3bb35a2ee33c0946c723e058ce98f33a86..3fa5a156b6a848247460c3c904ccfdc13f2a2334 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 17, /**/ 16, /**/ diff --git a/src/window.c b/src/window.c index 54e17be2db884270eecfdcb3b0908ecfc220d986..f7d423d9386e5d1e21dfcf3784834b75948007b8 100644 --- a/src/window.c +++ b/src/window.c @@ -2441,7 +2441,7 @@ close_windows( for (wp = firstwin; wp != NULL && !ONE_WINDOW; ) { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { if (win_close(wp, FALSE) == FAIL) // If closing the window fails give up, to avoid looping @@ -2462,7 +2462,7 @@ close_windows( if (tp != curtab) FOR_ALL_WINDOWS_IN_TAB(tp, wp) if (wp->w_buffer == buf - && !(wp->w_closing || wp->w_buffer->b_locked > 0)) + && !(win_locked(wp) || wp->w_buffer->b_locked > 0)) { win_close_othertab(wp, FALSE, tp); @@ -2584,10 +2584,10 @@ win_close_buffer(win_T *win, int action, int abort_if_last) bufref_T bufref; set_bufref(&bufref, curbuf); - win->w_closing = TRUE; + win->w_locked = TRUE; close_buffer(win, win->w_buffer, action, abort_if_last, TRUE); if (win_valid_any_tab(win)) - win->w_closing = FALSE; + win->w_locked = FALSE; // Make sure curbuf is valid. It can become invalid if 'bufhidden' is // "wipe". if (!bufref_valid(&bufref)) @@ -2635,7 +2635,7 @@ win_close(win_T *win, int free_buf) if (window_layout_locked(CMD_close)) return FAIL; - if (win->w_closing || (win->w_buffer != NULL + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) return FAIL; // window is already being closed if (win_unlisted(win)) @@ -2684,19 +2684,19 @@ win_close(win_T *win, int free_buf) other_buffer = TRUE; if (!win_valid(win)) return FAIL; - win->w_closing = TRUE; + win->w_locked = TRUE; apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf); if (!win_valid(win)) return FAIL; - win->w_closing = FALSE; + win->w_locked = FALSE; if (last_window()) return FAIL; } - win->w_closing = TRUE; + win->w_locked = TRUE; apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf); if (!win_valid(win)) return FAIL; - win->w_closing = FALSE; + win->w_locked = FALSE; if (last_window()) return FAIL; #ifdef FEAT_EVAL @@ -3269,7 +3269,7 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) // Get here with win->w_buffer == NULL when win_close() detects the tab // page changed. - if (win->w_closing || (win->w_buffer != NULL + if (win_locked(win) || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) return; // window is already being closed @@ -7812,3 +7812,12 @@ skip: return NULL; // no error } #endif + +/* + * Don't let autocommands close the given window + */ + int +win_locked(win_T *wp) +{ + return wp->w_locked; +}