segmentation fault in regexp.c:1788 in vim/vim
Reported on
Feb 21st 2023
Description
SIGSEGV raised on regtilde function at regexp.c. As the function processes the tainted string inside the poc file, constant calls to the alloc function with ever-increasing size actually exhausts memory and the process terminates. At last negative size value is assigned.
Version
$ git log
commit 938ae280c79b8cdb0fca60336ec4c090ecd8bb5a (HEAD -> master, origin/master, origin/HEAD)
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Feb 20 20:44:55 2023 +0000
Update runtime files.
Proof of Concept
$ ./vim -u NONE -i NONE -n -m -X -Z -e -s -S poc -c :qa!
Segmentation fault (core dumped)
file poc2 achieves cpu and memory high by handling very large memory. This is handled in second memmove at regexp.c:1790
poc2
ASAN
$ ./vim -u NONE -i NONE -n -m -X -Z -e -s -S poc -c :qa!
=================================================================
==12373==ERROR: AddressSanitizer: negative-size-param: (size=-2145058819)
#0 0x555c98d1cfdc in __asan_memmove (/home/user/vim/src/vim+0x250fdc) (BuildId: 114ec797266b9b8572c771e928386eb985250bed)
#1 0x555c992bc4ad in regtilde /home/user/vim/src/regexp.c:1788:7
#2 0x555c98f4b2e3 in ex_substitute /home/user/vim/src/ex_cmds.c:4047:19
#3 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#4 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#5 0x555c991a9c61 in nv_colon /home/user/vim/src/normal.c:3176:15
#6 0x555c9918d86a in normal_cmd /home/user/vim/src/normal.c:938:5
#7 0x555c98f8da9c in exec_normal /home/user/vim/src/ex_docmd.c:8887:6
#8 0x555c98f8d6c3 in exec_normal_cmd /home/user/vim/src/ex_docmd.c:8850:5
#9 0x555c98f8d431 in ex_normal /home/user/vim/src/ex_docmd.c:8768:6
#10 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#11 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#12 0x555c99384eb3 in do_source_ext /home/user/vim/src/scriptfile.c:1759:5
#13 0x555c993829e0 in do_source /home/user/vim/src/scriptfile.c:1905:12
#14 0x555c9938252f in cmd_source /home/user/vim/src/scriptfile.c:1250:14
#15 0x555c9938202d in ex_source /home/user/vim/src/scriptfile.c:1276:2
#16 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#17 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#18 0x555c98f5f780 in do_cmdline_cmd /home/user/vim/src/ex_docmd.c:587:12
#19 0x555c9979b46c in exe_commands /home/user/vim/src/main.c:3146:2
#20 0x555c9979926a in vim_main2 /home/user/vim/src/main.c:782:2
#21 0x555c99792e7e in main /home/user/vim/src/main.c:433:12
#22 0x7fbdd0a29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#23 0x7fbdd0a29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#24 0x555c98c9aa74 in _start (/home/user/vim/src/vim+0x1cea74) (BuildId: 114ec797266b9b8572c771e928386eb985250bed)
0x7fbd09009800 is located 0 bytes inside of 2149908494-byte region [0x7fbd09009800,0x7fbd8925980e)
allocated by thread T0 here:
#0 0x555c98d1d8be in __interceptor_malloc (/home/user/vim/src/vim+0x2518be) (BuildId: 114ec797266b9b8572c771e928386eb985250bed)
#1 0x555c98d589d6 in lalloc /home/user/vim/src/alloc.c:246:11
#2 0x555c98d58939 in alloc /home/user/vim/src/alloc.c:151:12
#3 0x555c992bc47f in regtilde /home/user/vim/src/regexp.c:1783:12
#4 0x555c98f4b2e3 in ex_substitute /home/user/vim/src/ex_cmds.c:4047:19
#5 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#6 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#7 0x555c991a9c61 in nv_colon /home/user/vim/src/normal.c:3176:15
#8 0x555c9918d86a in normal_cmd /home/user/vim/src/normal.c:938:5
#9 0x555c98f8da9c in exec_normal /home/user/vim/src/ex_docmd.c:8887:6
#10 0x555c98f8d6c3 in exec_normal_cmd /home/user/vim/src/ex_docmd.c:8850:5
#11 0x555c98f8d431 in ex_normal /home/user/vim/src/ex_docmd.c:8768:6
#12 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#13 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#14 0x555c99384eb3 in do_source_ext /home/user/vim/src/scriptfile.c:1759:5
#15 0x555c993829e0 in do_source /home/user/vim/src/scriptfile.c:1905:12
#16 0x555c9938252f in cmd_source /home/user/vim/src/scriptfile.c:1250:14
#17 0x555c9938202d in ex_source /home/user/vim/src/scriptfile.c:1276:2
#18 0x555c98f688bf in do_one_cmd /home/user/vim/src/ex_docmd.c:2580:2
#19 0x555c98f5c684 in do_cmdline /home/user/vim/src/ex_docmd.c:993:17
#20 0x555c98f5f780 in do_cmdline_cmd /home/user/vim/src/ex_docmd.c:587:12
#21 0x555c9979b46c in exe_commands /home/user/vim/src/main.c:3146:2
#22 0x555c9979926a in vim_main2 /home/user/vim/src/main.c:782:2
#23 0x555c99792e7e in main /home/user/vim/src/main.c:433:12
#24 0x7fbdd0a29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: negative-size-param (/home/user/vim/src/vim+0x250fdc) (BuildId: 114ec797266b9b8572c771e928386eb985250bed) in __asan_memmove
==12373==ABORTING
GDB before memmove function call
- After a large size alloc function call completes
[----------------------------------registers-----------------------------------]
RAX: 0x7ffec333d010 --> 0x0
RBX: 0x0
RCX: 0x7fff5cf9e010 ("nXnXnXnXnXnXnXnXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(\\|0rOg@P(nXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg"...)
RDX: 0xffffffff8024fffd
RSI: 0x7fff5cf9e010 ("nXnXnXnXnXnXnXnXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(\\|0rOg@P(nXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg"...)
RDI: 0x7ffec333d010 --> 0x0
RBP: 0x7fffffffb690 --> 0x7fffffffb9b0 --> 0x7fffffffbc30 --> 0x7fffffffc3c0 --> 0x7fffffffc400 --> 0x7fffffffc4b0 (--> ...)
RSP: 0x7fffffffb660 --> 0x1558893e0
RIP: 0x555555718887 (<regtilde+212>: call 0x55555558b4e0 <memmove@plt>)
R8 : 0x7ffec333d010 --> 0x0
R9 : 0x7ffec333d010 --> 0x0
R10: 0x22 ('"')
R11: 0x246
R12: 0x7fffffffde98 --> 0x7fffffffe262 ("/home/user/fuzzing/vanillavim/vim/src/vim")
R13: 0x5555558893e0 (<main>: endbr64)
R14: 0x555555904038 --> 0x55555558bac0 (<__do_global_dtors_aux>: endbr64)
R15: 0x7ffff7ffd040 --> 0x7ffff7ffe2e0 --> 0x555555554000 --> 0x10102464c457f
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x55555571887d <regtilde+202>: mov rax,QWORD PTR [rbp-0x8]
0x555555718881 <regtilde+206>: mov rsi,rcx
0x555555718884 <regtilde+209>: mov rdi,rax
=> 0x555555718887 <regtilde+212>: call 0x55555558b4e0 <memmove@plt>
0x55555571888c <regtilde+217>: mov eax,DWORD PTR [rbp-0x20]
0x55555571888f <regtilde+220>: movsxd rdx,eax
0x555555718892 <regtilde+223>: mov rax,QWORD PTR [rip+0x2320f7] # 0x55555594a990 <reg_prev_sub>
0x555555718899 <regtilde+230>: mov ecx,DWORD PTR [rbp-0x1c]
Guessed arguments:
arg[0]: 0x7ffec333d010 --> 0x0
arg[1]: 0x7fff5cf9e010 ("nXnXnXnXnXnXnXnXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(\\|0rOg@P(nXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg"...)
arg[2]: 0xffffffff8024fffd
arg[3]: 0x7fff5cf9e010 ("nXnXnXnXnXnXnXnXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(\\|0rOg@P(nXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg"...)
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffb660 --> 0x1558893e0
0008| 0x7fffffffb668 --> 0x5555559677e0 ("nX", '~' <repeats 12 times>, "\\|0rOg@P(")
0016| 0x7fffffffb670 --> 0x8024fffd19a0ffff
0024| 0x7fffffffb678 --> 0x7fff5cf9e010 ("nXnXnXnXnXnXnXnXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(\\|0rOg@P(nXnX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg@P(nX\\|0rOg"...)
0032| 0x7fffffffb680 --> 0x7fffdd1ee00d ("~~~~~~~\\|0rOg@P(")
0040| 0x7fffffffb688 --> 0x7ffec333d010 --> 0x0
0048| 0x7fffffffb690 --> 0x7fffffffb9b0 --> 0x7fffffffbc30 --> 0x7fffffffc3c0 --> 0x7fffffffc400 --> 0x7fffffffc4b0 (--> ...)
0056| 0x7fffffffb698 --> 0x55555561996e (<ex_substitute+2947>: mov QWORD PTR [rbp-0x1c0],rax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Impact
it can lead to DoS, can affect other processes by exhausting memory, dangerous from heap attacks, possibly remote execution
@maintainer Is the poc here too long? This vulnerability uses a string inside the file. If the poc is too long, I'll trim it.
Please always try to reduce the size of the POC. Certainly in this case, as the script contains many control characters and random text.
Okay i will. Here's the first trimmed version poc2
here is short explained for this vuln.
The very large difference in values in len = (int)(p - newsub)
in regexp.c:1787 is assigned to the len
variable, and the very large value with the high order bits filled with 0xff is passed as an argument to the memmove
function due to the (size_t)
cast in mch_memmove(tmpsub, newsub, (size_t)len)
in regexp.c:1788. This is treated as negative inside the memmove
function, causing a SIGSEGV signal to be raised and the process to terminate.
The POC takes a bit of time because it involves constant heap allocation and freeing. In my case, it always resulted in a sigfault within 10 seconds
Sorry for the long delay. I tried out "poc3" and could reproduce the problem. But it does take a very long time before it fails. That makes it unsuitable for a regression test. Any idea of how to trigger the issue in a quicker way?