aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-12-10 13:52:40 +0800
committerzeertzjq <zeertzjq@outlook.com>2024-12-10 14:29:24 +0800
commit7a7ed0c8ac2d66d695da5bd3f90536e8c5c11ccc (patch)
treef19dcf946b2166a42c780c704986221e0ae91681
parentac230370f3de2925b3ca9443e8d52d7fc4311aba (diff)
downloadrneovim-7a7ed0c8ac2d66d695da5bd3f90536e8c5c11ccc.tar.gz
rneovim-7a7ed0c8ac2d66d695da5bd3f90536e8c5c11ccc.tar.bz2
rneovim-7a7ed0c8ac2d66d695da5bd3f90536e8c5c11ccc.zip
vim-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: vim/vim#13554 closes: vim/vim#13555 https://github.com/vim/vim/commit/3770574e4a70e810add9929973c51f9070c8c851 Co-authored-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/nvim/indent_c.c82
-rw-r--r--test/old/testdir/test_indent.vim15
2 files changed, 59 insertions, 38 deletions
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 98b0d6003a..9b5c80dd09 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -1689,7 +1689,7 @@ void parse_cino(buf_T *buf)
p++;
}
char *digits_start = p; // remember where the digits start
- int n = getdigits_int(&p, true, 0);
+ int64_t n = getdigits_int(&p, true, 0);
divider = 0;
if (*p == '.') { // ".5s" means a fraction.
fraction = atoi(++p);
@@ -1717,119 +1717,125 @@ void parse_cino(buf_T *buf)
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;
+ buf->b_ind_level = (int)n;
break;
case 'e':
- buf->b_ind_open_imag = n;
+ buf->b_ind_open_imag = (int)n;
break;
case 'n':
- buf->b_ind_no_brace = n;
+ buf->b_ind_no_brace = (int)n;
break;
case 'f':
- buf->b_ind_first_open = n;
+ buf->b_ind_first_open = (int)n;
break;
case '{':
- buf->b_ind_open_extra = n;
+ buf->b_ind_open_extra = (int)n;
break;
case '}':
- buf->b_ind_close_extra = n;
+ buf->b_ind_close_extra = (int)n;
break;
case '^':
- buf->b_ind_open_left_imag = n;
+ buf->b_ind_open_left_imag = (int)n;
break;
case 'L':
- buf->b_ind_jump_label = n;
+ buf->b_ind_jump_label = (int)n;
break;
case ':':
- buf->b_ind_case = n;
+ buf->b_ind_case = (int)n;
break;
case '=':
- buf->b_ind_case_code = n;
+ buf->b_ind_case_code = (int)n;
break;
case 'b':
- buf->b_ind_case_break = n;
+ buf->b_ind_case_break = (int)n;
break;
case 'p':
- buf->b_ind_param = n;
+ buf->b_ind_param = (int)n;
break;
case 't':
- buf->b_ind_func_type = n;
+ buf->b_ind_func_type = (int)n;
break;
case '/':
- buf->b_ind_comment = n;
+ buf->b_ind_comment = (int)n;
break;
case 'c':
- buf->b_ind_in_comment = n;
+ buf->b_ind_in_comment = (int)n;
break;
case 'C':
- buf->b_ind_in_comment2 = n;
+ buf->b_ind_in_comment2 = (int)n;
break;
case 'i':
- buf->b_ind_cpp_baseclass = n;
+ buf->b_ind_cpp_baseclass = (int)n;
break;
case '+':
- buf->b_ind_continuation = n;
+ buf->b_ind_continuation = (int)n;
break;
case '(':
- buf->b_ind_unclosed = n;
+ buf->b_ind_unclosed = (int)n;
break;
case 'u':
- buf->b_ind_unclosed2 = n;
+ buf->b_ind_unclosed2 = (int)n;
break;
case 'U':
- buf->b_ind_unclosed_noignore = n;
+ buf->b_ind_unclosed_noignore = (int)n;
break;
case 'W':
- buf->b_ind_unclosed_wrapped = n;
+ buf->b_ind_unclosed_wrapped = (int)n;
break;
case 'w':
- buf->b_ind_unclosed_whiteok = n;
+ buf->b_ind_unclosed_whiteok = (int)n;
break;
case 'm':
- buf->b_ind_matching_paren = n;
+ buf->b_ind_matching_paren = (int)n;
break;
case 'M':
- buf->b_ind_paren_prev = n;
+ buf->b_ind_paren_prev = (int)n;
break;
case ')':
- buf->b_ind_maxparen = n;
+ buf->b_ind_maxparen = (int)n;
break;
case '*':
- buf->b_ind_maxcomment = n;
+ buf->b_ind_maxcomment = (int)n;
break;
case 'g':
- buf->b_ind_scopedecl = n;
+ buf->b_ind_scopedecl = (int)n;
break;
case 'h':
- buf->b_ind_scopedecl_code = n;
+ buf->b_ind_scopedecl_code = (int)n;
break;
case 'j':
- buf->b_ind_java = n;
+ buf->b_ind_java = (int)n;
break;
case 'J':
- buf->b_ind_js = n;
+ buf->b_ind_js = (int)n;
break;
case 'l':
- buf->b_ind_keep_case_label = n;
+ buf->b_ind_keep_case_label = (int)n;
break;
case '#':
- buf->b_ind_hash_comment = n;
+ buf->b_ind_hash_comment = (int)n;
break;
case 'N':
- buf->b_ind_cpp_namespace = n;
+ buf->b_ind_cpp_namespace = (int)n;
break;
case 'k':
- buf->b_ind_if_for_while = n;
+ buf->b_ind_if_for_while = (int)n;
break;
case 'E':
- buf->b_ind_cpp_extern_c = n;
+ buf->b_ind_cpp_extern_c = (int)n;
break;
case 'P':
- buf->b_ind_pragma = n;
+ buf->b_ind_pragma = (int)n;
break;
}
if (*p == ',') {
diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim
index 6afc3ff405..0998b04443 100644
--- a/test/old/testdir/test_indent.vim
+++ b/test/old/testdir/test_indent.vim
@@ -288,4 +288,19 @@ func Test_indent_overflow_count()
close!
endfunc
+func Test_indent_overflow_count2()
+ throw 'skipped: Nvim does not support 64-bit number options'
+ 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