CVE-2022-2289: Use After Free (CWE-416)
value: Use After Free in GitHub repository vim/vim prior to 9.0.
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-07-03T15:15Z
Repository: https://github.com/vim/vim
Language: C
Files changed: src/diff.c, src/version.c
Commit date: 2022-07-02 15:10:00 +0100
Commit message: patch 9.0.0026: accessing freed memory with diff put

Problem:    Accessing freed memory with diff put.
Solution:   Bail out when diff pointer is no longer valid.

Diff: diff --git a/src/diff.c b/src/diff.c
index 91e5ae2f2f68..e4bafe2c934e 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -2640,10 +2640,24 @@ nv_diffgetput(int put, long count)
     ea.line1 = curwin->w_cursor.lnum;
     ea.line2 = curwin->w_cursor.lnum;
     ex_diffgetput(&ea);
 }
 
+/*
+ * Return TRUE if "diff" appears in the list of diff blocks of the current tab.
+ */
+    static int
+valid_diff(diff_T *diff)
+{
+    diff_T	*dp;
+
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
+	if (dp == diff)
+	    return TRUE;
+    return FALSE;
+}
+
 /*
  * ":diffget"
  * ":diffput"
  */
     void
@@ -2897,13 +2911,13 @@ ex_diffgetput(exarg_T *eap)
 		    else
 			dprev->df_next = dp;
 		}
 	    }
 
-	    // Adjust marks.  This will change the following entries!
 	    if (added != 0)
 	    {
+		// Adjust marks.  This will change the following entries!
 		mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added);
 		if (curwin->w_cursor.lnum >= lnum)
 		{
 		    // Adjust the cursor position if it's in/after the changed
 		    // lines.
@@ -2921,11 +2935,17 @@ ex_diffgetput(exarg_T *eap)
 #ifdef FEAT_FOLDING
 		diff_fold_update(dfree, idx_to);
 #endif
 		vim_free(dfree);
 	    }
-	    else
+
+	    // mark_adjust() may have made "dp" invalid.  We don't know where
+	    // to continue then, bail out.
+	    if (added != 0 && !valid_diff(dp))
+		break;
+
+	    if (dfree == NULL)
 		// mark_adjust() may have changed the count in a wrong way
 		dp->df_count[idx_to] = new_count;
 
 	    // When changing the current buffer, keep track of line numbers
 	    if (idx_cur == idx_to)
diff --git a/src/version.c b/src/version.c
index 8c9325d9410e..0eb586396781 100644
--- a/src/version.c
+++ b/src/version.c
@@ -733,10 +733,12 @@ static char *(features[]) =
 	NULL
 };
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    26,
 /**/
     25,
 /**/
     24,
 /**/

Vulnerable code: 	    // Adjust marks.  This will change the following entries!
	    else
Fixed code: /*
 * Return TRUE if "diff" appears in the list of diff blocks of the current tab.
 */
    static int
valid_diff(diff_T *diff)
{
    diff_T	*dp;

    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
	if (dp == diff)
	    return TRUE;
    return FALSE;
}

		// Adjust marks.  This will change the following entries!

	    // mark_adjust() may have made "dp" invalid.  We don't know where
	    // to continue then, bail out.
	    if (added != 0 && !valid_diff(dp))
		break;

	    if (dfree == NULL)
/**/
    26,