fix CVE-2024-41957 CVE-2024-41965

(cherry picked from commit dfd9ba28525f88a2925ba262ff92fb9c9c744969)
This commit is contained in:
wangjiang 2024-08-12 10:32:08 +08:00 committed by openeuler-sync-bot
parent 1c1b25159b
commit cb40e35e81
6 changed files with 572 additions and 1 deletions

View File

@ -0,0 +1,43 @@
From 8a0bbe7b8aad6f8da28dee218c01bc8a0185a2d5 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <cb@256bit.org>
Date: Thu, 1 Aug 2024 20:16:51 +0200
Subject: [PATCH] patch 9.1.0647: [security] use-after-free in
tagstack_clear_entry
Problem: [security] use-after-free in tagstack_clear_entry
(Suyue Guo )
Solution: Instead of manually calling vim_free() on each of the tagstack
entries, let's use tagstack_clear_entry(), which will
also free the stack, but using the VIM_CLEAR macro,
which prevents a use-after-free by setting those pointers
to NULL
This addresses CVE-2024-41957
Github advisory:
https://github.com/vim/vim/security/advisories/GHSA-f9cr-gv85-hcr4
Signed-off-by: Christian Brabandt <cb@256bit.org>
---
src/window.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/window.c b/src/window.c
index 7ca29d46a..70c72bca7 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5661,10 +5661,7 @@ win_free(
win_free_lsize(wp);
for (i = 0; i < wp->w_tagstacklen; ++i)
- {
- vim_free(wp->w_tagstack[i].tagname);
- vim_free(wp->w_tagstack[i].user_data);
- }
+ tagstack_clear_entry(&wp->w_tagstack[i]);
vim_free(wp->w_localdir);
vim_free(wp->w_prevdir);
--
2.33.0

View File

@ -0,0 +1,42 @@
From b29f4abcd4b3382fa746edd1d0562b7b48c9de60 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <cb@256bit.org>
Date: Thu, 1 Aug 2024 22:10:28 +0200
Subject: [PATCH] patch 9.1.0648: [security] double-free in dialog_changed()
Problem: [security] double-free in dialog_changed()
(SuyueGuo)
Solution: Only clear pointer b_sfname pointer, if it is different
than the b_ffname pointer. Don't try to free b_fname,
set it to NULL instead.
fixes: #15403
Github Advisory:
https://github.com/vim/vim/security/advisories/GHSA-46pw-v7qw-xc2f
Signed-off-by: Christian Brabandt <cb@256bit.org>
---
src/ex_cmds2.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index ce30b8d39..0d76b3b27 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -197,9 +197,11 @@ dialog_changed(
// restore to empty when write failed
if (empty_bufname)
{
- VIM_CLEAR(buf->b_fname);
+ // prevent double free
+ if (buf->b_sfname != buf->b_ffname)
+ VIM_CLEAR(buf->b_sfname);
+ buf->b_fname = NULL;
VIM_CLEAR(buf->b_ffname);
- VIM_CLEAR(buf->b_sfname);
unchanged(buf, TRUE, FALSE);
}
}
--
2.33.0

View File

@ -0,0 +1,171 @@
From df46115fc839c8912ed60646e86a412e5180ba1d Mon Sep 17 00:00:00 2001
From: glepnir <glephunter@gmail.com>
Date: Thu, 4 Apr 2024 22:23:29 +0200
Subject: [PATCH] patch 9.1.0265: console dialog cannot save unnamed buffers
Problem: console dialog cannot save unnamed buffers
Solution: set bufname before save (glepnir). Define dialog_con_gui
to test for GUI+Console dialog support, use it to skip
the test when the GUI feature has been defined.
Note: The dialog_changed() function will also try to call the
browse_save_fname() function, when FEAT_BROWSE is defined (which is only
defined in a GUI build of Vim). This will eventually lead to a call of
do_browse(), which causes an error message if a GUI is not currently
running (see the TODO: in do_browse()) and will then lead to a failure
in Test_goto_buf_with_onfirm().
Therefore, we must disable the Test_goto_buf_with_onfirm(), when the
dialog_con_gui feature is enabled (which basically means dialog feature
for GUI and Console builds, in contrast to the dialog_con and dialog_gui
feature).
(Previously this wasn't a problem, because the test aborted in the YES
case for the :confirm :b XgotoConf case and did therefore not run into
the browse function call)
closes: #14398
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
---
runtime/doc/builtin.txt | 5 +++--
src/evalfunc.c | 7 +++++++
src/ex_cmds2.c | 26 ++++++++++++++++++++++----
src/testdir/test_buffer.vim | 21 +++++++++++++++------
4 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 6a4c8d981..fb7c794f6 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt* For Vim version 9.0. Last change: 2023 Sep 27
+*builtin.txt* For Vim version 9.1. Last change: 2024 Apr 04
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1761,7 +1761,7 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
made. It returns the number of the choice. For the first
choice this is 1.
Note: confirm() is only supported when compiled with dialog
- support, see |+dialog_con| and |+dialog_gui|.
+ support, see |+dialog_con| |+dialog_con_gui| and |+dialog_gui|.
{msg} is displayed in a |dialog| with {choices} as the
alternatives. When {choices} is missing or empty, "&OK" is
@@ -10912,6 +10912,7 @@ cscope Compiled with |cscope| support.
cursorbind Compiled with |'cursorbind'| (always true)
debug Compiled with "DEBUG" defined.
dialog_con Compiled with console dialog support.
+dialog_con_gui Compiled with console and GUI dialog support.
dialog_gui Compiled with GUI dialog support.
diff Compiled with |vimdiff| and 'diff' support.
digraphs Compiled with support for digraphs.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 0e071d87b..20649828e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5792,6 +5792,13 @@ f_has(typval_T *argvars, typval_T *rettv)
1
#else
0
+#endif
+ },
+ {"dialog_con_gui",
+#if defined(FEAT_CON_DIALOG) && defined(FEAT_GUI_DIALOG)
+ 1
+#else
+ 0
#endif
},
{"dialog_gui",
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 4a6f51923..a75bfc11c 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -163,7 +163,8 @@ dialog_changed(
char_u buff[DIALOG_MSG_SIZE];
int ret;
buf_T *buf2;
- exarg_T ea;
+ exarg_T ea;
+ int empty_buf = buf->b_fname == NULL ? TRUE : FALSE;
dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
if (checkall)
@@ -181,10 +182,27 @@ dialog_changed(
// May get file name, when there is none
browse_save_fname(buf);
#endif
- if (buf->b_fname != NULL && check_overwrite(&ea, buf,
- buf->b_fname, buf->b_ffname, FALSE) == OK)
+ if (empty_buf)
+ buf_set_name(buf->b_fnum, (char_u *)"Untitled");
+
+ if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, FALSE) == OK)
+ {
// didn't hit Cancel
- (void)buf_write_all(buf, FALSE);
+ if (buf_write_all(buf, FALSE) == OK)
+ return;
+ }
+
+ // restore to empty when write failed
+ if (empty_buf)
+ {
+ vim_free(buf->b_fname);
+ buf->b_fname = NULL;
+ vim_free(buf->b_ffname);
+ buf->b_ffname = NULL;
+ vim_free(buf->b_sfname);
+ buf->b_sfname = NULL;
+ unchanged(buf, TRUE, FALSE);
+ }
}
else if (ret == VIM_NO)
{
diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim
index a5643b3bb..de088bd8e 100644
--- a/src/testdir/test_buffer.vim
+++ b/src/testdir/test_buffer.vim
@@ -252,21 +252,30 @@ func Test_goto_buf_with_confirm()
CheckUnix
CheckNotGui
CheckFeature dialog_con
+ " When dialog_con_gui is defined, Vim is compiled with GUI support
+ " and FEAT_BROWSE will be defined, which causes :confirm :b to
+ " call do_browse(), which will try to use a GUI file browser,
+ " which aborts if a GUI is not available.
+ CheckNotFeature dialog_con_gui
new XgotoConf
enew
call setline(1, 'test')
call assert_fails('b XgotoConf', 'E37:')
call feedkeys('c', 'L')
call assert_fails('confirm b XgotoConf', 'E37:')
- call assert_equal(1, &modified)
- call assert_equal('', @%)
+ call assert_true(&modified)
+ call assert_true(empty(bufname('%')))
call feedkeys('y', 'L')
- call assert_fails('confirm b XgotoConf', ['', 'E37:'])
- call assert_equal(1, &modified)
- call assert_equal('', @%)
+ confirm b XgotoConf
+ call assert_equal('XgotoConf', bufname('%'))
+ call assert_equal(['test'], readfile('Untitled'))
+ e Untitled
+ call setline(2, 'test2')
call feedkeys('n', 'L')
confirm b XgotoConf
- call assert_equal('XgotoConf', @%)
+ call assert_equal('XgotoConf', bufname('%'))
+ call assert_equal(['test'], readfile('Untitled'))
+ call delete('Untitled')
close!
endfunc
--
2.33.0

View File

@ -0,0 +1,67 @@
From c20bdf1107d48a1c14713709d12d429e761132af Mon Sep 17 00:00:00 2001
From: zeertzjq <zeertzjq@outlook.com>
Date: Fri, 5 Apr 2024 20:02:55 +0200
Subject: [PATCH] patch 9.1.0267: File name entered in GUI dialog is ignored
Problem: File name entered in GUI dialog is ignored (after v9.1.0265)
Solution: Only set file name to "Untitled" if GUI dialog didn't set it.
(zeertzjq)
closes: #14417
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
---
src/ex_cmds2.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index a75bfc11c..ce30b8d39 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -164,7 +164,6 @@ dialog_changed(
int ret;
buf_T *buf2;
exarg_T ea;
- int empty_buf = buf->b_fname == NULL ? TRUE : FALSE;
dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
if (checkall)
@@ -178,11 +177,14 @@ dialog_changed(
if (ret == VIM_YES)
{
+ int empty_bufname;
+
#ifdef FEAT_BROWSE
// May get file name, when there is none
browse_save_fname(buf);
#endif
- if (empty_buf)
+ empty_bufname = buf->b_fname == NULL ? TRUE : FALSE;
+ if (empty_bufname)
buf_set_name(buf->b_fnum, (char_u *)"Untitled");
if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, FALSE) == OK)
@@ -193,14 +195,11 @@ dialog_changed(
}
// restore to empty when write failed
- if (empty_buf)
+ if (empty_bufname)
{
- vim_free(buf->b_fname);
- buf->b_fname = NULL;
- vim_free(buf->b_ffname);
- buf->b_ffname = NULL;
- vim_free(buf->b_sfname);
- buf->b_sfname = NULL;
+ VIM_CLEAR(buf->b_fname);
+ VIM_CLEAR(buf->b_ffname);
+ VIM_CLEAR(buf->b_sfname);
unchanged(buf, TRUE, FALSE);
}
}
--
2.33.0

View File

@ -0,0 +1,237 @@
From 4ff3a9b1e3ba45f9dbd0ea8c721f27d9315c4d93 Mon Sep 17 00:00:00 2001
From: LemonBoy <thatlemon@gmail.com>
Date: Tue, 9 Jul 2024 20:03:24 +0200
Subject: [PATCH] patch 9.1.0554: :bw leaves jumplist and tagstack data around
Problem: :bw leaves jumplist and tagstack data around
(Paul "Joey" Clark)
Solution: Wipe jumplist and tagstack references to the wiped buffer
(LemonBoy)
As documented the :bwipeout command brutally deletes all the references
to the buffer, so let's make it delete all the entries in the jump list
and tag stack referring to the wiped-out buffer.
fixes: #8201
closes: #15185
Signed-off-by: LemonBoy <thatlemon@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
---
runtime/doc/version9.txt | 1 +
runtime/doc/windows.txt | 5 +++--
src/buffer.c | 5 +++++
src/mark.c | 34 ++++++++++++++++++++++++++++++++++
src/proto/mark.pro | 1 +
src/proto/tag.pro | 1 +
src/tag.c | 3 +--
src/testdir/test_jumplist.vim | 22 ++++++----------------
src/testdir/test_tagjump.vim | 17 +++++++++++++++++
9 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 9cf20300f..df56215ea 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -31701,6 +31701,7 @@ Other improvements *new-other-9.1*
Changed *changed-9.1*
-------
+- |:bwipe| also wipes jumplist and tagstack data
Added *added-9.1*
-----
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index e264e5117..d3e5f6785 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -1,4 +1,4 @@
-*windows.txt* For Vim version 9.0. Last change: 2022 Nov 27
+*windows.txt* For Vim version 9.1. Last change: 2024 Jul 09
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1225,7 +1225,8 @@ list of buffers. |unlisted-buffer|
:bw[ipeout][!] N1 N2 ...
Like |:bdelete|, but really delete the buffer. Everything
related to the buffer is lost. All marks in this buffer
- become invalid, option settings are lost, etc. Don't use this
+ become invalid, option settings are lost, the jumplist and
+ tagstack data will be purged, etc. Don't use this
unless you know what you are doing. Examples: >
:.+,$bwipeout " wipe out all buffers after the current
" one
diff --git a/src/buffer.c b/src/buffer.c
index cbec9b980..28967342d 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -750,10 +750,15 @@ aucmd_abort:
*/
if (wipe_buf)
{
+ win_T *wp;
+
// Do not wipe out the buffer if it is used in a window.
if (buf->b_nwindows > 0)
return FALSE;
+ FOR_ALL_WINDOWS(wp)
+ mark_forget_file(wp, buf->b_fnum);
+
if (action == DOBUF_WIPE_REUSE)
{
// we can re-use this buffer number, store it
diff --git a/src/mark.c b/src/mark.c
index 22e3c6257..85f7b68e2 100644
--- a/src/mark.c
+++ b/src/mark.c
@@ -129,6 +129,40 @@ setmark_pos(int c, pos_T *pos, int fnum)
return FAIL;
}
+/*
+ * Delete every entry referring to file 'fnum' from both the jumplist and the
+ * tag stack.
+ */
+ void
+mark_forget_file(win_T *wp, int fnum)
+{
+ int i;
+
+ for (i = 0; i < wp->w_jumplistlen; ++i)
+ if (wp->w_jumplist[i].fmark.fnum == fnum)
+ {
+ vim_free(wp->w_jumplist[i].fname);
+ mch_memmove(&wp->w_jumplist[i], &wp->w_jumplist[i + 1],
+ (wp->w_jumplistlen - i - 1) * sizeof(xfmark_T));
+ if (wp->w_jumplistidx > i)
+ --wp->w_jumplistidx;
+ --wp->w_jumplistlen;
+ --i;
+ }
+
+ for (i = 0; i < wp->w_tagstacklen; i++)
+ if (wp->w_tagstack[i].fmark.fnum == fnum)
+ {
+ tagstack_clear_entry(&wp->w_tagstack[i]);
+ mch_memmove(&wp->w_tagstack[i], &wp->w_tagstack[i + 1],
+ (wp->w_tagstacklen - i - 1) * sizeof(taggy_T));
+ if (wp->w_tagstackidx > i)
+ --wp->w_tagstackidx;
+ --wp->w_tagstacklen;
+ --i;
+ }
+}
+
/*
* Set the previous context mark to the current position and add it to the
* jump list.
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
index cc45f0d3c..d398c3677 100644
--- a/src/proto/mark.pro
+++ b/src/proto/mark.pro
@@ -28,4 +28,5 @@ void set_last_cursor(win_T *win);
void free_all_marks(void);
xfmark_T *get_namedfm(void);
void f_getmarklist(typval_T *argvars, typval_T *rettv);
+void mark_forget_file(win_T *wp, int fnum);
/* vim: set ft=c : */
diff --git a/src/proto/tag.pro b/src/proto/tag.pro
index 6de463e92..eec7c24ed 100644
--- a/src/proto/tag.pro
+++ b/src/proto/tag.pro
@@ -14,4 +14,5 @@ int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file);
int get_tags(list_T *list, char_u *pat, char_u *buf_fname);
void get_tagstack(win_T *wp, dict_T *retdict);
int set_tagstack(win_T *wp, dict_T *d, int action);
+void tagstack_clear_entry(taggy_T *item);
/* vim: set ft=c : */
diff --git a/src/tag.c b/src/tag.c
index d406fdec1..57f9fe016 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -144,7 +144,6 @@ static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_
#if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
static int add_llist_tags(char_u *tag, int num_matches, char_u **matches);
#endif
-static void tagstack_clear_entry(taggy_T *item);
static char_u *tagmatchname = NULL; // name of last used tag
@@ -4225,7 +4224,7 @@ find_extra(char_u **pp)
/*
* Free a single entry in a tag stack
*/
- static void
+ void
tagstack_clear_entry(taggy_T *item)
{
VIM_CLEAR(item->tagname);
diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim
index 8fbf39f55..0f43a8c6e 100644
--- a/src/testdir/test_jumplist.vim
+++ b/src/testdir/test_jumplist.vim
@@ -62,26 +62,16 @@ endfunc
func Test_jumplist_invalid()
new
clearjumps
- " put some randome text
- put ='a'
- let prev = bufnr('%')
+ " Put some random text and fill the jump list.
+ call setline(1, ['foo', 'bar', 'baz'])
+ normal G
+ normal gg
setl nomodified bufhidden=wipe
e XXJumpListBuffer
- let bnr = bufnr('%')
- " 1) empty jumplist
- let expected = [[
- \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1]
- call assert_equal(expected, getjumplist())
+ " The jump list is empty as the buffer was wiped out.
+ call assert_equal([[], 0], getjumplist())
let jumps = execute(':jumps')
call assert_equal('>', jumps[-1:])
- " now jump back
- exe ":norm! \<c-o>"
- let expected = [[
- \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0},
- \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 0]
- call assert_equal(expected, getjumplist())
- let jumps = execute(':jumps')
- call assert_match('> 0 2 0 -invalid-', jumps)
endfunc
" Test for '' mark in an empty buffer
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
index 432906efb..71237855c 100644
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -943,6 +943,23 @@ func Test_tag_stack()
call settagstack(1, {'items' : []})
call assert_fails('pop', 'E73:')
+ " References to wiped buffer are deleted.
+ for i in range(10, 20)
+ edit Xtest
+ exe "tag var" .. i
+ endfor
+ edit Xtest
+
+ let t = gettagstack()
+ call assert_equal(11, t.length)
+ call assert_equal(12, t.curidx)
+
+ bwipe!
+
+ let t = gettagstack()
+ call assert_equal(0, t.length)
+ call assert_equal(1, t.curidx)
+
set tags&
%bwipe
endfunc
--
2.33.0

View File

@ -14,7 +14,7 @@
Name: vim
Epoch: 2
Version: %{baseversion}.%{patchlevel}
Release: 7
Release: 8
Summary: Vim is a highly configurable text editor for efficiently creating and changing any kind of text.
License: Vim and MIT
URL: http://www.vim.org
@ -42,6 +42,11 @@ Patch6008: backport-patch-9.0.2123-Problem-with-initializing-the-length-of-
Patch6009: backport-vim-7.0-rclocation.patch
Patch6010: backport-CVE-2024-22667.patch
Patch6011: backport-CVE-2023-48232.patch
Patch6012: backport-patch-9.1.0265-console-dialog-cannot-save-unnamed-bu.patch
Patch6013: backport-patch-9.1.0267-File-name-entered-in-GUI-dialog-is-ig.patch
Patch6014: backport-CVE-2024-41965.patch
Patch6015: backport-patch-9.1.0554-bw-leaves-jumplist-and-tagstack-data-.patch
Patch6016: backport-CVE-2024-41957.patch
Patch9000: bugfix-rm-modify-info-version.patch
@ -449,6 +454,12 @@ LC_ALL=en_US.UTF-8 make -j1 test || echo "Warning: Please check tests."
%{_mandir}/man1/evim.*
%changelog
* Tue Aug 06 2024 wangjiang <wangjiang37@h-partners.com> - 2:9.0.2092-8
- Type:CVE
- ID:CVE-2024-41957 CVE-2024-41965
- SUG:NA
- DESC:fix CVE-2024-41957 CVE-2024-41965
* Mon Jul 29 2024 Funda Wang <fundawang@yeah.net> - 2:9.0.2092-7
- Type:enhacement
- ID:NA