CVE-2023-4750 (published 2023-09-04T14:15Z)

Use After Free in GitHub repository vim/vim prior to 9.0.1857.

CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-416
cwe_name: Use After Free
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.
extended_description: 
             
             
             
			 
             
             
         
         

Fix information:
repo_url: https://github.com/vim/vim
commit_details: repo_url: https://github.com/vim/vim
author: Christian Brabandt
author_date: 2023-09-03 20:20:52+02:00
msg: patch 9.0.1857: [security] heap-use-after-free in is_qf_win()

Problem:  heap-use-after-free in is_qf_win()
Solution: Check buffer is valid before accessing it

Signed-off-by: Christian Brabandt <cb@256bit.org>
repository: repo_url: https://github.com/vim/vim
repo_name: vim/vim
description: The official Vim repository
repo_language: Vim Script
owner: vim
file_changes: filename: main.c
change_type: ModificationType.MODIFY
diff: @@ -1646,7 +1646,7 @@ getout(int exitval)
 	    next_tp = tp->tp_next;
 	    FOR_ALL_WINDOWS_IN_TAB(tp, wp)
 	    {
-		if (wp->w_buffer == NULL)
+		if (wp->w_buffer == NULL || !buf_valid(wp->w_buffer))
 		    // Autocmd must have close the buffer already, skip.
 		    continue;
 		buf = wp->w_buffer;

programming_language: C
filename: quickfix.c
change_type: ModificationType.MODIFY
diff: @@ -4492,7 +4492,7 @@ is_qf_win(win_T *win, qf_info_T *qi)
     // set to NULL.
     // A window displaying a location list buffer will have the w_llist_ref
     // pointing to the location list.
-    if (bt_quickfix(win->w_buffer))
+    if (buf_valid(win->w_buffer) && bt_quickfix(win->w_buffer))
 	if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
 		|| (IS_LL_STACK(qi) && win->w_llist_ref == qi))
 	    return TRUE;

programming_language: C
filename: bt_quickfix_poc
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+comman!-narg=* Xexpr <mods>lex<args>
+auto BufReadPre * exe"sn" ..expand("<abuf>") 
+fu Xautocmd_changelist()
+cal writefile(['Xtestfile2:4:4'],'Xerr')
+  sil! edi Xerr
+Xexpr 'Xtestfile:4:4'
+endf
+call Xautocmd_changelist()
+call Xautocmd_changelist()
\ No newline at end of file

programming_language: Batchfile
filename: test_crash.vim
change_type: ModificationType.MODIFY
diff: @@ -5,38 +5,58 @@ source screendump.vim
 CheckScreendump
 
 func Test_crash1()
+  if !executable('sh')
+    throw 'Skipped: sh not executable!'
+  endif
   " The following used to crash Vim
-  " let opts = #{wait_for_ruler: 0, rows: 20, cmd: 'sh'}
   let opts = #{cmd: 'sh'}
-  let args = 'bash'
   let vim  = GetVimProg()
 
-  let buf = RunVimInTerminal(args, opts)
+  let buf = RunVimInTerminal('sh', opts)
 
   let file = 'crash/poc_huaf1'
   let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
   let args = printf(cmn_args, vim, file)
   call term_sendkeys(buf, args ..
-    \ '  && echo "crash 1: [OK]" >> X_crash1_result.txt' .. "\<cr>")
+    \ '  && echo "crash 1: [OK]" > X_crash1_result.txt' .. "\<cr>")
+  call TermWait(buf, 50)
 
   let file = 'crash/poc_huaf2'
   let args = printf(cmn_args, vim, file)
   call term_sendkeys(buf, args ..
     \ '  && echo "crash 2: [OK]" >> X_crash1_result.txt' .. "\<cr>")
+  call TermWait(buf, 50)
 
   let file = 'crash/poc_huaf3'
   let args = printf(cmn_args, vim, file)
   call term_sendkeys(buf, args ..
     \ '  && echo "crash 3: [OK]" >> X_crash1_result.txt' .. "\<cr>")
+  call TermWait(buf, 100)
 
-  call TermWait(buf, 50)
+  let file = 'crash/bt_quickfix_poc'
+  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)
 
   " clean up
+  call delete('Xerr')
   exe buf .. "bw!"
 
   sp X_crash1_result.txt
-  call assert_equal(['crash 1: [OK]', 'crash 2: [OK]', 'crash 3: [OK]'],
-    \ getline(1, '$'))
+
+  let expected = [
+      \ 'crash 1: [OK]',
+      \ 'crash 2: [OK]',
+      \ 'crash 3: [OK]',
+      \ 'crash 4: [OK]',
+      \ ]
+
+  call assert_equal(expected, getline(1, '$'))
   bw!
 
   call delete('X_crash1_result.txt')

programming_language: Shell
filename: version.c
change_type: ModificationType.MODIFY
diff: @@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1857,
 /**/
     1856,
 /**/

programming_language: Ruby