1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
From: Markus Koschany <apo@debian.org>
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(-)
--- 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;
--- 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
+
|