aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-12-10 13:24:54 +0800
committerzeertzjq <zeertzjq@outlook.com>2024-12-10 14:29:24 +0800
commit2336389d236f3d80575a5139e92c551c005b0eff (patch)
tree0979fe1164b1e13625384a11b03590ca365d6849
parent4889935a7a0e188d6fb247cbc3b3bb0c5b0ed731 (diff)
downloadrneovim-2336389d236f3d80575a5139e92c551c005b0eff.tar.gz
rneovim-2336389d236f3d80575a5139e92c551c005b0eff.tar.bz2
rneovim-2336389d236f3d80575a5139e92c551c005b0eff.zip
vim-patch:9.0.2112: [security]: overflow in shift_line
Problem: [security]: overflow in shift_line Solution: allow a max indent of INT_MAX [security]: overflow in shift_line When shifting lines in operator pending mode and using a very large value, we may overflow the size of integer. Fix this by using a long variable, testing if the result would be larger than INT_MAX and if so, indent by INT_MAX value. Special case: We cannot use long here, since on 32bit architectures (or on Windows?), it typically cannot take larger values than a plain int, so we have to use long long count, decide whether the resulting multiplication of the shiftwidth value * amount is larger than INT_MAX and if so, we will store INT_MAX as possible larges value in the long long count variable. Then we can safely cast it back to int when calling the functions to set the indent (set_indent() or change_indent()). So this should be safe. Add a test that when using a huge value in operator pending mode for shifting, we will shift by INT_MAX closes: vim/vim#13535 https://github.com/vim/vim/commit/6bf131888a3d1de62bbfa8a7ea03c0ddccfd496e Skip the test for now, as it takes too long and requires other fixes. Co-authored-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/nvim/ops.c16
-rw-r--r--test/old/testdir/test_indent.vim12
2 files changed, 22 insertions, 6 deletions
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 63c78936ba..1bba1154f2 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -283,11 +283,11 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes)
if (sw_val == 0) {
sw_val = 1; // shouldn't happen, just in case
}
- int count = get_indent(); // get current indent
+ int64_t count = get_indent(); // get current indent
if (round) { // round off indent
- int i = count / sw_val; // number of 'shiftwidth' rounded down
- int j = count % sw_val; // extra spaces
+ int i = (int)(count / sw_val); // number of 'shiftwidth' rounded down
+ int j = (int)(count % sw_val); // extra spaces
if (j && left) { // first remove extra spaces
amount--;
}
@@ -301,15 +301,19 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes)
if (left) {
count = MAX(count - sw_val * amount, 0);
} else {
- count += sw_val * amount;
+ if ((int64_t)sw_val * (int64_t)amount > INT_MAX - count) {
+ count = INT_MAX;
+ } else {
+ count += (int64_t)sw_val * (int64_t)amount;
+ }
}
}
// Set new indent
if (State & VREPLACE_FLAG) {
- change_indent(INDENT_SET, count, false, call_changed_bytes);
+ change_indent(INDENT_SET, (int)count, false, call_changed_bytes);
} else {
- set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
+ set_indent((int)count, call_changed_bytes ? SIN_CHANGED : 0);
}
}
diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim
index dcacc11663..6afc3ff405 100644
--- a/test/old/testdir/test_indent.vim
+++ b/test/old/testdir/test_indent.vim
@@ -276,4 +276,16 @@ func Test_formatting_keeps_first_line_indent()
bwipe!
endfunc
+" Test for indenting with large amount, causes overflow
+func Test_indent_overflow_count()
+ throw 'skipped: TODO: '
+ new
+ setl sw=8
+ call setline(1, "abc")
+ norm! V2147483647>
+ " indents by INT_MAX
+ call assert_equal(2147483647, indent(1))
+ close!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab