CVE-2023-5535: Use After Free (CWE-416)
value: Use After Free in GitHub repository vim/vim prior to v9.0.2010.
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-10-11T20:15Z
Repository: https://github.com/vim/vim
Language: C
Files changed: src/buffer.c, src/testdir/test_crash.vim, src/version.c
Commit date: 2023-10-11 21:09:53 +0200
Commit message: patch 9.0.2010: [security] use-after-free from buf_contents_changed()

Problem:  [security] use-after-free from buf_contents_changed()
Solution: block autocommands

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

Diff: diff --git a/src/buffer.c b/src/buffer.c
index 93f9245f27f9..9ee74f54dd6f 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -6011,10 +6011,13 @@ buf_contents_changed(buf_T *buf)
 	// Failed to find a window for "newbuf".
 	wipe_buffer(newbuf, FALSE);
 	return TRUE;
     }
 
+    // We don't want to trigger autocommands now, they may have nasty
+    // side-effects like wiping buffers
+    block_autocmds();
     if (ml_open(curbuf) == OK
 	    && readfile(buf->b_ffname, buf->b_fname,
 				  (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
 					    &ea, READ_NEW | READ_DUMMY) == OK)
     {
@@ -6036,10 +6039,12 @@ buf_contents_changed(buf_T *buf)
     aucmd_restbuf(&aco);
 
     if (curbuf != newbuf)	// safety check
 	wipe_buffer(newbuf, FALSE);
 
+    unblock_autocmds();
+
     return differ;
 }
 
 /*
  * Wipe out a buffer and decrement the last buffer number if it was used for
diff --git a/src/testdir/crash/editing_arg_idx_POC_1 b/src/testdir/crash/editing_arg_idx_POC_1
new file mode 100644
index 000000000000..5d048d03405a
Binary files /dev/null and b/src/testdir/crash/editing_arg_idx_POC_1 differ
diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim
index 9a80340c285d..5cd07e2a3f0b 100644
--- a/src/testdir/test_crash.vim
+++ b/src/testdir/test_crash.vim
@@ -76,10 +76,18 @@ func Test_crash1()
   let args = printf(cmn_args, vim, file)
   call term_sendkeys(buf, args ..
     \ '  && echo "crash 9: [OK]" >> X_crash1_result.txt' .. "\<cr>")
   call TermWait(buf, 1000)
 
+  let file = 'crash/editing_arg_idx_POC_1'
+  let args = printf(cmn_args, vim, file)
+  call term_sendkeys(buf, args ..
+    \ '  || echo "crash 10: [OK]" >> X_crash1_result.txt' .. "\<cr>")
+  call TermWait(buf, 1000)
+  call delete('Xerr')
+  call delete('@')
+
   " clean up
   exe buf .. "bw!"
 
   sp X_crash1_result.txt
 
@@ -91,10 +99,11 @@ func Test_crash1()
       \ 'crash 5: [OK]',
       \ 'crash 6: [OK]',
       \ 'crash 7: [OK]',
       \ 'crash 8: [OK]',
       \ 'crash 9: [OK]',
+      \ 'crash 10: [OK]',
       \ ]
 
   call assert_equal(expected, getline(1, '$'))
   bw!
 
diff --git a/src/version.c b/src/version.c
index 458b46a37136..0479f2096d42 100644
--- a/src/version.c
+++ b/src/version.c
@@ -702,10 +702,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2010,
 /**/
     2009,
 /**/
     2008,
 /**/

Fixed code:     // We don't want to trigger autocommands now, they may have nasty
    // side-effects like wiping buffers
    block_autocmds();
    unblock_autocmds();

  let file = 'crash/editing_arg_idx_POC_1'
  let args = printf(cmn_args, vim, file)
  call term_sendkeys(buf, args ..
    \ '  || echo "crash 10: [OK]" >> X_crash1_result.txt' .. "\<cr>")
  call TermWait(buf, 1000)
  call delete('Xerr')
  call delete('@')

      \ 'crash 10: [OK]',
/**/
    2010,