From c605ea0d6d796036672d4ea9de384f84e96d2eb9 Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Mon, 30 Nov 2020 17:47:25 -0500 Subject: [PATCH] Cygwin: AF_UNIX: SCM_RIGHTS: support pty slave descriptors This is the first case where the fhandler being sent uses an archetype. This archetype is of no use to the receiving process, so we have to make the following changes: - Modify fhandler_pty_slave::dup so that it duplicates handles when it is called on an fhandler that doesn't yet have an archetype. - Modify dtable::dup_worker so that it creates an archetype for the new fhandler after fhandler_pty_slave::dup returns. --- winsup/cygwin/dtable.cc | 71 ++++++++++------ winsup/cygwin/fhandler_socket_unix.cc | 39 ++++++--- winsup/cygwin/fhandler_tty.cc | 111 +++++++++++++++++++++++++- 3 files changed, 185 insertions(+), 36 deletions(-) diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 0e5370abc..09e2744da 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -677,35 +677,56 @@ out: fhandler_base * dtable::dup_worker (fhandler_base *oldfh, int flags, DWORD src_pid) { + bool need_new_arch = false; fhandler_base *newfh = oldfh->clone (); + if (!newfh) - debug_printf ("clone failed"); - else { - if (!oldfh->archetype) - newfh->set_handle (NULL); - - newfh->pc.reset_conv_handle (); - if (oldfh->dup (newfh, flags, src_pid)) - { - delete newfh; - newfh = NULL; - debug_printf ("oldfh->dup failed"); - } - else - { - /* Don't increment refcnt here since we don't know if this is a - allocated fd. So we leave this chore to the caller. */ - - newfh->usecount = 0; - newfh->archetype_usecount (1); - - /* The O_CLOEXEC flag enforces close-on-exec behaviour. */ - newfh->set_close_on_exec (!!(flags & O_CLOEXEC)); - debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), - oldfh->get_handle (), newfh->get_handle ()); - } + debug_printf ("clone failed"); + goto out; } + + /* If we're duplicating an fhandler from a different process and we + use an archetype, the old archetype is useless. */ + if (src_pid && oldfh->archetype + && !(newfh->archetype = find_archetype (oldfh->dev ()))) + need_new_arch = true; + + if (!oldfh->archetype) + newfh->set_handle (NULL); + + newfh->pc.reset_conv_handle (); + if (oldfh->dup (newfh, flags, src_pid)) + { + delete newfh; + newfh = NULL; + debug_printf ("oldfh->dup failed"); + goto out; + } + if (need_new_arch) + { + newfh->set_name (newfh->dev ().name ()); + newfh->archetype = newfh->clone (); + debug_printf ("created an archetype (%p) for %s(%d/%d)", + newfh->archetype, newfh->get_name (), + newfh->dev ().get_major (), newfh->dev ().get_minor ()); + newfh->archetype->archetype = NULL; + newfh->archetype->usecount = 0; + *add_archetype () = newfh->archetype; + } + + /* Don't increment refcnt here since we don't know if this is a + allocated fd. So we leave this chore to the caller. */ + + newfh->usecount = 0; + newfh->archetype_usecount (1); + + /* The O_CLOEXEC flag enforces close-on-exec behaviour. */ + newfh->set_close_on_exec (!!(flags & O_CLOEXEC)); + debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), + oldfh->get_handle (), newfh->get_handle ()); + +out: return newfh; } diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc index 4ba56dda0..98ddc02be 100644 --- a/winsup/cygwin/fhandler_socket_unix.cc +++ b/winsup/cygwin/fhandler_socket_unix.cc @@ -2008,6 +2008,7 @@ fhandler_socket_unix::serialize (int fd) switch (dev.get_major ()) { case DEV_PTYS_MAJOR: + break; case DEV_PTYM_MAJOR: case DEV_FLOPPY_MAJOR: case DEV_CDROM_MAJOR: @@ -2091,30 +2092,48 @@ fhandler_socket_unix::deserialize (void *bufp) { fh_ser *fhs = (fh_ser *) bufp; fhandler_base *oldfh, *newfh; - DWORD winpid = fhs->winpid; cygheap_fdnew cfd; if (cfd < 0) return -1; oldfh = (fhandler_base *) &fhs->fhu; - newfh = cygheap->fdtab.dup_worker (oldfh, 0, winpid); + newfh = cygheap->fdtab.dup_worker (oldfh, 0, fhs->winpid); + /* Tell sender it can delete its temporary copy of the fhandler. */ if (!send_scm_fd_ack (fhs->uniq_id)) debug_printf ("can't send ack"); if (!newfh) return -1; - switch ((dev_t) newfh->dev ()) + device dev = newfh->dev (); + switch (dev.get_major ()) { - case FH_FS: - newfh->set_name_from_handle (); - break; - case FH_UNIX: - if (((fhandler_socket_unix *) newfh)->get_pipe_end () == pipe_server) - ((fhandler_socket_unix *) newfh)->gen_pipe_name (); + case DEV_PTYS_MAJOR: break; + case DEV_PTYM_MAJOR: + case DEV_FLOPPY_MAJOR: + case DEV_CDROM_MAJOR: + case DEV_SD_MAJOR: + case DEV_SD1_MAJOR ... DEV_SD7_MAJOR: + case DEV_SD_HIGHPART_START ... DEV_SD_HIGHPART_END: + case DEV_TAPE_MAJOR: + case DEV_SERIAL_MAJOR: + case DEV_CONS_MAJOR: + set_errno (EOPNOTSUPP); + return -1; default: - break; + switch ((dev_t) dev) + { + case FH_FS: + newfh->set_name_from_handle (); + break; + case FH_UNIX: + if (((fhandler_socket_unix *) newfh)->get_pipe_end () == pipe_server) + ((fhandler_socket_unix *) newfh)->gen_pipe_name (); + break; + default: + break; + } } cfd = newfh; return cfd; diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 76f146977..bafd9ee5d 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -1081,8 +1081,11 @@ out: } int -fhandler_pty_slave::dup (fhandler_base *child, int flags, DWORD) +fhandler_pty_slave::dup (fhandler_base *child, int flags, DWORD src_pid) { + if (src_pid && !child->archetype) + goto dup_handles; + /* This code was added in Oct 2001 for some undisclosed reason. However, setting the controlling tty on a dup causes rxvt to hang when the parent does a dup since the controlling pgid changes. @@ -1095,6 +1098,112 @@ fhandler_pty_slave::dup (fhandler_base *child, int flags, DWORD) myself->set_ctty (this, flags); report_tty_counts (child, "duped slave", ""); return 0; + +dup_handles: + /* We're being called from dtable::dup_worker with src_pid != 0, and + we don't have an archetype yet. We need to duplicate handles + from the source process, and the caller will create a new + archetype. The following code is adapted from + fhandler_pty_slave::open. */ + + fhandler_pty_slave *fhp = (fhandler_pty_slave *) child; + HANDLE src_proc; + HANDLE from_master_local, from_master_cyg_local; + HANDLE to_master_local, to_master_cyg_local; + + HANDLE *handles[] = + { + &src_proc, + &from_master_local, &from_master_cyg_local, + &to_master_local, &to_master_cyg_local, + &fhp->output_mutex, &fhp->input_mutex, &fhp->inuse, + &fhp->input_available_event, + NULL + }; + + for (HANDLE **h = handles; *h; h++) + **h = NULL; + + src_proc = OpenProcess (PROCESS_DUP_HANDLE, FALSE, src_pid); + if (!src_proc) + { + termios_printf ("can't open source process, %E"); + goto err; + } + + if (!DuplicateHandle (src_proc, output_mutex, GetCurrentProcess (), + &fhp->output_mutex, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate output_mutex from %u/%p, %E", + src_pid, output_mutex); + goto err; + } + if (!DuplicateHandle (src_proc, input_mutex, GetCurrentProcess (), + &fhp->input_mutex, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input_mutex from %u/%p, %E", + src_pid, input_mutex); + goto err; + } + if (!DuplicateHandle (src_proc, input_available_event, GetCurrentProcess (), + &fhp->input_available_event, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input_available_event from %u/%p, %E", + src_pid, input_available_event); + goto err; + } + if (!DuplicateHandle (src_proc, inuse, GetCurrentProcess (), + &fhp->inuse, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate inuse from %u/%p, %E", + src_pid, inuse); + goto err; + } + if (!DuplicateHandle (src_proc, get_ttyp ()->from_master (), + GetCurrentProcess (), &from_master_local, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input from %u/%p, %E", + src_pid, get_ttyp ()->from_master ()); + goto err; + } + if (!DuplicateHandle (src_proc, get_ttyp ()->from_master_cyg (), + GetCurrentProcess (), &from_master_cyg_local, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input from %u/%p, %E", + src_pid, get_ttyp ()->from_master_cyg ()); + goto err; + } + if (!DuplicateHandle (src_proc, get_ttyp ()->to_master (), + GetCurrentProcess (), &to_master_local, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate to_master_local from %u/%p, %E", + src_pid, get_ttyp ()->to_master ()); + goto err; + } + if (!DuplicateHandle (src_proc, get_ttyp ()->to_master_cyg (), + GetCurrentProcess (), &to_master_cyg_local, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate to_master_cyg_local from %u/%p, %E", + src_pid, get_ttyp ()->to_master_cyg ()); + goto err; + } + CloseHandle (src_proc); + fhp->set_handle (from_master_local); + fhp->set_handle_cyg (from_master_cyg_local); + fhp->set_output_handle (to_master_local); + fhp->set_output_handle_cyg (to_master_cyg_local); + return 0; +err: + __seterrno (); + for (HANDLE **h = handles; *h; h++) + if (**h) + CloseHandle (**h); + return -1; } int