From 831b9b2a5c0b377148a3de51f1aa9db8ff3d998b Mon Sep 17 00:00:00 2001 From: wangjiang Date: Sat, 11 May 2024 17:15:06 +0800 Subject: [PATCH] backport upstream patch to fix some bugs --- ...9.0.2106-Use-after-free-in-win_close.patch | 32 ++ ...-9.0.2109-overflow-in-nv_z_get_count.patch | 50 +++ ....2110-overflow-in-ex-address-parsing.patch | 50 +++ ...atch-9.0.2111-overflow-in-get_number.patch | 53 ++++ ...atch-9.0.2112-overflow-in-shift_line.patch | 97 ++++++ ...w-detection-not-accurate-when-adding.patch | 94 ++++++ ...2121-use-after-free-in-ex_substitute.patch | 294 ++++++++++++++++++ ...itializing-the-length-of-range-lists.patch | 90 ++++++ vim.spec | 28 +- 9 files changed, 782 insertions(+), 6 deletions(-) create mode 100644 backport-patch-9.0.2106-Use-after-free-in-win_close.patch create mode 100644 backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch create mode 100644 backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch create mode 100644 backport-patch-9.0.2111-overflow-in-get_number.patch create mode 100644 backport-patch-9.0.2112-overflow-in-shift_line.patch create mode 100644 backport-patch-9.0.2114-overflow-detection-not-accurate-when-adding.patch create mode 100644 backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch create mode 100644 backport-patch-9.0.2123-Problem-with-initializing-the-length-of-range-lists.patch diff --git a/backport-patch-9.0.2106-Use-after-free-in-win_close.patch b/backport-patch-9.0.2106-Use-after-free-in-win_close.patch new file mode 100644 index 0000000..dc98657 --- /dev/null +++ b/backport-patch-9.0.2106-Use-after-free-in-win_close.patch @@ -0,0 +1,32 @@ +From 25aabc2b8ee1e19ced6f4da9d866cf9378fc4c5a Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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)) diff --git a/backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch b/backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch new file mode 100644 index 0000000..1aa3049 --- /dev/null +++ b/backport-patch-9.0.2109-overflow-in-nv_z_get_count.patch @@ -0,0 +1,50 @@ +From 58f9befca1fa172068effad7f2ea5a9d6a7b0cca Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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 diff --git a/backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch b/backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch new file mode 100644 index 0000000..0076e73 --- /dev/null +++ b/backport-patch-9.0.2110-overflow-in-ex-address-parsing.patch @@ -0,0 +1,50 @@ +From 060623e4a3bc72b011e7cd92bedb3bfb64e06200 Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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 diff --git a/backport-patch-9.0.2111-overflow-in-get_number.patch b/backport-patch-9.0.2111-overflow-in-get_number.patch new file mode 100644 index 0000000..98728b3 --- /dev/null +++ b/backport-patch-9.0.2111-overflow-in-get_number.patch @@ -0,0 +1,53 @@ +From 73b2d3790cad5694fc0ed0db2926e4220c48d968 Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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", diff --git a/backport-patch-9.0.2112-overflow-in-shift_line.patch b/backport-patch-9.0.2112-overflow-in-shift_line.patch new file mode 100644 index 0000000..a5cde61 --- /dev/null +++ b/backport-patch-9.0.2112-overflow-in-shift_line.patch @@ -0,0 +1,97 @@ +From 6bf131888a3d1de62bbfa8a7ea03c0ddccfd496e Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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 diff --git a/backport-patch-9.0.2114-overflow-detection-not-accurate-when-adding.patch b/backport-patch-9.0.2114-overflow-detection-not-accurate-when-adding.patch new file mode 100644 index 0000000..2e05e10 --- /dev/null +++ b/backport-patch-9.0.2114-overflow-detection-not-accurate-when-adding.patch @@ -0,0 +1,94 @@ +From 22cbc8a4e17ce61aa460c451a26e1bff2c3d2af9 Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +Signed-off-by: Michael Henry +Signed-off-by: Ernie Rael +--- + 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 : */ diff --git a/backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch b/backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch new file mode 100644 index 0000000..86354d3 --- /dev/null +++ b/backport-patch-9.0.2121-use-after-free-in-ex_substitute.patch @@ -0,0 +1,294 @@ +From 26c11c56888d01e298cd8044caf860f3c26f57bb Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +--- + 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\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 diff --git a/backport-patch-9.0.2123-Problem-with-initializing-the-length-of-range-lists.patch b/backport-patch-9.0.2123-Problem-with-initializing-the-length-of-range-lists.patch new file mode 100644 index 0000000..e062058 --- /dev/null +++ b/backport-patch-9.0.2123-Problem-with-initializing-the-length-of-range-lists.patch @@ -0,0 +1,90 @@ +From df63da98d8dc284b1c76cfe1b17fa0acbd6094d8 Mon Sep 17 00:00:00 2001 +From: Christian Brabandt +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 +Signed-off-by: Christian Brabandt +--- + 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)) diff --git a/vim.spec b/vim.spec index 8718dc5..98b0c8c 100644 --- a/vim.spec +++ b/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 - 2:9.0.2092-3 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:backport upstream patch to fix some bugs + * Wed May 08 2024 yinyongkang - 2:9.0.2092-2 - Type:bugfix - ID:NA -- Gitee