Memory leaks in function vim_strsave in vim/vim
Reported on
Jun 16th 2022
Description
Memory leaks in function vim_strsave at strings.c:27
vim version
git log
commit 83497f875881973df772cc4cc593766345df6c4a (HEAD -> master, tag: v8.2.5105, origin/master, origin/HEAD)
POC
root@fuzz-vm0-187:/home/fuzz/fuzz/vim/afl/src# ./vim -u NONE -i NONE -n -m -X -Z -e -s -S /mnt/share/max/fuzz/poc/vim/poc_ml3_s.dat -c :qa!
=================================================================
==31529==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 8 byte(s) in 4 object(s) allocated from:
#0 0x499cad in malloc (/home/fuzz/fuzz/vim/afl/src/vim+0x499cad)
#1 0x4cb382 in lalloc /home/fuzz/fuzz/vim/afl/src/alloc.c:246:11
#2 0x4cb26a in alloc /home/fuzz/fuzz/vim/afl/src/alloc.c:151:12
#3 0xf8cbd6 in vim_strsave /home/fuzz/fuzz/vim/afl/src/strings.c:27:9
#4 0x6a6984 in typval2string /home/fuzz/fuzz/vim/afl/src/eval.c:502:11
#5 0x6a6d7f in eval_to_string_eap /home/fuzz/fuzz/vim/afl/src/eval.c:528:11
#6 0x6a6e9f in eval_to_string /home/fuzz/fuzz/vim/afl/src/eval.c:541:12
#7 0xcec814 in vim_regsub_both /home/fuzz/fuzz/vim/afl/src/regexp.c:2049:17
#8 0xcf06eb in vim_regsub_multi /home/fuzz/fuzz/vim/afl/src/regexp.c:1915:14
#9 0x7b3650 in ex_substitute /home/fuzz/fuzz/vim/afl/src/ex_cmds.c:4420:12
#10 0x7dd249 in do_one_cmd /home/fuzz/fuzz/vim/afl/src/ex_docmd.c:2570:2
#11 0x7ca105 in do_cmdline /home/fuzz/fuzz/vim/afl/src/ex_docmd.c:992:17
#12 0x115857c in call_user_func /home/fuzz/fuzz/vim/afl/src/userfunc.c:2900:2
#13 0x115466d in call_user_func_check /home/fuzz/fuzz/vim/afl/src/userfunc.c:3048:2
#14 0x114ea14 in call_func /home/fuzz/fuzz/vim/afl/src/userfunc.c:3612:11
#15 0x114bdb3 in get_func_tv /home/fuzz/fuzz/vim/afl/src/userfunc.c:1833:8
#16 0x6e4b90 in eval_func /home/fuzz/fuzz/vim/afl/src/eval.c:2113:8
#17 0x6e2cfe in eval9 /home/fuzz/fuzz/vim/afl/src/eval.c:4027:9
#18 0x6eea19 in eval8 /home/fuzz/fuzz/vim/afl/src/eval.c:3596:11
#19 0x6ec808 in eval7 /home/fuzz/fuzz/vim/afl/src/eval.c:3388:9
#20 0x6e975f in eval6 /home/fuzz/fuzz/vim/afl/src/eval.c:3151:9
#21 0x6e82b2 in eval5 /home/fuzz/fuzz/vim/afl/src/eval.c:3040:9
#22 0x6e6aac in eval4 /home/fuzz/fuzz/vim/afl/src/eval.c:2891:9
#23 0x6e51af in eval3 /home/fuzz/fuzz/vim/afl/src/eval.c:2752:9
#24 0x6c0b9f in eval2 /home/fuzz/fuzz/vim/afl/src/eval.c:2626:9
#25 0x6a2aff in eval1 /home/fuzz/fuzz/vim/afl/src/eval.c:2472:9
#26 0x6bfa55 in eval0_retarg /home/fuzz/fuzz/vim/afl/src/eval.c:2389:11
#27 0x6a0097 in eval0 /home/fuzz/fuzz/vim/afl/src/eval.c:2364:12
#28 0x6a6cf5 in eval_to_string_eap /home/fuzz/fuzz/vim/afl/src/eval.c:524:9
#29 0x6a6e9f in eval_to_string /home/fuzz/fuzz/vim/afl/src/eval.c:541:12
SUMMARY: AddressSanitizer: 8 byte(s) leaked in 4 allocation(s).
Impact
Memory leaks result in general software reliability problems, but if an attacker can intentionally trigger a memory leak, the attacker might be able to launch a denial of service attack (by crashing or hanging the program) or take advantage of other unexpected program behavior resulting from a low memory condition.
The POC is very complicated. Please reduce it to the minimum needed to reproduce the problem.
The POC was reduced via afl-tmin. It seems could not be reduced anymore with the afl-tmin command.
afl-tmin -e -i /mnt/share/max/fuzz/poc/vim/poc_ml3_s.dat -o /mnt/share/max/fuzz/poc/vim/poc_ml1_s.dat -- ./vim -u NONE -i NONE -n -m -X -Z -e -s -S @@ -c :qa!
afl-tmin++4.01a by Michal Zalewski
[+] Read 211 bytes from '/mnt/share/max/fuzz/poc/vim/poc_ml3_s.dat'.
[*] Spinning up the fork server...
[+] All right - fork server is up.
[*] Target map size: 110345
[*] Performing dry run (mem limit = 0 MB, timeout = 1000 ms, edges only)...
[+] Program terminates normally, minimizing in instrumented mode.
[*] Stage #0: One-time block normalization...
[+] Block normalization complete, 0 bytes replaced.
[*] --- Pass #1 ---
[*] Stage #1: Removing blocks of data...
Block length = 16, remaining size = 211
Block length = 8, remaining size = 211
Block length = 4, remaining size = 211
Block length = 2, remaining size = 211
Block length = 1, remaining size = 211
[+] Block removal complete, 0 bytes deleted.
[*] Stage #2: Minimizing symbols (50 code points)...
[+] Symbol minimization finished, 0 symbols (0 bytes) replaced.
[*] Stage #3: Character minimization...
[+] Character minimization done, 0 bytes replaced.
File size reduced by : 0.00% (to 211 bytes)
Characters simplified : 0.00%
Number of execs done : 658
Fruitless execs : path=655 crash=0 hang=2
[*] Writing output to '/mnt/share/max/fuzz/poc/vim/poc_ml1_s.dat'...
[+] We're done here. Have a nice day!
The POC can defenitely be made shorter. I tried deleting one line with "R" and the same valgrind output results. When fixing a problem I should add a regression test, but this POC can't possibly be used as a test.
Manually reduced the POC to 28 bytes: poc_ml4.dat
./vim -u NONE -i NONE -n -m -X -Z -e -s -S ./poc_ml4.dat -c :qa!
=================================================================
==2403==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 2 byte(s) in 1 object(s) allocated from:
#0 0x499cbd in malloc (/home/fuzz/fuzz/vim/afl/src/vim+0x499cbd)
#1 0x4cb392 in lalloc /home/fuzz/fuzz/vim/afl/src/alloc.c:246:11
#2 0x4cb27a in alloc /home/fuzz/fuzz/vim/afl/src/alloc.c:151:12
#3 0xf8d4e6 in vim_strsave /home/fuzz/fuzz/vim/afl/src/strings.c:27:9
#4 0x6a6a54 in typval2string /home/fuzz/fuzz/vim/afl/src/eval.c:502:11
#5 0x6a6e4f in eval_to_string_eap /home/fuzz/fuzz/vim/afl/src/eval.c:528:11
#6 0x6a6f6f in eval_to_string /home/fuzz/fuzz/vim/afl/src/eval.c:541:12
#7 0xcecdb4 in vim_regsub_both /home/fuzz/fuzz/vim/afl/src/regexp.c:2050:17
#8 0xcf0c8b in vim_regsub_multi /home/fuzz/fuzz/vim/afl/src/regexp.c:1916:14
#9 0x7b3750 in ex_substitute /home/fuzz/fuzz/vim/afl/src/ex_cmds.c:4420:12
#10 0x7dd349 in do_one_cmd /home/fuzz/fuzz/vim/afl/src/ex_docmd.c:2570:2
#11 0x7ca205 in do_cmdline /home/fuzz/fuzz/vim/afl/src/ex_docmd.c:992:17
#12 0x1158fbc in call_user_func /home/fuzz/fuzz/vim/afl/src/userfunc.c:2900:2
#13 0x11550ad in call_user_func_check /home/fuzz/fuzz/vim/afl/src/userfunc.c:3057:2
#14 0x114f454 in call_func /home/fuzz/fuzz/vim/afl/src/userfunc.c:3613:11
#15 0x114c7f3 in get_func_tv /home/fuzz/fuzz/vim/afl/src/userfunc.c:1833:8
#16 0x6e4c60 in eval_func /home/fuzz/fuzz/vim/afl/src/eval.c:2113:8
#17 0x6e2dce in eval9 /home/fuzz/fuzz/vim/afl/src/eval.c:4027:9
#18 0x6eeae9 in eval8 /home/fuzz/fuzz/vim/afl/src/eval.c:3596:11
#19 0x6ec8d8 in eval7 /home/fuzz/fuzz/vim/afl/src/eval.c:3388:9
#20 0x6e982f in eval6 /home/fuzz/fuzz/vim/afl/src/eval.c:3151:9
#21 0x6e8382 in eval5 /home/fuzz/fuzz/vim/afl/src/eval.c:3040:9
#22 0x6e6b7c in eval4 /home/fuzz/fuzz/vim/afl/src/eval.c:2891:9
#23 0x6e527f in eval3 /home/fuzz/fuzz/vim/afl/src/eval.c:2752:9
#24 0x6c0c6f in eval2 /home/fuzz/fuzz/vim/afl/src/eval.c:2626:9
#25 0x6a2bcf in eval1 /home/fuzz/fuzz/vim/afl/src/eval.c:2472:9
#26 0x6bfb25 in eval0_retarg /home/fuzz/fuzz/vim/afl/src/eval.c:2389:11
#27 0x6a0167 in eval0 /home/fuzz/fuzz/vim/afl/src/eval.c:2364:12
#28 0x6a6dc5 in eval_to_string_eap /home/fuzz/fuzz/vim/afl/src/eval.c:524:9
#29 0x6a6f6f in eval_to_string /home/fuzz/fuzz/vim/afl/src/eval.c:541:12
SUMMARY: AddressSanitizer: 2 byte(s) leaked in 1 allocation(s).
Thanks, now I can reproduce it. Looks like this happens because vim_regsub_both() is called only once, the static string copy then is lost.
Fixed with patch 8.2.5146. Used the POC as a regression test. This may also fix previously reported problems in a better way.
Hmm, the "Mark as fixed" button is broken... Github commit: 44ddf19ec0ff59c969658ec7d9ed42070c59c51b
@Bram - Apologies for the breakage issue last week. We quickly identified the issue and released a patch.
As requested above by the researcher, are you happy for a CVE to be assigned and published for this report?
I have no opinion about which issues are worth creating a CVE for. Generally, these problems require a user to execute commands provided by an attacker, in which case those commands can do various nasty things already. It might just be better hidden.