changeset 33784:872c07d5befe v9.0.2112

patch 9.0.2112: [security]: overflow in shift_line Commit: https://github.com/vim/vim/commit/6bf131888a3d1de62bbfa8a7ea03c0ddccfd496e Author: Christian Brabandt <cb@256bit.org> Date: Tue Nov 14 22:42:59 2023 +0100 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: #13535 Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 16 Nov 2023 22:15:15 +0100
parents 682386b2c209
children e214c3c60b1c
files src/ops.c src/testdir/test_indent.vim src/version.c
diffstat 3 files changed, 23 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- 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);
 }
 
 /*
--- a/src/testdir/test_indent.vim
+++ b/src/testdir/test_indent.vim
@@ -275,4 +275,15 @@ func Test_formatting_keeps_first_line_in
   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
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2112,
+/**/
     2111,
 /**/
     2110,