[newlib-cygwin] Cygwin: pty: Guard get_winpid_to_hand_over() with attach_mutex

Takashi Yano tyan0@sourceware.org
Sun Mar 29 00:44:05 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=3adbd41f5babda5a42430fb25d9a02205c416542

commit 3adbd41f5babda5a42430fb25d9a02205c416542
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date:   Tue Mar 17 11:59:21 2026 +0900

    Cygwin: pty: Guard get_winpid_to_hand_over() with attach_mutex
    
    The master process (e.g. mintty) temporarily attaches to the pseudo
    console's conhost in `transfer_input()` so it can read
    INPUT_RECORDs via `ReadConsoleInputA()`. During that brief window,
    `get_console_process_id()` inside `get_winpid_to_hand_over()` calls
    `GetConsoleProcessList()`, which sees the master among the console's
    attached processes and may select it as the handover target. That is
    wrong because the master will detach immediately after the read.
    
    Until now, `attach_mutex` was a process-local unnamed mutex, so
    the slave's `get_winpid_to_hand_over()` could not serialize with
    the master's temporary attachment. Make `attach_mutex` a
    cross-process named mutex (`ATTACH_MUTEX`) shared within the PTY,
    and acquire it around the `get_console_process_id()` calls in
    `get_winpid_to_hand_over()`. This ensures the console process list
    enumeration never observes the master while it is temporarily
    attached.
    
    Fixes: 1e6c51d74136 ("Cygwin: pty: Reorganize the code path of setting up and closing pcon.")
    Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
    Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

Diff:
---
 winsup/cygwin/fhandler/pty.cc      | 16 ++++++++++++++--
 winsup/cygwin/local_includes/tty.h |  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 90c7a9710..ac5f67bc4 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -774,6 +774,12 @@ fhandler_pty_slave::open (int flags, mode_t)
       errmsg = "open pipe switch mutex failed, %E";
       goto err;
     }
+  if (!(attach_mutex
+	= get_ttyp ()->open_mutex (ATTACH_MUTEX, MAXIMUM_ALLOWED)))
+    {
+      errmsg = "open attach mutex failed, %E";
+      goto err;
+    }
   shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
   if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf)))
     {
@@ -2525,6 +2531,9 @@ void
 fhandler_pty_slave::fixup_after_fork (HANDLE parent)
 {
   create_invisible_console ();
+  /* attach_mutex is initialized not only in the fork() case, but also in
+     the exec() case, since fixup_after_exec() calls fixup_after_fork(). */
+  attach_mutex = get_ttyp ()->open_mutex (ATTACH_MUTEX, MAXIMUM_ALLOWED);
 
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
@@ -3161,8 +3170,9 @@ fhandler_pty_master::setup ()
   if (!(pipe_sw_mutex = CreateMutex (&sa, FALSE, buf)))
     goto err;
 
-  if (!attach_mutex)
-    attach_mutex = CreateMutex (&sec_none_nih, FALSE, NULL);
+  errstr = shared_name (buf, ATTACH_MUTEX, unit);
+  if (!(attach_mutex = CreateMutex (&sa, FALSE, buf)))
+    goto err;
 
   /* Create master control pipe which allows the master to duplicate
      the pty pipe handles to processes which deserve it. */
@@ -3716,6 +3726,7 @@ fhandler_pty_slave::get_winpid_to_hand_over (tty *ttyp,
       DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId;
       if (ttyp->nat_pipe_owner_pid == GetCurrentProcessId ())
 	current_pid = GetCurrentProcessId ();
+      acquire_attach_mutex (mutex_timeout);
       switch_to = get_console_process_id (current_pid,
 					  false, true, true, true);
       if (!switch_to)
@@ -3724,6 +3735,7 @@ fhandler_pty_slave::get_winpid_to_hand_over (tty *ttyp,
       if (!switch_to && ttyp->pcon_activated)
 	switch_to = get_console_process_id (current_pid,
 					    false, false, false, false);
+      release_attach_mutex ();
     }
   return switch_to;
 }
diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h
index cd1e202f1..962697782 100644
--- a/winsup/cygwin/local_includes/tty.h
+++ b/winsup/cygwin/local_includes/tty.h
@@ -22,6 +22,7 @@ details. */
 #define OUTPUT_MUTEX		"cygtty.output.mutex"
 #define INPUT_MUTEX		"cygtty.input.mutex"
 #define PIPE_SW_MUTEX		"cygtty.pipe_sw.mutex"
+#define ATTACH_MUTEX		"cygtty.attach.mutex"
 #define TTY_SLAVE_ALIVE		"cygtty.slave_alive"
 #define TTY_SLAVE_READING	"cygtty.slave_reading"


More information about the Cygwin-cvs mailing list