Dominique Pellé <[email protected]> wrote:

> Hi
>
> afl-fuzz found the following command which causes a stack
> buffer overflow in vim-7.4.2232 and older:
>
> $ vim  -c 'echo substitute("x", ".", {-> submatch(10)}, "")'
>
> This one as well:
>
> $ vim -u NONE -c 'norm ix' -c 's/./\=submatch(10)/'
>
> The address sanitizer reports:
>
> =================================================================
> ==8302==ERROR: AddressSanitizer: stack-buffer-overflow on address
> 0x7f65148036b0 at pc 0x77ec07 bp 0x7ffce56f5f00 sp 0x7ffce56f5ef8
> READ of size 4 at 0x7f65148036b0 thread T0
>     #0 0x77ec06 in reg_submatch /home/pel/sb/vim/src/regexp.c:7878
>     #1 0x4e0043 in f_submatch /home/pel/sb/vim/src/evalfunc.c:11503
>     #2 0x4afe03 in call_internal_func /home/pel/sb/vim/src/evalfunc.c:997
>     #3 0x8e6e56 in call_func /home/pel/sb/vim/src/userfunc.c:1372
>     #4 0x8e1948 in get_func_tv /home/pel/sb/vim/src/userfunc.c:455
>     #5 0x493c4f in eval7 /home/pel/sb/vim/src/eval.c:4343
>     #6 0x492837 in eval6 /home/pel/sb/vim/src/eval.c:3977
>     #7 0x491dc7 in eval5 /home/pel/sb/vim/src/eval.c:3793
>     #8 0x490623 in eval4 /home/pel/sb/vim/src/eval.c:3492
>     #9 0x4901dc in eval3 /home/pel/sb/vim/src/eval.c:3409
>     #10 0x48fdcd in eval2 /home/pel/sb/vim/src/eval.c:3341
>     #11 0x48f945 in eval1 /home/pel/sb/vim/src/eval.c:3269
>     #12 0x48f73c in eval0 /home/pel/sb/vim/src/eval.c:3229
>     #13 0x482889 in eval_to_string /home/pel/sb/vim/src/eval.c:733
>     #14 0x77cdce in vim_regsub_both /home/pel/sb/vim/src/regexp.c:7517
>     #15 0x77c685 in vim_regsub_multi /home/pel/sb/vim/src/regexp.c:7390
>     #16 0x4ff687 in do_sub /home/pel/sb/vim/src/ex_cmds.c:5496
>     #17 0x5301e4 in do_one_cmd /home/pel/sb/vim/src/ex_docmd.c:2925
>     #18 0x528514 in do_cmdline /home/pel/sb/vim/src/ex_docmd.c:1110
>     #19 0x5270f8 in do_cmdline_cmd /home/pel/sb/vim/src/ex_docmd.c:715
>     #20 0x985dc9 in exe_commands /home/pel/sb/vim/src/main.c:2896
>     #21 0x97f1eb in vim_main2 /home/pel/sb/vim/src/main.c:781
>     #22 0x97e7e6 in main /home/pel/sb/vim/src/main.c:415
>     #23 0x7f65228ebf44 in __libc_start_main
> (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)
>     #24 0x40eb28 (/home/pel/sb/vim/src/vim+0x40eb28)
>
> Address 0x7f65148036b0 is located in stack of thread T0 at offset 688 in frame
>     #0 0x4fbf21 in do_sub /home/pel/sb/vim/src/ex_cmds.c:4775
>
>   This frame has 6 object(s):
>     [32, 36) 'sc'
>     [96, 100) 'ec'
>     [160, 168) 'cmd'
>     [224, 240) 'old_cursor'
>     [288, 320) 'subflags_save'
>     [352, 688) 'regmatch' <== Memory access at offset 688 overflows
> this variable
> HINT: this may be a false positive if your program uses some custom
> stack unwind mechanism or swapcontext
>       (longjmp and C++ exceptions *are* supported)
> SUMMARY: AddressSanitizer: stack-buffer-overflow
> /home/pel/sb/vim/src/regexp.c:7878 reg_submatch
> Shadow bytes around the buggy address:
>   0x0fed228f8680: f1 f1 f1 f1 04 f4 f4 f4 f2 f2 f2 f2 04 f4 f4 f4
>   0x0fed228f8690: f2 f2 f2 f2 00 f4 f4 f4 f2 f2 f2 f2 00 00 f4 f4
>   0x0fed228f86a0: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
>   0x0fed228f86b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x0fed228f86c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> =>0x0fed228f86d0: 00 00 00 00 00 00[f4]f4 f3 f3 f3 f3 00 00 00 00
>   0x0fed228f86e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x0fed228f86f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>   0x0fed228f8700: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>   0x0fed228f8710: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>   0x0fed228f8720: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
> Shadow byte legend (one shadow byte represents 8 application bytes):
>   Addressable:           00
>   Partially addressable: 01 02 03 04 05 06 07
>   Heap left redzone:       fa
>   Heap right redzone:      fb
>   Freed heap region:       fd
>   Stack left redzone:      f1
>   Stack mid redzone:       f2
>   Stack right redzone:     f3
>   Stack partial redzone:   f4
>   Stack after return:      f5
>   Stack use after scope:   f8
>   Global redzone:          f9
>   Global init order:       f6
>   Poisoned by user:        f7
>   Contiguous container OOB:fc
>   ASan internal:           fe
> ==8302==ABORTING
>
> Valgrind detects the bug as well but indirectly as use
> of uninitialized memory, since valgrind does not check
> for buffer overflows in stack.
>
> Attached patch fixes it and adds a test.
>
> Regards
> Dominique

Attached is a small update to the patch: comment in test
indicated "Vim-7.3.2232" instead of "Vim-7.4.2232".

Dominique

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 16e2365..504f344 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -11491,7 +11491,11 @@ f_submatch(typval_T *argvars, typval_T *rettv)
     no = (int)get_tv_number_chk(&argvars[0], &error);
     if (error)
 	return;
-    error = FALSE;
+    if (no < 0 || no >= NSUBEXP)
+    {
+        EMSGN(_("E999: invalid submatch number %d"), no);
+        return;
+    }
     if (argvars[1].v_type != VAR_UNKNOWN)
 	retList = (int)get_tv_number_chk(&argvars[1], &error);
     if (error)
@@ -12326,7 +12330,7 @@ get_callback(typval_T *arg, partial_T **pp)
 }
 
 /*
- * Unref/free "callback" and "partial" retured by get_callback().
+ * Unref/free "callback" and "partial" returned by get_callback().
  */
     void
 free_callback(char_u *callback, partial_T *partial)
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index a7ad65e..1fbc20c 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -198,6 +198,11 @@ func Test_substitute_expr()
   call assert_equal('--', substitute('xxx', 'x*', {-> '-' . Recurse() . '-'}, ''))
 endfunc
 
+func Test_invalid_submatch()
+  " This was causing invalid memory access in Vim-7.4.2232 and older
+  call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E999:')
+endfunc
+
 func Test_substitute_expr_arg()
   call assert_equal('123456789-123456789=', substitute('123456789',
 	\ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',

Raspunde prin e-mail lui