Cygwin: pty: do not leak nat handles when adopting the pcon's in open_setup()

When a Cygwin process opens a pty slave whose pseudo console is already
active, open() has just installed duplicates of the cyg master-side
pipe ends into io_handle_nat and output_handle_nat. The pcon adoption
added in "Cygwin: pty: Fixup pty state after a cygwin app exits"
overwrites those two slots via &get_handle_nat() / &get_output_handle_nat()
without closing them first, so two handles leak on every pcon-backed
grandchild open. It also hands the result of OpenProcess() straight to
DuplicateHandle() without a NULL check, so if the nat-pipe owner has
already exited both duplications fail and leave the nat slots NULL,
which then breaks the slave's input routing.

Close the old slots before replacing them, skip the replacement
entirely when OpenProcess() returns NULL so we degrade to the handles
open() installed, and make the pair transactional so a partial success
cannot leave one original slot and one pcon slot.

Fixes: b34394d456 ("Cygwin: pty: Fixup pty state after a cygwin app exits")
Assisted-by: Opus 4.8
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Reviewed-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
Johannes Schindelin authored and Takashi Yano committed 2026-06-30 17:32:08 +09:00
1 parent 10140bec21
commit 60a88896dc
1 file changed
+27 -7
+27 -7
View File
@@ -1212,13 +1212,33 @@ fhandler_pty_slave::open_setup (int flags)
{
HANDLE pcon_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
get_ttyp ()->nat_pipe_owner_pid);
DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
GetCurrentProcess (), &get_handle_nat (),
0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out,
GetCurrentProcess (), &get_output_handle_nat (),
0, TRUE, DUPLICATE_SAME_ACCESS);
CloseHandle (pcon_owner);
if (pcon_owner)
{
HANDLE new_in = NULL, new_out = NULL;
bool ok_in = DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in,
GetCurrentProcess (), &new_in,
0, TRUE, DUPLICATE_SAME_ACCESS);
bool ok_out = DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out,
GetCurrentProcess (), &new_out,
0, TRUE, DUPLICATE_SAME_ACCESS);
if (ok_in && ok_out)
{
/* Close the cyg master-side handles open() installed before
replacing them, so they do not leak. */
CloseHandle (get_handle_nat ());
CloseHandle (get_output_handle_nat ());
set_handle_nat (new_in);
set_output_handle_nat (new_out);
}
else
{
if (new_in)
CloseHandle (new_in);
if (new_out)
CloseHandle (new_out);
}
CloseHandle (pcon_owner);
}
}
set_flags ((flags & ~O_TEXT) | O_BINARY);