From: Markus Koschany Date: Wed, 26 Oct 2022 23:24:00 +0200 Subject: CVE-2022-0413 Origin: https://github.com/vim/vim/commit/37f47958b8a2a44abc60614271d9537e7f14e51a --- src/ex_cmds.c | 19 +++++++++++++++---- src/testdir/test_substitute.vim | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index b18f58c..5ad8913 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -4857,6 +4857,7 @@ do_sub(exarg_T *eap) int save_do_all; /* remember user specified 'g' flag */ int save_do_ask; /* remember user specified 'c' flag */ char_u *pat = NULL, *sub = NULL; /* init for GCC */ + char_u *sub_copy = NULL; int delimiter; int sublen; int got_quit = FALSE; @@ -5152,11 +5153,20 @@ do_sub(exarg_T *eap) sub_firstline = NULL; /* - * ~ in the substitute pattern is replaced with the old pattern. - * We do it here once to avoid it to be replaced over and over again. - * But don't do it when it starts with "\=", then it's an expression. + * If the substitute pattern starts with "\=" then it's an expression. + * Make a copy, a recursive function may free it. + * Otherwise, '~' in the substitute pattern is replaced with the old + * pattern. We do it here once to avoid it to be replaced over and over + * again. */ - if (!(sub[0] == '\\' && sub[1] == '=')) + if (sub[0] == '\\' && sub[1] == '=') + { + sub = vim_strsave(sub); + if (sub == NULL) + return; + sub_copy = sub; + } + else sub = regtilde(sub, p_magic); /* @@ -5925,6 +5935,7 @@ outofmem: #endif vim_regfree(regmatch.regprog); + vim_free(sub_copy); /* Restore the flag values, they can be used for ":&&". */ subflags.do_all = save_do_all; diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index d84daa7..c1e8f30 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -500,3 +500,20 @@ func Test_sub_cmd_8() enew! set titlestring& endfunc + +" This was using "old_sub" after it was freed. +func Test_using_old_sub() + set compatible maxfuncdepth=10 + new + call setline(1, 'some text.') + func Repl() + ~ + s/ + endfunc + silent! s/\%')/\=Repl() + + delfunc Repl + bwipe! + set nocompatible +endfunc +