patch 9.2.0616: GTK4: use-after-free on clipboard read timeout

Commit: 
https://github.com/vim/vim/commit/2d3e3fe7846410f6ab4d9e09c9f1ef5c6672a2d2
Author: Yasuhiro Matsumoto <[email protected]>
Date:   Wed Jun 10 20:37:11 2026 +0000

    patch 9.2.0616: GTK4: use-after-free on clipboard read timeout
    
    Problem:  clip_mch_request_selection() stack-allocates ClipReadData
              and waits up to 3 seconds for the async callback to fire.
              If the timeout expires before the callback runs, the
              function returns and the stack frame is gone, but the async
              read is still pending; when the callback eventually fires
              it a use-after-free.
    Solution: Heap-allocate ClipReadData and add an "abandoned" flag
              (Yasuhiro Matsumoto).
    
    closes: #20467
    
    Co-Authored-by: Claude <[email protected]>
    Signed-off-by: Yasuhiro Matsumoto <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c
index 9c913bc71..dd4946793 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -3554,6 +3554,7 @@ gtk4_get_clipboard(Clipboard_T *cbd, GdkContentProvider 
**provider)
 typedef struct {
     Clipboard_T *cbd;
     gboolean   done;
+    gboolean   abandoned;      // requester timed out, callback owns "crd"
 } ClipReadData;
 
 /*
@@ -3596,7 +3597,7 @@ clip_read_cb(GdkClipboard *cb, GAsyncResult *result, 
ClipReadData *crd)
     len = (long)arr->len;
     actual = final = g_byte_array_free(arr, FALSE);
 
-    if (clip_convert_data(&final, &len, &motion_type,
+    if (!crd->abandoned && clip_convert_data(&final, &len, &motion_type,
            STRCMP(mime_type, VIM_MIMETYPE_NAME) == 0,
            STRCMP(mime_type, VIMENC_MIMETYPE_NAME) == 0, &tofree) == OK)
        clip_yank_selection(motion_type, final, len, cbd);
@@ -3606,7 +3607,11 @@ clip_read_cb(GdkClipboard *cb, GAsyncResult *result, 
ClipReadData *crd)
 exit:
     if (in_stream != NULL)
        g_object_unref(in_stream);
-    crd->done = TRUE;
+    // free "crd" if the requester gave up, else mark the read complete
+    if (crd->abandoned)
+       vim_free(crd);
+    else
+       crd->done = TRUE;
 }
 
 /*
@@ -3623,25 +3628,37 @@ clip_mch_request_selection(Clipboard_T *cbd)
        NULL
     };
     GdkClipboard       *clipboard;
-    ClipReadData       crd;
+    ClipReadData       *crd;
     time_t             start;
 
     clipboard = gtk4_get_clipboard(cbd, NULL);
     if (clipboard == NULL)
        return;
 
-    crd.cbd = cbd;
-    crd.done = FALSE;
+    // Heap-allocate: on a timeout this returns before the read completes,
+    // so "crd" must outlive this stack frame.
+    crd = ALLOC_ONE(ClipReadData);
+    if (crd == NULL)
+       return;
+    crd->cbd = cbd;
+    crd->done = FALSE;
+    crd->abandoned = FALSE;
 
     gdk_clipboard_read_async(
            clipboard, clip_html ? supported_mimes : mimes_no_html,
-           G_PRIORITY_HIGH, NULL, (GAsyncReadyCallback)clip_read_cb, &crd);
+           G_PRIORITY_HIGH, NULL, (GAsyncReadyCallback)clip_read_cb, crd);
 
     // Spin until the async callback fires, with a 3-second wall-clock
     // timeout as a safety net.
     start = time(NULL);
-    while (!crd.done && time(NULL) < start + 3)
+    while (!crd->done && time(NULL) < start + 3)
        g_main_context_iteration(NULL, TRUE);
+
+    if (crd->done)
+       vim_free(crd);
+    else
+       // timed out: hand ownership to the callback, which frees "crd"
+       crd->abandoned = TRUE;
 }
 
 static int in_clipboard_set = FALSE;
diff --git a/src/version.c b/src/version.c
index 319f43ba6..7790231b8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    616,
 /**/
     615,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wXPnN-008TXT-Ol%40256bit.org.

Raspunde prin e-mail lui