[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