!606 backport upstream patch to fix some bugs
From: @wangjiang37 Reviewed-by: @gaoruoshu Signed-off-by: @gaoruoshu
This commit is contained in:
commit
a60f5b131a
32
backport-patch-9.0.2106-Use-after-free-in-win_close.patch
Normal file
32
backport-patch-9.0.2106-Use-after-free-in-win_close.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 25aabc2b8ee1e19ced6f4da9d866cf9378fc4c5a Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 14 Nov 2023 19:31:34 +0100
|
||||
Subject: [PATCH] patch 9.0.2106: [security]: Use-after-free in win_close()
|
||||
|
||||
Problem: [security]: Use-after-free in win_close()
|
||||
Solution: Check window is valid, before accessing it
|
||||
|
||||
If the current window structure is no longer valid (because a previous
|
||||
autocommand has already freed this window), fail and return before
|
||||
attempting to set win->w_closing variable.
|
||||
|
||||
Add a test to trigger ASAN in CI
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/window.c | 2 ++
|
||||
1 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/window.c b/src/window.c
|
||||
index f77ede330d304..55ce31c886437 100644
|
||||
--- a/src/window.c
|
||||
+++ b/src/window.c
|
||||
@@ -2682,6 +2682,8 @@ win_close(win_T *win, int free_buf)
|
||||
reset_VIsual_and_resel(); // stop Visual mode
|
||||
|
||||
other_buffer = TRUE;
|
||||
+ if (!win_valid(win))
|
||||
+ return FAIL;
|
||||
win->w_closing = TRUE;
|
||||
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
|
||||
if (!win_valid(win))
|
||||
50
backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch
Normal file
50
backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch
Normal file
@ -0,0 +1,50 @@
|
||||
From 58f9befca1fa172068effad7f2ea5a9d6a7b0cca Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 14 Nov 2023 21:02:30 +0100
|
||||
Subject: [PATCH] patch 9.0.2109: [security]: overflow in nv_z_get_count
|
||||
|
||||
Problem: [security]: overflow in nv_z_get_count
|
||||
Solution: break out, if count is too large
|
||||
|
||||
When getting the count for a normal z command, it may overflow for large
|
||||
counts given. So verify, that we can safely store the result in a long.
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/normal.c | 7 +++++++
|
||||
src/testdir/test_normal.vim | 5 +++++
|
||||
2 files changed, 12 insertions(+)
|
||||
|
||||
diff --git a/src/normal.c b/src/normal.c
|
||||
index a06d61e6fce7d..16b4b45069329 100644
|
||||
--- a/src/normal.c
|
||||
+++ b/src/normal.c
|
||||
@@ -2562,7 +2562,14 @@ nv_z_get_count(cmdarg_T *cap, int *nchar_arg)
|
||||
if (nchar == K_DEL || nchar == K_KDEL)
|
||||
n /= 10;
|
||||
else if (VIM_ISDIGIT(nchar))
|
||||
+ {
|
||||
+ if (n > LONG_MAX / 10)
|
||||
+ {
|
||||
+ clearopbeep(cap->oap);
|
||||
+ break;
|
||||
+ }
|
||||
n = n * 10 + (nchar - '0');
|
||||
+ }
|
||||
else if (nchar == CAR)
|
||||
{
|
||||
#ifdef FEAT_GUI
|
||||
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
|
||||
index c7d37f066f208..6b889f46b3dd7 100644
|
||||
--- a/src/testdir/test_normal.vim
|
||||
+++ b/src/testdir/test_normal.vim
|
||||
@@ -4159,4 +4159,9 @@ func Test_normal33_g_cmd_nonblank()
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
+func Test_normal34_zet_large()
|
||||
+ " shouldn't cause overflow
|
||||
+ norm! z9765405999999999999
|
||||
+endfunc
|
||||
+
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
50
backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch
Normal file
50
backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch
Normal file
@ -0,0 +1,50 @@
|
||||
From 060623e4a3bc72b011e7cd92bedb3bfb64e06200 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 14 Nov 2023 21:33:29 +0100
|
||||
Subject: [PATCH] patch 9.0.2110: [security]: overflow in ex address parsing
|
||||
|
||||
Problem: [security]: overflow in ex address parsing
|
||||
Solution: Verify that lnum is positive, before substracting from
|
||||
LONG_MAX
|
||||
|
||||
[security]: overflow in ex address parsing
|
||||
|
||||
When parsing relative ex addresses one may unintentionally cause an
|
||||
overflow (because LONG_MAX - lnum will overflow for negative addresses).
|
||||
|
||||
So verify that lnum is actually positive before doing the overflow
|
||||
check.
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/ex_docmd.c | 2 +-
|
||||
src/testdir/test_excmd.vim | 4 ++++
|
||||
2 files changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
|
||||
index 06837ac92c55c..01d411a632ccf 100644
|
||||
--- a/src/ex_docmd.c
|
||||
+++ b/src/ex_docmd.c
|
||||
@@ -4644,7 +4644,7 @@ get_address(
|
||||
lnum -= n;
|
||||
else
|
||||
{
|
||||
- if (n >= LONG_MAX - lnum)
|
||||
+ if (lnum >= 0 && n >= LONG_MAX - lnum)
|
||||
{
|
||||
emsg(_(e_line_number_out_of_range));
|
||||
goto error;
|
||||
diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim
|
||||
index 3637351f636c0..47fc26726d5e6 100644
|
||||
--- a/src/testdir/test_excmd.vim
|
||||
+++ b/src/testdir/test_excmd.vim
|
||||
@@ -724,5 +724,9 @@ func Test_write_after_rename()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
+" catch address lines overflow
|
||||
+func Test_ex_address_range_overflow()
|
||||
+ call assert_fails(':--+foobar', 'E492:')
|
||||
+endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
53
backport-patch-9.0.2111-overflow-in-get_number.patch
Normal file
53
backport-patch-9.0.2111-overflow-in-get_number.patch
Normal file
@ -0,0 +1,53 @@
|
||||
From 73b2d3790cad5694fc0ed0db2926e4220c48d968 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 14 Nov 2023 21:58:26 +0100
|
||||
Subject: [PATCH] patch 9.0.2111: [security]: overflow in get_number
|
||||
|
||||
Problem: [security]: overflow in get_number
|
||||
Solution: Return 0 when the count gets too large
|
||||
|
||||
[security]: overflow in get_number
|
||||
|
||||
When using the z= command, we may overflow the count with values larger
|
||||
than MAX_INT. So verify that we do not overflow and in case when an
|
||||
overflow is detected, simply return 0
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/misc1.c | 2 ++
|
||||
src/testdir/test_spell.vim | 9 +++++++++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/src/misc1.c b/src/misc1.c
|
||||
index 5b008c614a9bb..5f9828ebe9544 100644
|
||||
--- a/src/misc1.c
|
||||
+++ b/src/misc1.c
|
||||
@@ -975,6 +975,8 @@ get_number(
|
||||
c = safe_vgetc();
|
||||
if (VIM_ISDIGIT(c))
|
||||
{
|
||||
+ if (n > INT_MAX / 10)
|
||||
+ return 0;
|
||||
n = n * 10 + c - '0';
|
||||
msg_putchar(c);
|
||||
++typed;
|
||||
diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim
|
||||
index be0bc55810f0e..1ddcd83d5117e 100644
|
||||
--- a/src/testdir/test_spell.vim
|
||||
+++ b/src/testdir/test_spell.vim
|
||||
@@ -1077,6 +1077,15 @@ func Test_spell_compatible()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
+func Test_z_equal_with_large_count()
|
||||
+ split
|
||||
+ set spell
|
||||
+ call setline(1, "ff")
|
||||
+ norm 0z=337203685477580
|
||||
+ set nospell
|
||||
+ bwipe!
|
||||
+endfunc
|
||||
+
|
||||
let g:test_data_aff1 = [
|
||||
\"SET ISO8859-1",
|
||||
\"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
|
||||
97
backport-patch-9.0.2112-overflow-in-shift_line.patch
Normal file
97
backport-patch-9.0.2112-overflow-in-shift_line.patch
Normal file
@ -0,0 +1,97 @@
|
||||
From 6bf131888a3d1de62bbfa8a7ea03c0ddccfd496e Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Tue, 14 Nov 2023 22:42:59 +0100
|
||||
Subject: [PATCH] patch 9.0.2112: [security]: overflow in shift_line
|
||||
|
||||
Problem: [security]: overflow in shift_line
|
||||
Solution: allow a max indent of INT_MAX
|
||||
|
||||
[security]: overflow in shift_line
|
||||
|
||||
When shifting lines in operator pending mode and using a very large
|
||||
value, we may overflow the size of integer. Fix this by using a long
|
||||
variable, testing if the result would be larger than INT_MAX and if so,
|
||||
indent by INT_MAX value.
|
||||
|
||||
Special case: We cannot use long here, since on 32bit architectures (or
|
||||
on Windows?), it typically cannot take larger values than a plain int,
|
||||
so we have to use long long count, decide whether the resulting
|
||||
multiplication of the shiftwidth value * amount is larger than INT_MAX
|
||||
and if so, we will store INT_MAX as possible larges value in the long
|
||||
long count variable.
|
||||
|
||||
Then we can safely cast it back to int when calling the functions to set
|
||||
the indent (set_indent() or change_indent()). So this should be safe.
|
||||
|
||||
Add a test that when using a huge value in operator pending mode for
|
||||
shifting, we will shift by INT_MAX
|
||||
|
||||
closes: #13535
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/ops.c | 15 ++++++++++-----
|
||||
src/testdir/test_indent.vim | 11 +++++++++++
|
||||
2 files changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/ops.c b/src/ops.c
|
||||
index c0a2981d68770..ecd7fc2170c58 100644
|
||||
--- a/src/ops.c
|
||||
+++ b/src/ops.c
|
||||
@@ -229,11 +229,11 @@ shift_line(
|
||||
int amount,
|
||||
int call_changed_bytes) // call changed_bytes()
|
||||
{
|
||||
- int count;
|
||||
+ long long count;
|
||||
int i, j;
|
||||
int sw_val = (int)get_sw_value_indent(curbuf);
|
||||
|
||||
- count = get_indent(); // get current indent
|
||||
+ count = (long long)get_indent(); // get current indent
|
||||
|
||||
if (round) // round off indent
|
||||
{
|
||||
@@ -260,14 +260,19 @@ shift_line(
|
||||
count = 0;
|
||||
}
|
||||
else
|
||||
- count += sw_val * amount;
|
||||
+ {
|
||||
+ if ((long long)sw_val * (long long)amount > INT_MAX - count)
|
||||
+ count = INT_MAX;
|
||||
+ else
|
||||
+ count += (long long)sw_val * (long long)amount;
|
||||
+ }
|
||||
}
|
||||
|
||||
// Set new indent
|
||||
if (State & VREPLACE_FLAG)
|
||||
- change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes);
|
||||
+ change_indent(INDENT_SET, (int)count, FALSE, NUL, call_changed_bytes);
|
||||
else
|
||||
- (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
|
||||
+ (void)set_indent((int)count, call_changed_bytes ? SIN_CHANGED : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/src/testdir/test_indent.vim b/src/testdir/test_indent.vim
|
||||
index 96e9d2300883c..217a7ae625072 100644
|
||||
--- a/src/testdir/test_indent.vim
|
||||
+++ b/src/testdir/test_indent.vim
|
||||
@@ -275,4 +275,15 @@ func Test_formatting_keeps_first_line_indent()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
+" Test for indenting with large amount, causes overflow
|
||||
+func Test_indent_overflow_count()
|
||||
+ new
|
||||
+ setl sw=8
|
||||
+ call setline(1, "abc")
|
||||
+ norm! V2147483647>
|
||||
+ " indents by INT_MAX
|
||||
+ call assert_equal(2147483647, indent(1))
|
||||
+ close!
|
||||
+endfunc
|
||||
+
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
@ -0,0 +1,94 @@
|
||||
From 22cbc8a4e17ce61aa460c451a26e1bff2c3d2af9 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Sun, 19 Nov 2023 10:47:21 +0100
|
||||
Subject: [PATCH] patch 9.0.2114: overflow detection not accurate when adding
|
||||
digits
|
||||
|
||||
Problem: overflow detection not accurate when adding digits
|
||||
Solution: Use a helper function
|
||||
|
||||
Use a helper function to better detect overflows before adding integer
|
||||
digits to a long or an integer variable respectively. Signal the
|
||||
overflow to the caller function.
|
||||
|
||||
closes: #13539
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
Signed-off-by: Michael Henry <vim@drmikehenry.com>
|
||||
Signed-off-by: Ernie Rael <errael@raelity.com>
|
||||
---
|
||||
src/misc1.c | 25 +++++++++++++++++++++++--
|
||||
src/normal.c | 3 +--
|
||||
src/proto/misc1.pro | 2 ++
|
||||
3 files changed, 26 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/misc1.c b/src/misc1.c
|
||||
index 5f9828ebe9544..dc0deae67af93 100644
|
||||
--- a/src/misc1.c
|
||||
+++ b/src/misc1.c
|
||||
@@ -975,9 +975,8 @@ get_number(
|
||||
c = safe_vgetc();
|
||||
if (VIM_ISDIGIT(c))
|
||||
{
|
||||
- if (n > INT_MAX / 10)
|
||||
+ if (vim_append_digit_int(&n, c - '0') == FAIL)
|
||||
return 0;
|
||||
- n = n * 10 + c - '0';
|
||||
msg_putchar(c);
|
||||
++typed;
|
||||
}
|
||||
@@ -2817,3 +2816,25 @@ may_trigger_modechanged(void)
|
||||
restore_v_event(v_event, &save_v_event);
|
||||
#endif
|
||||
}
|
||||
+
|
||||
+// For overflow detection, add a digit safely to an int value.
|
||||
+ int
|
||||
+vim_append_digit_int(int *value, int digit)
|
||||
+{
|
||||
+ int x = *value;
|
||||
+ if (x > ((INT_MAX - digit) / 10))
|
||||
+ return FAIL;
|
||||
+ *value = x * 10 + digit;
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
+// For overflow detection, add a digit safely to a long value.
|
||||
+ int
|
||||
+vim_append_digit_long(long *value, int digit)
|
||||
+{
|
||||
+ long x = *value;
|
||||
+ if (x > ((LONG_MAX - (long)digit) / 10))
|
||||
+ return FAIL;
|
||||
+ *value = x * 10 + (long)digit;
|
||||
+ return OK;
|
||||
+}
|
||||
diff --git a/src/normal.c b/src/normal.c
|
||||
index 16b4b45069329..61a19c13a43c9 100644
|
||||
--- a/src/normal.c
|
||||
+++ b/src/normal.c
|
||||
@@ -2563,12 +2563,11 @@ nv_z_get_count(cmdarg_T *cap, int *nchar_arg)
|
||||
n /= 10;
|
||||
else if (VIM_ISDIGIT(nchar))
|
||||
{
|
||||
- if (n > LONG_MAX / 10)
|
||||
+ if (vim_append_digit_long(&n, nchar - '0') == FAIL)
|
||||
{
|
||||
clearopbeep(cap->oap);
|
||||
break;
|
||||
}
|
||||
- n = n * 10 + (nchar - '0');
|
||||
}
|
||||
else if (nchar == CAR)
|
||||
{
|
||||
diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro
|
||||
index b87b7ea747576..2b8e9d8f264cb 100644
|
||||
--- a/src/proto/misc1.pro
|
||||
+++ b/src/proto/misc1.pro
|
||||
@@ -53,4 +53,6 @@ int path_with_url(char_u *fname);
|
||||
dict_T *get_v_event(save_v_event_T *sve);
|
||||
void restore_v_event(dict_T *v_event, save_v_event_T *sve);
|
||||
void may_trigger_modechanged(void);
|
||||
+int vim_append_digit_int(int *value, int digit);
|
||||
+int vim_append_digit_long(long *value, int digit);
|
||||
/* vim: set ft=c : */
|
||||
294
backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch
Normal file
294
backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch
Normal file
@ -0,0 +1,294 @@
|
||||
From 26c11c56888d01e298cd8044caf860f3c26f57bb Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Wed, 22 Nov 2023 21:26:41 +0100
|
||||
Subject: [PATCH] patch 9.0.2121: [security]: use-after-free in ex_substitute
|
||||
|
||||
Problem: [security]: use-after-free in ex_substitute
|
||||
Solution: always allocate memory
|
||||
|
||||
closes: #13552
|
||||
|
||||
A recursive :substitute command could cause a heap-use-after free in Vim
|
||||
(CVE-2023-48706).
|
||||
|
||||
The whole reproducible test is a bit tricky, I can only reproduce this
|
||||
reliably when no previous substitution command has been used yet
|
||||
(which is the reason, the test needs to run as first one in the
|
||||
test_substitute.vim file) and as a combination of the `:~` command
|
||||
together with a :s command that contains the special substitution atom `~\=`
|
||||
which will make use of a sub-replace special atom and calls a vim script
|
||||
function.
|
||||
|
||||
There was a comment in the existing :s code, that already makes the
|
||||
`sub` variable allocate memory so that a recursive :s call won't be able
|
||||
to cause any issues here, so this was known as a potential problem
|
||||
already. But for the current test-case that one does not work, because
|
||||
the substitution does not start with `\=` but with `~\=` (and since
|
||||
there does not yet exist a previous substitution atom, Vim will simply
|
||||
increment the `sub` pointer (which then was not allocated dynamically)
|
||||
and later one happily use a sub-replace special expression (which could
|
||||
then free the `sub` var).
|
||||
|
||||
The following commit fixes this, by making the sub var always using
|
||||
allocated memory, which also means we need to free the pointer whenever
|
||||
we leave the function. Since sub is now always an allocated variable,
|
||||
we also do no longer need the sub_copy variable anymore, since this one
|
||||
was used to indicated when sub pointed to allocated memory (and had
|
||||
therefore to be freed on exit) and when not.
|
||||
|
||||
Github Security Advisory:
|
||||
https://github.com/vim/vim/security/advisories/GHSA-c8qm-x72m-q53q
|
||||
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/ex_cmds.c | 50 ++++++++++++++++++++++++---------
|
||||
src/testdir/test_substitute.vim | 48 +++++++++++++++++++++++++++++--
|
||||
2 files changed, 83 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
|
||||
index c5f912e7ee57f..a08682b071fb5 100644
|
||||
--- a/src/ex_cmds.c
|
||||
+++ b/src/ex_cmds.c
|
||||
@@ -3737,13 +3737,13 @@ ex_substitute(exarg_T *eap)
|
||||
int save_do_all; // remember user specified 'g' flag
|
||||
int save_do_ask; // remember user specified 'c' flag
|
||||
char_u *pat = NULL, *sub = NULL; // init for GCC
|
||||
- char_u *sub_copy = NULL;
|
||||
int delimiter;
|
||||
int sublen;
|
||||
int got_quit = FALSE;
|
||||
int got_match = FALSE;
|
||||
int which_pat;
|
||||
char_u *cmd;
|
||||
+ char_u *p;
|
||||
int save_State;
|
||||
linenr_T first_line = 0; // first changed line
|
||||
linenr_T last_line= 0; // below last changed line AFTER the
|
||||
@@ -3827,8 +3827,12 @@ ex_substitute(exarg_T *eap)
|
||||
* Small incompatibility: vi sees '\n' as end of the command, but in
|
||||
* Vim we want to use '\n' to find/substitute a NUL.
|
||||
*/
|
||||
- sub = cmd; // remember the start of the substitution
|
||||
+ p = cmd; // remember the start of the substitution
|
||||
cmd = skip_substitute(cmd, delimiter);
|
||||
+ sub = vim_strsave(p);
|
||||
+ if (sub == NULL)
|
||||
+ // out of memory
|
||||
+ return;
|
||||
|
||||
if (!eap->skip)
|
||||
{
|
||||
@@ -3839,14 +3843,22 @@ ex_substitute(exarg_T *eap)
|
||||
if (old_sub == NULL) // there is no previous command
|
||||
{
|
||||
emsg(_(e_no_previous_substitute_regular_expression));
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
- sub = old_sub;
|
||||
+ vim_free(sub);
|
||||
+ sub = vim_strsave(old_sub);
|
||||
+ if (sub == NULL)
|
||||
+ // out of memory
|
||||
+ return;
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(old_sub);
|
||||
old_sub = vim_strsave(sub);
|
||||
+ if (old_sub == NULL)
|
||||
+ // out of memory
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3858,7 +3870,7 @@ ex_substitute(exarg_T *eap)
|
||||
return;
|
||||
}
|
||||
pat = NULL; // search_regcomp() will use previous pattern
|
||||
- sub = old_sub;
|
||||
+ sub = vim_strsave(old_sub);
|
||||
|
||||
// Vi compatibility quirk: repeating with ":s" keeps the cursor in the
|
||||
// last column after using "$".
|
||||
@@ -3877,7 +3889,10 @@ ex_substitute(exarg_T *eap)
|
||||
linenr_T joined_lines_count;
|
||||
|
||||
if (eap->skip)
|
||||
+ {
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
+ }
|
||||
curwin->w_cursor.lnum = eap->line1;
|
||||
if (*cmd == 'l')
|
||||
eap->flags = EXFLAG_LIST;
|
||||
@@ -3904,6 +3919,7 @@ ex_substitute(exarg_T *eap)
|
||||
save_re_pat(RE_SUBST, pat, magic_isset());
|
||||
// put pattern in history
|
||||
add_to_history(HIST_SEARCH, pat, TRUE, NUL);
|
||||
+ vim_free(sub);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -3991,6 +4007,7 @@ ex_substitute(exarg_T *eap)
|
||||
if (i <= 0 && !eap->skip && subflags.do_error)
|
||||
{
|
||||
emsg(_(e_positive_count_required));
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
else if (i >= INT_MAX)
|
||||
@@ -3998,6 +4015,7 @@ ex_substitute(exarg_T *eap)
|
||||
char buf[20];
|
||||
vim_snprintf(buf, sizeof(buf), "%ld", i);
|
||||
semsg(_(e_val_too_large), buf);
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
eap->line1 = eap->line2;
|
||||
@@ -4016,17 +4034,22 @@ ex_substitute(exarg_T *eap)
|
||||
if (eap->nextcmd == NULL)
|
||||
{
|
||||
semsg(_(e_trailing_characters_str), cmd);
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (eap->skip) // not executing commands, only parsing
|
||||
+ {
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
+ }
|
||||
|
||||
if (!subflags.do_count && !curbuf->b_p_ma)
|
||||
{
|
||||
// Substitution is not allowed in non-'modifiable' buffer
|
||||
emsg(_(e_cannot_make_changes_modifiable_is_off));
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4034,6 +4057,7 @@ ex_substitute(exarg_T *eap)
|
||||
{
|
||||
if (subflags.do_error)
|
||||
emsg(_(e_invalid_command));
|
||||
+ vim_free(sub);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4054,20 +4078,20 @@ ex_substitute(exarg_T *eap)
|
||||
*/
|
||||
if (sub[0] == '\\' && sub[1] == '=')
|
||||
{
|
||||
- sub = vim_strsave(sub);
|
||||
- if (sub == NULL)
|
||||
+ p = vim_strsave(sub);
|
||||
+ vim_free(sub);
|
||||
+ if (p == NULL)
|
||||
return;
|
||||
- sub_copy = sub;
|
||||
+ sub = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
- char_u *newsub = regtilde(sub, magic_isset());
|
||||
+ p = regtilde(sub, magic_isset());
|
||||
|
||||
- if (newsub != sub)
|
||||
+ if (p != sub)
|
||||
{
|
||||
- // newsub was allocated, free it later.
|
||||
- sub_copy = newsub;
|
||||
- sub = newsub;
|
||||
+ vim_free(sub);
|
||||
+ sub = p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4965,7 +4989,7 @@ ex_substitute(exarg_T *eap)
|
||||
#endif
|
||||
|
||||
vim_regfree(regmatch.regprog);
|
||||
- vim_free(sub_copy);
|
||||
+ vim_free(sub);
|
||||
|
||||
// Restore the flag values, they can be used for ":&&".
|
||||
subflags.do_all = save_do_all;
|
||||
diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim
|
||||
index 3ed159799f5cc..7c2bbb4767705 100644
|
||||
--- a/src/testdir/test_substitute.vim
|
||||
+++ b/src/testdir/test_substitute.vim
|
||||
@@ -4,6 +4,32 @@ source shared.vim
|
||||
source check.vim
|
||||
source screendump.vim
|
||||
|
||||
+" NOTE: This needs to be the first test to be
|
||||
+" run in the file, since it depends on
|
||||
+" that the previous substitution atom
|
||||
+" was not yet set.
|
||||
+"
|
||||
+" recursive call of :s and sub-replace special
|
||||
+" (did cause heap-use-after free in < v9.0.2121)
|
||||
+func Test_aaaa_substitute_expr_recursive_special()
|
||||
+ func R()
|
||||
+ " FIXME: leaving out the 'n' flag leaks memory, why?
|
||||
+ %s/./\='.'/gn
|
||||
+ endfunc
|
||||
+ new Xfoobar_UAF
|
||||
+ put ='abcdef'
|
||||
+ let bufnr = bufnr('%')
|
||||
+ try
|
||||
+ silent! :s/./~\=R()/0
|
||||
+ "call assert_fails(':s/./~\=R()/0', 'E939:')
|
||||
+ let @/='.'
|
||||
+ ~g
|
||||
+ catch /^Vim\%((\a\+)\)\=:E565:/
|
||||
+ endtry
|
||||
+ delfunc R
|
||||
+ exe bufnr .. "bw!"
|
||||
+endfunc
|
||||
+
|
||||
func Test_multiline_subst()
|
||||
enew!
|
||||
call append(0, ["1 aa",
|
||||
@@ -147,7 +173,6 @@ func Test_substitute_repeat()
|
||||
call feedkeys("Qsc\<CR>y", 'tx')
|
||||
bwipe!
|
||||
endfunc
|
||||
-
|
||||
" Test %s/\n// which is implemented as a special case to use a
|
||||
" more efficient join rather than doing a regular substitution.
|
||||
func Test_substitute_join()
|
||||
@@ -1447,11 +1472,30 @@ func Test_substitute_expr_switch_win()
|
||||
endfunc
|
||||
new Xfoobar
|
||||
let bufnr = bufnr('%')
|
||||
- put ="abcdef"
|
||||
+ put ='abcdef'
|
||||
silent! s/\%')/\=R()
|
||||
call assert_fails(':%s/./\=R()/g', 'E565:')
|
||||
delfunc R
|
||||
exe bufnr .. "bw!"
|
||||
endfunc
|
||||
|
||||
+" recursive call of :s using test-replace special
|
||||
+func Test_substitute_expr_recursive()
|
||||
+ func Q()
|
||||
+ %s/./\='foobar'/gn
|
||||
+ return "foobar"
|
||||
+ endfunc
|
||||
+ func R()
|
||||
+ %s/./\=Q()/g
|
||||
+ endfunc
|
||||
+ new Xfoobar_UAF
|
||||
+ let bufnr = bufnr('%')
|
||||
+ put ='abcdef'
|
||||
+ silent! s/./\=R()/g
|
||||
+ call assert_fails(':%s/./\=R()/g', 'E565:')
|
||||
+ delfunc R
|
||||
+ delfunc Q
|
||||
+ exe bufnr .. "bw!"
|
||||
+endfunc
|
||||
+
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
@ -0,0 +1,90 @@
|
||||
From df63da98d8dc284b1c76cfe1b17fa0acbd6094d8 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Brabandt <cb@256bit.org>
|
||||
Date: Thu, 23 Nov 2023 20:14:28 +0100
|
||||
Subject: [PATCH] patch 9.0.2123: Problem with initializing the length of
|
||||
range() lists
|
||||
|
||||
Problem: Problem with initializing the length of range() lists
|
||||
Solution: Set length explicitly when it shouldn't contain any items
|
||||
|
||||
range() may cause a wrong calculation of list length, which may later
|
||||
then cause a segfault in list_find(). This is usually not a problem,
|
||||
because range_list_materialize() calculates the length, when it
|
||||
materializes the list.
|
||||
|
||||
In addition, in list_find() when the length of the range was wrongly
|
||||
initialized, it may seem to be valid, so the check for list index
|
||||
out-of-bounds will not be true, because it is called before the list is
|
||||
actually materialized. And so we may eventually try to access a null
|
||||
pointer, causing a segfault.
|
||||
|
||||
So this patch does 3 things:
|
||||
|
||||
- In f_range(), when we know that the list should be empty, explicitly
|
||||
set the list->lv_len value to zero. This should happen, when
|
||||
start is larger than end (in case the stride is positive) or
|
||||
end is larger than start when the stride is negative.
|
||||
This should fix the underlying issue properly. However,
|
||||
|
||||
- as a safety measure, let's check that the requested index is not
|
||||
out of range one more time, after the list has been materialized
|
||||
and return NULL in case it suddenly is.
|
||||
|
||||
- add a few more tests to verify the behaviour.
|
||||
|
||||
fixes: #13557
|
||||
closes: #13563
|
||||
|
||||
Co-authored-by: Tim Pope <tpope@github.com>
|
||||
Signed-off-by: Christian Brabandt <cb@256bit.org>
|
||||
---
|
||||
src/evalfunc.c | 5 ++++-
|
||||
src/list.c | 4 ++++
|
||||
src/testdir/test_functions.vim | 3 +++
|
||||
3 files changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/evalfunc.c b/src/evalfunc.c
|
||||
index 7f7914eca7d91..fa27d0d274a64 100644
|
||||
--- a/src/evalfunc.c
|
||||
+++ b/src/evalfunc.c
|
||||
@@ -8646,7 +8646,10 @@ f_range(typval_T *argvars, typval_T *rettv)
|
||||
list->lv_u.nonmat.lv_start = start;
|
||||
list->lv_u.nonmat.lv_end = end;
|
||||
list->lv_u.nonmat.lv_stride = stride;
|
||||
- list->lv_len = (end - start) / stride + 1;
|
||||
+ if (stride > 0 ? end < start : end > start)
|
||||
+ list->lv_len = 0;
|
||||
+ else
|
||||
+ list->lv_len = (end - start) / stride + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/src/list.c b/src/list.c
|
||||
index d1494c67d56e9..ce1ccaa1c045c 100644
|
||||
--- a/src/list.c
|
||||
+++ b/src/list.c
|
||||
@@ -415,6 +415,10 @@ list_find(list_T *l, long n)
|
||||
|
||||
CHECK_LIST_MATERIALIZE(l);
|
||||
|
||||
+ // range_list_materialize may reset l->lv_len
|
||||
+ if (n >= l->lv_len)
|
||||
+ return NULL;
|
||||
+
|
||||
// When there is a cached index may start search from there.
|
||||
if (l->lv_u.mat.lv_idx_item != NULL)
|
||||
{
|
||||
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
|
||||
index 49b688c25f347..0801d2b695b76 100644
|
||||
--- a/src/testdir/test_functions.vim
|
||||
+++ b/src/testdir/test_functions.vim
|
||||
@@ -3052,6 +3052,9 @@ func Test_range()
|
||||
" get()
|
||||
call assert_equal(4, get(range(1, 10), 3))
|
||||
call assert_equal(-1, get(range(1, 10), 42, -1))
|
||||
+ call assert_equal(0, get(range(1, 0, 2), 0))
|
||||
+ call assert_equal(0, get(range(0, -1, 2), 0))
|
||||
+ call assert_equal(0, get(range(-2, -1, -2), 0))
|
||||
|
||||
" index()
|
||||
call assert_equal(1, index(range(1, 5), 2))
|
||||
28
vim.spec
28
vim.spec
@ -14,7 +14,7 @@
|
||||
Name: vim
|
||||
Epoch: 2
|
||||
Version: %{baseversion}.%{patchlevel}
|
||||
Release: 2
|
||||
Release: 3
|
||||
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
|
||||
@ -24,11 +24,21 @@ Source2: vimrc
|
||||
|
||||
Patch0000: vim-7.0-fixkeys.patch
|
||||
Patch0001: vim-7.4-specsyntax.patch
|
||||
Patch0006: vim-7.4-fstabsyntax.patch
|
||||
Patch0009: vim-7.4-globalsyntax.patch
|
||||
Patch0011: vim-8.0-copy-paste.patch
|
||||
Patch0012: vim-python3-tests.patch
|
||||
Patch0013: bugfix-security-overflow-with-count-for-s-command.patch
|
||||
Patch0002: vim-7.4-fstabsyntax.patch
|
||||
Patch0003: vim-7.4-globalsyntax.patch
|
||||
Patch0004: vim-8.0-copy-paste.patch
|
||||
Patch0005: vim-python3-tests.patch
|
||||
|
||||
|
||||
Patch6000: bugfix-security-overflow-with-count-for-s-command.patch
|
||||
Patch6001: backport-patch-9.0.2106-Use-after-free-in-win_close.patch
|
||||
Patch6002: backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch
|
||||
Patch6003: backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch
|
||||
Patch6004: backport-patch-9.0.2111-overflow-in-get_number.patch
|
||||
Patch6005: backport-patch-9.0.2112-overflow-in-shift_line.patch
|
||||
Patch6006: backport-patch-9.0.2114-overflow-detection-not-accurate-when-adding.patch
|
||||
Patch6007: backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch
|
||||
Patch6008: backport-patch-9.0.2123-Problem-with-initializing-the-length-of-range-lists.patch
|
||||
|
||||
Patch9000: bugfix-rm-modify-info-version.patch
|
||||
|
||||
@ -436,6 +446,12 @@ LC_ALL=en_US.UTF-8 make -j1 test || echo "Warning: Please check tests."
|
||||
%{_mandir}/man1/evim.*
|
||||
|
||||
%changelog
|
||||
* Sat May 11 2024 wangjiang <wangjiang37@h-partners.com> - 2:9.0.2092-3
|
||||
- Type:bugfix
|
||||
- ID:NA
|
||||
- SUG:NA
|
||||
- DESC:backport upstream patch to fix some bugs
|
||||
|
||||
* Wed May 08 2024 yinyongkang <yinyongkang@kylinos.cn> - 2:9.0.2092-2
|
||||
- Type:bugfix
|
||||
- ID:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user