| From b7081e135a16091c93f6f5f7525a5c58fb7ca9f9 Mon Sep 17 00:00:00 2001 |
| From: Bram Moolenaar <Bram@vim.org> |
| Date: Sat, 4 Sep 2021 18:47:28 +0200 |
| Subject: [PATCH] patch 8.2.3402: invalid memory access when using :retab with |
| large value |
| |
| Problem: Invalid memory access when using :retab with large value. |
| Solution: Check the number is positive. |
| |
| CVE: CVE-2021-3770 |
| Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> |
| Upstream-Status: Backport [https://github.com/vim/vim/commit/b7081e135a16091c93f6f5f7525a5c58fb7ca9f9] |
| --- |
| src/indent.c | 34 +++++++++++++++++++++------------- |
| src/option.c | 12 ++++++------ |
| src/optionstr.c | 4 ++-- |
| src/testdir/test_retab.vim | 3 +++ |
| src/version.c | 2 ++ |
| 5 files changed, 34 insertions(+), 21 deletions(-) |
| |
| Index: git/src/indent.c |
| =================================================================== |
| --- git.orig/src/indent.c |
| +++ git/src/indent.c |
| @@ -18,18 +18,19 @@ |
| /* |
| * Set the integer values corresponding to the string setting of 'vartabstop'. |
| * "array" will be set, caller must free it if needed. |
| + * Return FAIL for an error. |
| */ |
| int |
| tabstop_set(char_u *var, int **array) |
| { |
| - int valcount = 1; |
| - int t; |
| - char_u *cp; |
| + int valcount = 1; |
| + int t; |
| + char_u *cp; |
| |
| if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) |
| { |
| *array = NULL; |
| - return TRUE; |
| + return OK; |
| } |
| |
| for (cp = var; *cp != NUL; ++cp) |
| @@ -43,8 +44,8 @@ tabstop_set(char_u *var, int **array) |
| if (cp != end) |
| emsg(_(e_positive)); |
| else |
| - emsg(_(e_invarg)); |
| - return FALSE; |
| + semsg(_(e_invarg2), cp); |
| + return FAIL; |
| } |
| } |
| |
| @@ -55,26 +56,33 @@ tabstop_set(char_u *var, int **array) |
| ++valcount; |
| continue; |
| } |
| - emsg(_(e_invarg)); |
| - return FALSE; |
| + semsg(_(e_invarg2), var); |
| + return FAIL; |
| } |
| |
| *array = ALLOC_MULT(int, valcount + 1); |
| if (*array == NULL) |
| - return FALSE; |
| + return FAIL; |
| (*array)[0] = valcount; |
| |
| t = 1; |
| for (cp = var; *cp != NUL;) |
| { |
| - (*array)[t++] = atoi((char *)cp); |
| - while (*cp != NUL && *cp != ',') |
| + int n = atoi((char *)cp); |
| + |
| + if (n < 0 || n > 9999) |
| + { |
| + semsg(_(e_invarg2), cp); |
| + return FAIL; |
| + } |
| + (*array)[t++] = n; |
| + while (*cp != NUL && *cp != ',') |
| ++cp; |
| if (*cp != NUL) |
| ++cp; |
| } |
| |
| - return TRUE; |
| + return OK; |
| } |
| |
| /* |
| @@ -1556,7 +1564,7 @@ ex_retab(exarg_T *eap) |
| |
| #ifdef FEAT_VARTABS |
| new_ts_str = eap->arg; |
| - if (!tabstop_set(eap->arg, &new_vts_array)) |
| + if (tabstop_set(eap->arg, &new_vts_array) == FAIL) |
| return; |
| while (vim_isdigit(*(eap->arg)) || *(eap->arg) == ',') |
| ++(eap->arg); |
| Index: git/src/option.c |
| =================================================================== |
| --- git.orig/src/option.c |
| +++ git/src/option.c |
| @@ -2292,9 +2292,9 @@ didset_options2(void) |
| #endif |
| #ifdef FEAT_VARTABS |
| vim_free(curbuf->b_p_vsts_array); |
| - tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); |
| + (void)tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); |
| vim_free(curbuf->b_p_vts_array); |
| - tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); |
| + (void)tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); |
| #endif |
| } |
| |
| @@ -5756,7 +5756,7 @@ buf_copy_options(buf_T *buf, int flags) |
| buf->b_p_vsts = vim_strsave(p_vsts); |
| COPY_OPT_SCTX(buf, BV_VSTS); |
| if (p_vsts && p_vsts != empty_option) |
| - tabstop_set(p_vsts, &buf->b_p_vsts_array); |
| + (void)tabstop_set(p_vsts, &buf->b_p_vsts_array); |
| else |
| buf->b_p_vsts_array = 0; |
| buf->b_p_vsts_nopaste = p_vsts_nopaste |
| @@ -5914,7 +5914,7 @@ buf_copy_options(buf_T *buf, int flags) |
| buf->b_p_isk = save_p_isk; |
| #ifdef FEAT_VARTABS |
| if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) |
| - tabstop_set(p_vts, &buf->b_p_vts_array); |
| + (void)tabstop_set(p_vts, &buf->b_p_vts_array); |
| else |
| buf->b_p_vts_array = NULL; |
| #endif |
| @@ -5929,7 +5929,7 @@ buf_copy_options(buf_T *buf, int flags) |
| buf->b_p_vts = vim_strsave(p_vts); |
| COPY_OPT_SCTX(buf, BV_VTS); |
| if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) |
| - tabstop_set(p_vts, &buf->b_p_vts_array); |
| + (void)tabstop_set(p_vts, &buf->b_p_vts_array); |
| else |
| buf->b_p_vts_array = NULL; |
| #endif |
| @@ -6634,7 +6634,7 @@ paste_option_changed(void) |
| if (buf->b_p_vsts_array) |
| vim_free(buf->b_p_vsts_array); |
| if (buf->b_p_vsts && buf->b_p_vsts != empty_option) |
| - tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); |
| + (void)tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); |
| else |
| buf->b_p_vsts_array = 0; |
| #endif |
| Index: git/src/optionstr.c |
| =================================================================== |
| --- git.orig/src/optionstr.c |
| +++ git/src/optionstr.c |
| @@ -2166,7 +2166,7 @@ did_set_string_option( |
| if (errmsg == NULL) |
| { |
| int *oldarray = curbuf->b_p_vsts_array; |
| - if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) |
| + if (tabstop_set(*varp, &(curbuf->b_p_vsts_array)) == OK) |
| { |
| if (oldarray) |
| vim_free(oldarray); |
| @@ -2205,7 +2205,7 @@ did_set_string_option( |
| { |
| int *oldarray = curbuf->b_p_vts_array; |
| |
| - if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) |
| + if (tabstop_set(*varp, &(curbuf->b_p_vts_array)) == OK) |
| { |
| vim_free(oldarray); |
| #ifdef FEAT_FOLDING |
| Index: git/src/testdir/test_retab.vim |
| =================================================================== |
| --- git.orig/src/testdir/test_retab.vim |
| +++ git/src/testdir/test_retab.vim |
| @@ -74,4 +74,7 @@ endfunc |
| func Test_retab_error() |
| call assert_fails('retab -1', 'E487:') |
| call assert_fails('retab! -1', 'E487:') |
| + call assert_fails('ret -1000', 'E487:') |
| + call assert_fails('ret 10000', 'E475:') |
| + call assert_fails('ret 80000000000000000000', 'E475:') |
| endfunc |
| Index: git/src/version.c |
| =================================================================== |
| --- git.orig/src/version.c |
| +++ git/src/version.c |
| @@ -743,6 +743,8 @@ static char *(features[]) = |
| static int included_patches[] = |
| { /* Add new patch number below this line */ |
| /**/ |
| + 3402, |
| +/**/ |
| 0 |
| }; |
| |