From 2336389d236f3d80575a5139e92c551c005b0eff Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 10 Dec 2024 13:24:54 +0800 Subject: 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 --- src/nvim/ops.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') 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); } } -- cgit