]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2122: [security]: prevent overflow in indenting v9.0.2122
authorChristian Brabandt <cb@256bit.org>
Wed, 22 Nov 2023 21:18:35 +0000 (22:18 +0100)
committerChristian Brabandt <cb@256bit.org>
Wed, 22 Nov 2023 21:18:35 +0000 (22:18 +0100)
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>
src/cindent.c
src/ops.c
src/testdir/test_indent.vim
src/version.c

index 9b2b6442a61b0092077b4c59ec69f38a21ed1407..7ac1f4ba8752a8688d0811161750cf7c375ff00d 100644 (file)
@@ -1730,10 +1730,17 @@ parse_cino(buf_T *buf)
     char_u     *p;
     char_u     *l;
     char_u     *digits;
-    int                n;
+    long long  n;
     int                divider;
     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.
 
@@ -1902,47 +1909,52 @@ parse_cino(buf_T *buf)
        if (l[1] == '-')
            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
        // doc/indent.txt, and add explanation for it!
        switch (*l)
        {
-           case '>': buf->b_ind_level = n; break;
-           case 'e': buf->b_ind_open_imag = n; break;
-           case 'n': buf->b_ind_no_brace = n; break;
-           case 'f': buf->b_ind_first_open = n; break;
-           case '{': buf->b_ind_open_extra = n; break;
-           case '}': buf->b_ind_close_extra = n; break;
-           case '^': buf->b_ind_open_left_imag = n; break;
-           case 'L': buf->b_ind_jump_label = n; break;
-           case ':': buf->b_ind_case = n; break;
-           case '=': buf->b_ind_case_code = n; break;
-           case 'b': buf->b_ind_case_break = n; break;
-           case 'p': buf->b_ind_param = n; break;
-           case 't': buf->b_ind_func_type = n; break;
-           case '/': buf->b_ind_comment = n; break;
-           case 'c': buf->b_ind_in_comment = n; break;
-           case 'C': buf->b_ind_in_comment2 = n; break;
-           case 'i': buf->b_ind_cpp_baseclass = n; break;
-           case '+': buf->b_ind_continuation = n; break;
-           case '(': buf->b_ind_unclosed = n; break;
-           case 'u': buf->b_ind_unclosed2 = n; break;
-           case 'U': buf->b_ind_unclosed_noignore = n; break;
-           case 'W': buf->b_ind_unclosed_wrapped = n; break;
-           case 'w': buf->b_ind_unclosed_whiteok = n; break;
-           case 'm': buf->b_ind_matching_paren = n; break;
-           case 'M': buf->b_ind_paren_prev = n; break;
-           case ')': buf->b_ind_maxparen = n; break;
-           case '*': buf->b_ind_maxcomment = n; break;
-           case 'g': buf->b_ind_scopedecl = n; break;
-           case 'h': buf->b_ind_scopedecl_code = n; break;
-           case 'j': buf->b_ind_java = n; break;
-           case 'J': buf->b_ind_js = n; break;
-           case 'l': buf->b_ind_keep_case_label = n; break;
-           case '#': buf->b_ind_hash_comment = n; break;
-           case 'N': buf->b_ind_cpp_namespace = n; break;
-           case 'k': buf->b_ind_if_for_while = n; break;
-           case 'E': buf->b_ind_cpp_extern_c = n; break;
-           case 'P': buf->b_ind_pragma = n; break;
+           case '>': buf->b_ind_level = (int)n; break;
+           case 'e': buf->b_ind_open_imag = (int)n; break;
+           case 'n': buf->b_ind_no_brace = (int)n; break;
+           case 'f': buf->b_ind_first_open = (int)n; break;
+           case '{': buf->b_ind_open_extra = (int)n; break;
+           case '}': buf->b_ind_close_extra = (int)n; break;
+           case '^': buf->b_ind_open_left_imag = (int)n; break;
+           case 'L': buf->b_ind_jump_label = (int)n; break;
+           case ':': buf->b_ind_case = (int)n; break;
+           case '=': buf->b_ind_case_code = (int)n; break;
+           case 'b': buf->b_ind_case_break = (int)n; break;
+           case 'p': buf->b_ind_param = (int)n; break;
+           case 't': buf->b_ind_func_type = (int)n; break;
+           case '/': buf->b_ind_comment = (int)n; break;
+           case 'c': buf->b_ind_in_comment = (int)n; break;
+           case 'C': buf->b_ind_in_comment2 = (int)n; break;
+           case 'i': buf->b_ind_cpp_baseclass = (int)n; break;
+           case '+': buf->b_ind_continuation = (int)n; break;
+           case '(': buf->b_ind_unclosed = (int)n; break;
+           case 'u': buf->b_ind_unclosed2 = (int)n; break;
+           case 'U': buf->b_ind_unclosed_noignore = (int)n; break;
+           case 'W': buf->b_ind_unclosed_wrapped = (int)n; break;
+           case 'w': buf->b_ind_unclosed_whiteok = (int)n; break;
+           case 'm': buf->b_ind_matching_paren = (int)n; break;
+           case 'M': buf->b_ind_paren_prev = (int)n; break;
+           case ')': buf->b_ind_maxparen = (int)n; break;
+           case '*': buf->b_ind_maxcomment = (int)n; break;
+           case 'g': buf->b_ind_scopedecl = (int)n; break;
+           case 'h': buf->b_ind_scopedecl_code = (int)n; break;
+           case 'j': buf->b_ind_java = (int)n; break;
+           case 'J': buf->b_ind_js = (int)n; break;
+           case 'l': buf->b_ind_keep_case_label = (int)n; break;
+           case '#': buf->b_ind_hash_comment = (int)n; break;
+           case 'N': buf->b_ind_cpp_namespace = (int)n; break;
+           case 'k': buf->b_ind_if_for_while = (int)n; break;
+           case 'E': buf->b_ind_cpp_extern_c = (int)n; break;
+           case 'P': buf->b_ind_pragma = (int)n; break;
        }
        if (*p == ',')
            ++p;
index 9e8ea86160c30d781cadea33e1f3df80357bda52..7cb82b89fb796913144b2723c9d5a0694b6f38ce 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -230,8 +230,8 @@ shift_line(
     int call_changed_bytes)    // call changed_bytes()
 {
     long long  count;
-    int                i, j;
-    int                sw_val = (int)get_sw_value_indent(curbuf);
+    long       i, j;
+    long       sw_val = get_sw_value_indent(curbuf);
 
     count = (long long)get_indent();   // get current indent
 
index 217a7ae625072893c0862a7bb944418b25854feb..a7e9f425c9bda801cccbd44c4808637252493ba0 100644 (file)
@@ -286,4 +286,18 @@ func Test_indent_overflow_count()
   close!
 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
index 642da01d8b2fc8c35563ef943413e5ce21cc647b..9b7fbe7229e61771062097b02480408bd589043e 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2122,
 /**/
     2121,
 /**/