From 8dc216e68ba7f5ade36c0864f26953bac84c1f6e Mon Sep 17 00:00:00 2001 From: shixuantong <1726671442@qq.com> Date: Wed, 20 Jul 2022 14:36:51 +0800 Subject: [PATCH] fix CVE-2022-2343 --- backport-CVE-2022-2343.patch | 233 +++++++++++++++++ ...nsert-completion-code-is-too-complic.patch | 239 ++++++++++++++++++ vim.spec | 10 +- 3 files changed, 481 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2022-2343.patch create mode 100644 backport-patch-8.2.3953-insert-completion-code-is-too-complic.patch diff --git a/backport-CVE-2022-2343.patch b/backport-CVE-2022-2343.patch new file mode 100644 index 0000000..ff6e162 --- /dev/null +++ b/backport-CVE-2022-2343.patch @@ -0,0 +1,233 @@ +From caea66442d86e7bbba3bf3dc202c3c0d549b9853 Mon Sep 17 00:00:00 2001 +From: Bram Moolenaar +Date: Thu, 7 Jul 2022 19:42:04 +0100 +Subject: [PATCH] patch 9.0.0045: reading past end of completion with a long + line + +Problem: Reading past end of completion with a long line and 'infercase' +set. +Solution: Allocate the string if needed. +--- + src/insexpand.c | 96 +++++++++++++++++++++++++++------------ + src/testdir/test_ins_complete.vim | 14 ++++++ + 2 files changed, 81 insertions(+), 29 deletions(-) + +diff --git a/src/insexpand.c b/src/insexpand.c +index 3b4d530..e8ba82e 100644 +--- a/src/insexpand.c ++++ b/src/insexpand.c +@@ -408,29 +408,32 @@ ins_compl_accept_char(int c) + + /* + * Get the completed text by inferring the case of the originally typed text. ++ * If the result is in allocated memory "tofree" is set to it. + */ + static char_u * + ins_compl_infercase_gettext( + char_u *str, +- int actual_len, +- int actual_compl_length, +- int min_len) ++ int char_len, ++ int compl_char_len, ++ int min_len, ++ char_u **tofree) + { + int *wca; // Wide character array. + char_u *p; + int i, c; + int has_lower = FALSE; + int was_letter = FALSE; ++ garray_T gap; + +- IObuff[0] = NUL; ++ vim_memset(IObuff, NUL, IOSIZE * sizeof(char_u)); + + // Allocate wide character array for the completion and fill it. +- wca = ALLOC_MULT(int, actual_len); ++ wca = ALLOC_MULT(int, char_len); + if (wca == NULL) + return IObuff; + + p = str; +- for (i = 0; i < actual_len; ++i) ++ for (i = 0; i < char_len; ++i) + if (has_mbyte) + wca[i] = mb_ptr2char_adv(&p); + else +@@ -450,7 +453,7 @@ ins_compl_infercase_gettext( + if (MB_ISUPPER(wca[i])) + { + // Rule 1 is satisfied. +- for (i = actual_compl_length; i < actual_len; ++i) ++ for (i = compl_char_len; i < char_len; ++i) + wca[i] = MB_TOLOWER(wca[i]); + break; + } +@@ -471,7 +474,7 @@ ins_compl_infercase_gettext( + if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) + { + // Rule 2 is satisfied. +- for (i = actual_compl_length; i < actual_len; ++i) ++ for (i = compl_char_len; i < char_len; ++i) + wca[i] = MB_TOUPPER(wca[i]); + break; + } +@@ -494,20 +497,52 @@ ins_compl_infercase_gettext( + } + + // Generate encoding specific output from wide character array. +- // Multi-byte characters can occupy up to five bytes more than +- // ASCII characters, and we also need one byte for NUL, so stay +- // six bytes away from the edge of IObuff. + p = IObuff; + i = 0; +- while (i < actual_len && (p - IObuff + 6) < IOSIZE) +- if (has_mbyte) ++ ga_init2(&gap, 1, 500); ++ while (i < char_len) ++ { ++ if (gap.ga_data != NULL) ++ { ++ if (ga_grow(&gap, 10) == FAIL) ++ { ++ ga_clear(&gap); ++ return (char_u *)"[failed]"; ++ } ++ p = (char_u *)gap.ga_data + gap.ga_len; ++ if (has_mbyte) ++ gap.ga_len += (*mb_char2bytes)(wca[i++], p); ++ else ++ { ++ *p = wca[i++]; ++ ++gap.ga_len; ++ } ++ } ++ else if ((p - IObuff) + 6 >= IOSIZE) ++ { ++ // Multi-byte characters can occupy up to five bytes more than ++ // ASCII characters, and we also need one byte for NUL, so when ++ // getting to six bytes from the edge of IObuff switch to using a ++ // growarray. Add the character in the next round. ++ if (ga_grow(&gap, IOSIZE) == FAIL) ++ return (char_u *)"[failed]"; ++ STRCPY(gap.ga_data, IObuff); ++ gap.ga_len = STRLEN(IObuff); ++ } ++ else if (has_mbyte) + p += (*mb_char2bytes)(wca[i++], p); + else + *(p++) = wca[i++]; +- *p = NUL; +- ++ } + vim_free(wca); + ++ if (gap.ga_data != NULL) ++ { ++ *tofree = gap.ga_data; ++ return gap.ga_data; ++ } ++ ++ *p = NUL; + return IObuff; + } + +@@ -528,10 +563,12 @@ ins_compl_add_infercase( + { + char_u *str = str_arg; + char_u *p; +- int actual_len; // Take multi-byte characters +- int actual_compl_length; // into account. ++ int char_len; // count multi-byte characters ++ int compl_char_len; + int min_len; + int flags = 0; ++ int res; ++ char_u *tofree = NULL; + + if (p_ic && curbuf->b_p_inf && len > 0) + { +@@ -541,44 +578,45 @@ ins_compl_add_infercase( + if (has_mbyte) + { + p = str; +- actual_len = 0; ++ char_len = 0; + while (*p != NUL) + { + MB_PTR_ADV(p); +- ++actual_len; ++ ++char_len; + } + } + else +- actual_len = len; ++ char_len = len; + + // Find actual length of original text. + if (has_mbyte) + { + p = compl_orig_text; +- actual_compl_length = 0; ++ compl_char_len = 0; + while (*p != NUL) + { + MB_PTR_ADV(p); +- ++actual_compl_length; ++ ++compl_char_len; + } + } + else +- actual_compl_length = compl_length; ++ compl_char_len = compl_length; + +- // "actual_len" may be smaller than "actual_compl_length" when using ++ // "char_len" may be smaller than "compl_char_len" when using + // thesaurus, only use the minimum when comparing. +- min_len = actual_len < actual_compl_length +- ? actual_len : actual_compl_length; ++ min_len = char_len < compl_char_len ? char_len : compl_char_len; + +- str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length, +- min_len); ++ str = ins_compl_infercase_gettext(str, char_len, ++ compl_char_len, min_len, &tofree); + } + if (cont_s_ipos) + flags |= CP_CONT_S_IPOS; + if (icase) + flags |= CP_ICASE; + +- return ins_compl_add(str, len, fname, NULL, dir, flags, FALSE); ++ res = ins_compl_add(str, len, fname, NULL, dir, flags, FALSE); ++ vim_free(tofree); ++ return res; + } + + /* +diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim +index b7cfd29..aa054f2 100644 +--- a/src/testdir/test_ins_complete.vim ++++ b/src/testdir/test_ins_complete.vim +@@ -397,3 +397,17 @@ func Test_complete_overrun() + bwipe! + endfunc + ++func Test_infercase_very_long_line() ++ " this was truncating the line when inferring case ++ new ++ let longLine = "blah "->repeat(300) ++ let verylongLine = "blah "->repeat(400) ++ call setline(1, verylongLine) ++ call setline(2, longLine) ++ set ic infercase ++ exe "normal 2Go\\\" ++ call assert_equal(longLine, getline(3)) ++ ++ bwipe! ++ set noic noinfercase ++endfunc +-- +1.8.3.1 + diff --git a/backport-patch-8.2.3953-insert-completion-code-is-too-complic.patch b/backport-patch-8.2.3953-insert-completion-code-is-too-complic.patch new file mode 100644 index 0000000..19d48a2 --- /dev/null +++ b/backport-patch-8.2.3953-insert-completion-code-is-too-complic.patch @@ -0,0 +1,239 @@ +From 6ad84ab3e48d9490e4139df04f2c55b136f5501d Mon Sep 17 00:00:00 2001 +From: Yegappan Lakshmanan +Date: Fri, 31 Dec 2021 12:59:53 +0000 +Subject: [PATCH] patch 8.2.3953: insert completion code is too complicated + +Problem: Insert completion code is too complicated. +Solution: More refactoring. Move function arguments into a struct. +(Yegappan Lakshmanan, closes #9437) +--- + src/insexpand.c | 196 +++++++++++++++++++++++++++++++------------------------- + 1 file changed, 107 insertions(+), 89 deletions(-) + +diff --git a/src/insexpand.c b/src/insexpand.c +index 66a836e..3b4d530 100644 +--- a/src/insexpand.c ++++ b/src/insexpand.c +@@ -407,6 +407,111 @@ ins_compl_accept_char(int c) + } + + /* ++ * Get the completed text by inferring the case of the originally typed text. ++ */ ++ static char_u * ++ins_compl_infercase_gettext( ++ char_u *str, ++ int actual_len, ++ int actual_compl_length, ++ int min_len) ++{ ++ int *wca; // Wide character array. ++ char_u *p; ++ int i, c; ++ int has_lower = FALSE; ++ int was_letter = FALSE; ++ ++ IObuff[0] = NUL; ++ ++ // Allocate wide character array for the completion and fill it. ++ wca = ALLOC_MULT(int, actual_len); ++ if (wca == NULL) ++ return IObuff; ++ ++ p = str; ++ for (i = 0; i < actual_len; ++i) ++ if (has_mbyte) ++ wca[i] = mb_ptr2char_adv(&p); ++ else ++ wca[i] = *(p++); ++ ++ // Rule 1: Were any chars converted to lower? ++ p = compl_orig_text; ++ for (i = 0; i < min_len; ++i) ++ { ++ if (has_mbyte) ++ c = mb_ptr2char_adv(&p); ++ else ++ c = *(p++); ++ if (MB_ISLOWER(c)) ++ { ++ has_lower = TRUE; ++ if (MB_ISUPPER(wca[i])) ++ { ++ // Rule 1 is satisfied. ++ for (i = actual_compl_length; i < actual_len; ++i) ++ wca[i] = MB_TOLOWER(wca[i]); ++ break; ++ } ++ } ++ } ++ ++ // Rule 2: No lower case, 2nd consecutive letter converted to ++ // upper case. ++ if (!has_lower) ++ { ++ p = compl_orig_text; ++ for (i = 0; i < min_len; ++i) ++ { ++ if (has_mbyte) ++ c = mb_ptr2char_adv(&p); ++ else ++ c = *(p++); ++ if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) ++ { ++ // Rule 2 is satisfied. ++ for (i = actual_compl_length; i < actual_len; ++i) ++ wca[i] = MB_TOUPPER(wca[i]); ++ break; ++ } ++ was_letter = MB_ISLOWER(c) || MB_ISUPPER(c); ++ } ++ } ++ ++ // Copy the original case of the part we typed. ++ p = compl_orig_text; ++ for (i = 0; i < min_len; ++i) ++ { ++ if (has_mbyte) ++ c = mb_ptr2char_adv(&p); ++ else ++ c = *(p++); ++ if (MB_ISLOWER(c)) ++ wca[i] = MB_TOLOWER(wca[i]); ++ else if (MB_ISUPPER(c)) ++ wca[i] = MB_TOUPPER(wca[i]); ++ } ++ ++ // Generate encoding specific output from wide character array. ++ // Multi-byte characters can occupy up to five bytes more than ++ // ASCII characters, and we also need one byte for NUL, so stay ++ // six bytes away from the edge of IObuff. ++ p = IObuff; ++ i = 0; ++ while (i < actual_len && (p - IObuff + 6) < IOSIZE) ++ if (has_mbyte) ++ p += (*mb_char2bytes)(wca[i++], p); ++ else ++ *(p++) = wca[i++]; ++ *p = NUL; ++ ++ vim_free(wca); ++ ++ return IObuff; ++} ++ ++/* + * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the + * case of the originally typed text is used, and the case of the completed + * text is inferred, ie this tries to work out what case you probably wanted +@@ -423,13 +528,9 @@ ins_compl_add_infercase( + { + char_u *str = str_arg; + char_u *p; +- int i, c; + int actual_len; // Take multi-byte characters + int actual_compl_length; // into account. + int min_len; +- int *wca; // Wide character array. +- int has_lower = FALSE; +- int was_letter = FALSE; + int flags = 0; + + if (p_ic && curbuf->b_p_inf && len > 0) +@@ -469,91 +570,8 @@ ins_compl_add_infercase( + min_len = actual_len < actual_compl_length + ? actual_len : actual_compl_length; + +- // Allocate wide character array for the completion and fill it. +- wca = ALLOC_MULT(int, actual_len); +- if (wca != NULL) +- { +- p = str; +- for (i = 0; i < actual_len; ++i) +- if (has_mbyte) +- wca[i] = mb_ptr2char_adv(&p); +- else +- wca[i] = *(p++); +- +- // Rule 1: Were any chars converted to lower? +- p = compl_orig_text; +- for (i = 0; i < min_len; ++i) +- { +- if (has_mbyte) +- c = mb_ptr2char_adv(&p); +- else +- c = *(p++); +- if (MB_ISLOWER(c)) +- { +- has_lower = TRUE; +- if (MB_ISUPPER(wca[i])) +- { +- // Rule 1 is satisfied. +- for (i = actual_compl_length; i < actual_len; ++i) +- wca[i] = MB_TOLOWER(wca[i]); +- break; +- } +- } +- } +- +- // Rule 2: No lower case, 2nd consecutive letter converted to +- // upper case. +- if (!has_lower) +- { +- p = compl_orig_text; +- for (i = 0; i < min_len; ++i) +- { +- if (has_mbyte) +- c = mb_ptr2char_adv(&p); +- else +- c = *(p++); +- if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) +- { +- // Rule 2 is satisfied. +- for (i = actual_compl_length; i < actual_len; ++i) +- wca[i] = MB_TOUPPER(wca[i]); +- break; +- } +- was_letter = MB_ISLOWER(c) || MB_ISUPPER(c); +- } +- } +- +- // Copy the original case of the part we typed. +- p = compl_orig_text; +- for (i = 0; i < min_len; ++i) +- { +- if (has_mbyte) +- c = mb_ptr2char_adv(&p); +- else +- c = *(p++); +- if (MB_ISLOWER(c)) +- wca[i] = MB_TOLOWER(wca[i]); +- else if (MB_ISUPPER(c)) +- wca[i] = MB_TOUPPER(wca[i]); +- } +- +- // Generate encoding specific output from wide character array. +- // Multi-byte characters can occupy up to five bytes more than +- // ASCII characters, and we also need one byte for NUL, so stay +- // six bytes away from the edge of IObuff. +- p = IObuff; +- i = 0; +- while (i < actual_len && (p - IObuff + 6) < IOSIZE) +- if (has_mbyte) +- p += (*mb_char2bytes)(wca[i++], p); +- else +- *(p++) = wca[i++]; +- *p = NUL; +- +- vim_free(wca); +- } +- +- str = IObuff; ++ str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length, ++ min_len); + } + if (cont_s_ipos) + flags |= CP_CONT_S_IPOS; +-- +1.8.3.1 + diff --git a/vim.spec b/vim.spec index 0ebb754..9df09d4 100644 --- a/vim.spec +++ b/vim.spec @@ -11,7 +11,7 @@ Name: vim Epoch: 2 Version: 8.2 -Release: 45 +Release: 46 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 @@ -143,6 +143,8 @@ Patch6109: backport-CVE-2022-2287.patch Patch6110: backport-patch-9.0.0022-spell-test-fails.patch Patch6111: backport-CVE-2022-2210.patch Patch6112: backport-CVE-2022-2289.patch +Patch6113: backport-patch-8.2.3953-insert-completion-code-is-too-complic.patch +Patch6114: backport-CVE-2022-2343.patch Patch9000: bugfix-rm-modify-info-version.patch Patch9001: remove-failed-tests-due-to-patch.patch @@ -545,6 +547,12 @@ LC_ALL=en_US.UTF-8 make -j1 test %{_mandir}/man1/evim.* %changelog +* Wed Jul 20 2022 shixuantong - 2:8.2-46 +- Type:CVE +- ID:CVE-2022-2343 +- SUG:NA +- DESC:fix CVE-2022-2343 + * Fri Jul 15 2022 shangyibin - 2:8.2-45 - Type:CVE - ID:CVE-2022-2289 -- Gitee