CVE-2023-4752: Use After Free (CWE-416)
value: Use After Free in GitHub repository vim/vim prior to 9.0.1858.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
CVSS v3 base score: 7.8
Published: 2023-09-04T14:15Z
Repository: https://github.com/vim/vim
Language: Other
Files changed: src/insexpand.c, src/testdir/crash/poc_tagfunc.vim, src/testdir/test_crash.vim, src/version.c
Commit date: 2023-09-03 21:24:33 +0200
Commit message: patch 9.0.1858: [security] heap use after free in ins_compl_get_exp()

Problem:  heap use after free in ins_compl_get_exp()
Solution: validate buffer before accessing it

Signed-off-by: Christian Brabandt <cb@256bit.org>

Diff: diff --git a/src/insexpand.c b/src/insexpand.c
index 3cfdface4413..b767b4efddb0 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -3848,11 +3848,11 @@ ins_compl_get_exp(pos_T *ini)
 	    compl_started = TRUE;
 	}
 	else
 	{
 	    // Mark a buffer scanned when it has been scanned completely
-	    if (type == 0 || type == CTRL_X_PATH_PATTERNS)
+	    if (buf_valid(st.ins_buf) && (type == 0 || type == CTRL_X_PATH_PATTERNS))
 		st.ins_buf->b_scanned = TRUE;
 
 	    compl_started = FALSE;
 	}
     }
diff --git a/src/testdir/crash/poc_tagfunc.vim b/src/testdir/crash/poc_tagfunc.vim
new file mode 100644
index 000000000000..49d9b6f71999
--- /dev/null
+++ b/src/testdir/crash/poc_tagfunc.vim
@@ -0,0 +1,6 @@
+fu Tagfunc(t,f,o)
+  bw
+endf
+set tagfunc=Tagfunc
+n0
+sil0norm0i
diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim
index 516d99193962..27bf7b55d46e 100644
--- a/src/testdir/test_crash.vim
+++ b/src/testdir/test_crash.vim
@@ -37,25 +37,31 @@ func Test_crash1()
   let args = printf(cmn_args, vim, file)
   call term_sendkeys(buf, args ..
     \ '  && echo "crash 4: [OK]" >> X_crash1_result.txt' .. "\<cr>")
   " clean up
   call delete('Xerr')
-
   " This test takes a bit longer
   call TermWait(buf, 200)
 
+  let file = 'crash/poc_tagfunc.vim'
+  let args = printf(cmn_args, vim, file)
+  call term_sendkeys(buf, args ..
+    \ '  || echo "crash 5: [OK]" >> X_crash1_result.txt' .. "\<cr>")
+
+  call TermWait(buf, 100)
+
   " clean up
-  call delete('Xerr')
   exe buf .. "bw!"
 
   sp X_crash1_result.txt
 
   let expected = [
       \ 'crash 1: [OK]',
       \ 'crash 2: [OK]',
       \ 'crash 3: [OK]',
       \ 'crash 4: [OK]',
+      \ 'crash 5: [OK]',
       \ ]
 
   call assert_equal(expected, getline(1, '$'))
   bw!
 
diff --git a/src/version.c b/src/version.c
index 13d5d695a69f..b604b57f8b37 100644
--- a/src/version.c
+++ b/src/version.c
@@ -697,10 +697,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1858,
 /**/
     1857,
 /**/
     1856,
 /**/

Vulnerable code: 	    if (type == 0 || type == CTRL_X_PATH_PATTERNS)

  call delete('Xerr')
Fixed code: 	    if (buf_valid(st.ins_buf) && (type == 0 || type == CTRL_X_PATH_PATTERNS))
fu Tagfunc(t,f,o)
  bw
endf
set tagfunc=Tagfunc
n0
sil0norm0i
  let file = 'crash/poc_tagfunc.vim'
  let args = printf(cmn_args, vim, file)
  call term_sendkeys(buf, args ..
    \ '  || echo "crash 5: [OK]" >> X_crash1_result.txt' .. "\<cr>")

  call TermWait(buf, 100)

      \ 'crash 5: [OK]',
/**/
    1858,