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

Takashi Yano via Cygwin-cvs <[email protected]> Sun, 29 Mar 2026 00:44:05 +0000 (GMT)
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D3adbd41f5ba=
bda5a42430fb25d9a02205c416542

commit 3adbd41f5babda5a42430fb25d9a02205c416542
Author: Takashi Yano <[email protected]>
Date:   Tue Mar 17 11:59:21 2026 +0900

    Cygwin: pty: Guard get_winpid_to_hand_over() with attach_mutex
   =20
    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.
   =20
    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.
   =20
    Fixes: 1e6c51d74136 ("Cygwin: pty: Reorganize the code path of setting =
up and closing pcon.")
    Signed-off-by: Takashi Yano <[email protected]>
    Reviewed-by: Johannes Schindelin <[email protected]>

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 =3D "open pipe switch mutex failed, %E";
       goto err;
     }
+  if (!(attach_mutex
+	=3D get_ttyp ()->open_mutex (ATTACH_MUTEX, MAXIMUM_ALLOWED)))
+    {
+      errmsg =3D "open attach mutex failed, %E";
+      goto err;
+    }
   shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
   if (!(input_available_event =3D 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 =3D get_ttyp ()->open_mutex (ATTACH_MUTEX, MAXIMUM_ALLOWED);
=20
   // fork_fixup (parent, inuse, "inuse");
   // fhandler_pty_common::fixup_after_fork (parent);
@@ -3161,8 +3170,9 @@ fhandler_pty_master::setup ()
   if (!(pipe_sw_mutex =3D CreateMutex (&sa, FALSE, buf)))
     goto err;
=20
-  if (!attach_mutex)
-    attach_mutex =3D CreateMutex (&sec_none_nih, FALSE, NULL);
+  errstr =3D shared_name (buf, ATTACH_MUTEX, unit);
+  if (!(attach_mutex =3D CreateMutex (&sa, FALSE, buf)))
+    goto err;
=20
   /* 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 *tty=
p,
       DWORD current_pid =3D myself->exec_dwProcessId ?: myself->dwProcessI=
d;
       if (ttyp->nat_pipe_owner_pid =3D=3D GetCurrentProcessId ())
 	current_pid =3D GetCurrentProcessId ();
+      acquire_attach_mutex (mutex_timeout);
       switch_to =3D 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 *tty=
p,
       if (!switch_to && ttyp->pcon_activated)
 	switch_to =3D 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_inclu=
des/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"