CVE-2022-1968: Use After Free (CWE-416)
value: Use After Free in GitHub repository vim/vim prior to 8.2.
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: 2022-06-02T14:15Z
Repository: https://github.com/vim/vim
Language: C
Files changed: src/search.c, src/testdir/test_tagjump.vim, src/version.c
Commit date: 2022-06-01 15:23:13 +0100
Commit message: patch 8.2.5050: using freed memory when searching for pattern in path

Problem:    Using freed memory when searching for pattern in path.
Solution:   Make a copy of the line.

Diff: diff --git a/src/search.c b/src/search.c
index ea72ec7fb9d7..35dc89b8fe4a 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3303,10 +3303,25 @@ update_search_stat(
     stat->last_maxcount = last_maxcount;
     p_ws = save_ws;
 }
 
 #if defined(FEAT_FIND_ID) || defined(PROTO)
+
+/*
+ * Get line "lnum" and copy it into "buf[LSIZE]".
+ * The copy is made because the regexp may make the line invalid when using a
+ * mark.
+ */
+    static char_u *
+get_line_and_copy(linenr_T lnum, char_u *buf)
+{
+    char_u *line = ml_get(lnum);
+
+    vim_strncpy(buf, line, LSIZE - 1);
+    return buf;
+}
+
 /*
  * Find identifiers or defines in included files.
  * If p_ic && compl_status_sol() then ptr must be in lowercase.
  */
     void
@@ -3407,11 +3422,11 @@ find_pattern_in_path(
     lnum = start_lnum;
     if (end_lnum > curbuf->b_ml.ml_line_count)
 	end_lnum = curbuf->b_ml.ml_line_count;
     if (lnum > end_lnum)		// do at least one line
 	lnum = end_lnum;
-    line = ml_get(lnum);
+    line = get_line_and_copy(lnum, file_line);
 
     for (;;)
     {
 	if (incl_regmatch.regprog != NULL
 		&& vim_regexec(&incl_regmatch, line, (colnr_T)0))
@@ -3736,11 +3751,11 @@ search_line:
 		    // exit_matched when past the last line.
 		    if (depth < 0)
 		    {
 			if (lnum >= end_lnum)
 			    goto exit_matched;
-			line = ml_get(++lnum);
+			line = get_line_and_copy(++lnum, file_line);
 		    }
 		    else if (vim_fgets(line = file_line,
 						      LSIZE, files[depth].fp))
 			goto exit_matched;
 
@@ -3948,11 +3963,11 @@ exit_matched:
 	}
 	else if (!already)
 	{
 	    if (++lnum > end_lnum)
 		break;
-	    line = ml_get(lnum);
+	    line = get_line_and_copy(lnum, file_line);
 	}
 	already = NULL;
     }
     // End of big for (;;) loop.
 
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
index aacfb9baeb56..060cc3b188c8 100644
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -1288,10 +1288,21 @@ func Test_inc_search()
   call assert_fails('isplit bar', 'E389:')
 
   close!
 endfunc
 
+" this was using a line from ml_get() freed by the regexp
+func Test_isearch_copy_line()
+  new
+  norm o
+  norm 0
+  0norm o
+  sil! norm bc0
+  sil! isearch \%')
+  bwipe!
+endfunc
+
 " Test for :dsearch, :dlist, :djump and :dsplit commands
 " Test for [d, ]d, [D, ]D, [ CTRL-D, ] CTRL-D and CTRL-W d commands
 func Test_macro_search()
   new
   call setline(1, ['#define FOO 1', '#define FOO 2', '#define FOO 3',
diff --git a/src/version.c b/src/version.c
index 97ca8ce5cb40..ba8688bc55c9 100644
--- a/src/version.c
+++ b/src/version.c
@@ -732,10 +732,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    5050,
 /**/
     5049,
 /**/
     5048,
 /**/

Vulnerable code:     line = ml_get(lnum);
			line = ml_get(++lnum);
	    line = ml_get(lnum);
Fixed code: 
/*
 * Get line "lnum" and copy it into "buf[LSIZE]".
 * The copy is made because the regexp may make the line invalid when using a
 * mark.
 */
    static char_u *
get_line_and_copy(linenr_T lnum, char_u *buf)
{
    char_u *line = ml_get(lnum);

    vim_strncpy(buf, line, LSIZE - 1);
    return buf;
}

    line = get_line_and_copy(lnum, file_line);
			line = get_line_and_copy(++lnum, file_line);
	    line = get_line_and_copy(lnum, file_line);
" this was using a line from ml_get() freed by the regexp
func Test_isearch_copy_line()
  new
  norm o
  norm 0
  0norm o
  sil! norm bc0
  sil! isearch \%')
  bwipe!
endfunc

/**/
    5050,