0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.0.2122: [security]: prevent overflow in indenting

Problem:  [security]: prevent overflow in indenting
Solution: use long long and remove cast to (int)

The shiftwidth option values are defined as being long. However, when
calculating the actual amount of indent, we cast down to (int), which
may cause the shiftwidth value to become negative and later it may even
cause Vim to try to allocate a huge amount of memory.

We already use long and long long variable types to calculate the indent
(and detect possible overflows), so the cast to (int) seems superfluous
and can be safely removed. So let's just remove the (int) cast and
calculate the indent using longs.

Additionally, the 'shiftwidth' option value is also used when determining
the actual 'cino' options. There it can again cause another overflow, so
make sure it is safe in parse_cino() as well.

fixes: #13554
closes: #13555

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Christian Brabandt
2023-11-22 22:18:35 +01:00
parent 26c11c5688
commit 3770574e4a
4 changed files with 69 additions and 41 deletions

View File

@@ -1730,10 +1730,17 @@ parse_cino(buf_T *buf)
char_u *p; char_u *p;
char_u *l; char_u *l;
char_u *digits; char_u *digits;
int n; long long n;
int divider; int divider;
int fraction = 0; int fraction = 0;
int sw = (int)get_sw_value(buf); int sw;
long long t = get_sw_value(buf);
// needed for cino-(, it will be multiplied by 2 again
if (t > INT_MAX / 2)
sw = INT_MAX / 2;
else
sw = (int)t;
// Set the default values. // Set the default values.
@@ -1902,47 +1909,52 @@ parse_cino(buf_T *buf)
if (l[1] == '-') if (l[1] == '-')
n = -n; n = -n;
if (n > INT_MAX)
n = INT_MAX;
else if (n < INT_MIN)
n = INT_MIN;
// When adding an entry here, also update the default 'cinoptions' in // When adding an entry here, also update the default 'cinoptions' in
// doc/indent.txt, and add explanation for it! // doc/indent.txt, and add explanation for it!
switch (*l) switch (*l)
{ {
case '>': buf->b_ind_level = n; break; case '>': buf->b_ind_level = (int)n; break;
case 'e': buf->b_ind_open_imag = n; break; case 'e': buf->b_ind_open_imag = (int)n; break;
case 'n': buf->b_ind_no_brace = n; break; case 'n': buf->b_ind_no_brace = (int)n; break;
case 'f': buf->b_ind_first_open = n; break; case 'f': buf->b_ind_first_open = (int)n; break;
case '{': buf->b_ind_open_extra = n; break; case '{': buf->b_ind_open_extra = (int)n; break;
case '}': buf->b_ind_close_extra = n; break; case '}': buf->b_ind_close_extra = (int)n; break;
case '^': buf->b_ind_open_left_imag = n; break; case '^': buf->b_ind_open_left_imag = (int)n; break;
case 'L': buf->b_ind_jump_label = n; break; case 'L': buf->b_ind_jump_label = (int)n; break;
case ':': buf->b_ind_case = n; break; case ':': buf->b_ind_case = (int)n; break;
case '=': buf->b_ind_case_code = n; break; case '=': buf->b_ind_case_code = (int)n; break;
case 'b': buf->b_ind_case_break = n; break; case 'b': buf->b_ind_case_break = (int)n; break;
case 'p': buf->b_ind_param = n; break; case 'p': buf->b_ind_param = (int)n; break;
case 't': buf->b_ind_func_type = n; break; case 't': buf->b_ind_func_type = (int)n; break;
case '/': buf->b_ind_comment = n; break; case '/': buf->b_ind_comment = (int)n; break;
case 'c': buf->b_ind_in_comment = n; break; case 'c': buf->b_ind_in_comment = (int)n; break;
case 'C': buf->b_ind_in_comment2 = n; break; case 'C': buf->b_ind_in_comment2 = (int)n; break;
case 'i': buf->b_ind_cpp_baseclass = n; break; case 'i': buf->b_ind_cpp_baseclass = (int)n; break;
case '+': buf->b_ind_continuation = n; break; case '+': buf->b_ind_continuation = (int)n; break;
case '(': buf->b_ind_unclosed = n; break; case '(': buf->b_ind_unclosed = (int)n; break;
case 'u': buf->b_ind_unclosed2 = n; break; case 'u': buf->b_ind_unclosed2 = (int)n; break;
case 'U': buf->b_ind_unclosed_noignore = n; break; case 'U': buf->b_ind_unclosed_noignore = (int)n; break;
case 'W': buf->b_ind_unclosed_wrapped = n; break; case 'W': buf->b_ind_unclosed_wrapped = (int)n; break;
case 'w': buf->b_ind_unclosed_whiteok = n; break; case 'w': buf->b_ind_unclosed_whiteok = (int)n; break;
case 'm': buf->b_ind_matching_paren = n; break; case 'm': buf->b_ind_matching_paren = (int)n; break;
case 'M': buf->b_ind_paren_prev = n; break; case 'M': buf->b_ind_paren_prev = (int)n; break;
case ')': buf->b_ind_maxparen = n; break; case ')': buf->b_ind_maxparen = (int)n; break;
case '*': buf->b_ind_maxcomment = n; break; case '*': buf->b_ind_maxcomment = (int)n; break;
case 'g': buf->b_ind_scopedecl = n; break; case 'g': buf->b_ind_scopedecl = (int)n; break;
case 'h': buf->b_ind_scopedecl_code = n; break; case 'h': buf->b_ind_scopedecl_code = (int)n; break;
case 'j': buf->b_ind_java = n; break; case 'j': buf->b_ind_java = (int)n; break;
case 'J': buf->b_ind_js = n; break; case 'J': buf->b_ind_js = (int)n; break;
case 'l': buf->b_ind_keep_case_label = n; break; case 'l': buf->b_ind_keep_case_label = (int)n; break;
case '#': buf->b_ind_hash_comment = n; break; case '#': buf->b_ind_hash_comment = (int)n; break;
case 'N': buf->b_ind_cpp_namespace = n; break; case 'N': buf->b_ind_cpp_namespace = (int)n; break;
case 'k': buf->b_ind_if_for_while = n; break; case 'k': buf->b_ind_if_for_while = (int)n; break;
case 'E': buf->b_ind_cpp_extern_c = n; break; case 'E': buf->b_ind_cpp_extern_c = (int)n; break;
case 'P': buf->b_ind_pragma = n; break; case 'P': buf->b_ind_pragma = (int)n; break;
} }
if (*p == ',') if (*p == ',')
++p; ++p;

View File

@@ -230,8 +230,8 @@ shift_line(
int call_changed_bytes) // call changed_bytes() int call_changed_bytes) // call changed_bytes()
{ {
long long count; long long count;
int i, j; long i, j;
int sw_val = (int)get_sw_value_indent(curbuf); long sw_val = get_sw_value_indent(curbuf);
count = (long long)get_indent(); // get current indent count = (long long)get_indent(); // get current indent

View File

@@ -286,4 +286,18 @@ func Test_indent_overflow_count()
close! close!
endfunc endfunc
func Test_indent_overflow_count2()
new
" this only works, when long is 64bits
try
setl sw=0x180000000
catch /^Vim\%((\a\+)\)\=:E487:/
throw 'Skipped: value negative on this platform'
endtry
call setline(1, "\tabc")
norm! <<
call assert_equal(0, indent(1))
close!
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2122,
/**/ /**/
2121, 2121,
/**/ /**/