]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2112: [security]: overflow in shift_line v9.0.2112
authorChristian Brabandt <cb@256bit.org>
Tue, 14 Nov 2023 21:42:59 +0000 (22:42 +0100)
committerChristian Brabandt <cb@256bit.org>
Thu, 16 Nov 2023 21:04:38 +0000 (22:04 +0100)
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: #13535

Signed-off-by: Christian Brabandt <cb@256bit.org>
src/ops.c
src/testdir/test_indent.vim
src/version.c

index c0a2981d68770498d25448ac1f48305f5fd61f8f..ecd7fc2170c58bf958eeabe3b896d09d6136c6b4 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -229,11 +229,11 @@ shift_line(
     int        amount,
     int call_changed_bytes)    // call changed_bytes()
 {
-    int                count;
+    long long  count;
     int                i, j;
     int                sw_val = (int)get_sw_value_indent(curbuf);
 
-    count = get_indent();      // get current indent
+    count = (long long)get_indent();   // get current indent
 
     if (round)                 // round off indent
     {
@@ -260,14 +260,19 @@ shift_line(
                count = 0;
        }
        else
-           count += sw_val * amount;
+       {
+           if ((long long)sw_val * (long long)amount > INT_MAX - count)
+               count = INT_MAX;
+           else
+               count += (long long)sw_val * (long long)amount;
+       }
     }
 
     // Set new indent
     if (State & VREPLACE_FLAG)
-       change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes);
+       change_indent(INDENT_SET, (int)count, FALSE, NUL, call_changed_bytes);
     else
-       (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
+       (void)set_indent((int)count, call_changed_bytes ? SIN_CHANGED : 0);
 }
 
 /*
index 96e9d2300883c9ee9eb5d30ade4500b0880b66c9..217a7ae625072893c0862a7bb944418b25854feb 100644 (file)
@@ -275,4 +275,15 @@ func Test_formatting_keeps_first_line_indent()
   bwipe!
 endfunc
 
+" Test for indenting with large amount, causes overflow
+func Test_indent_overflow_count()
+  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
index 66aff800bd38a607891199cbb9d66bdac8ac3c00..249cd11d208b80ad1fcfa5924dc66a631ee7530b 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2112,
 /**/
     2111,
 /**/