Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2009-11-17 13:43:01 +0300
committerCorinna Vinschen <corinna@vinschen.de>2009-11-17 13:43:01 +0300
commitb14f53a8ec619146e20cae8831dec4a8d9aaf883 (patch)
tree029928c686817a409f1665db3eb5a381f411f819 /winsup
parent88242190ec6f016a5a7956bd20a844dd38e436e6 (diff)
Reintegrate socket duplication via WSADuplicateSocket/WSASocket.
* autoload.cc (WSADuplicateSocketW): Define. (WSASocketW): Define. * dtable.cc (dtable::release): Call dec_need_fixup_before if necessary. (dtable::fixup_before_fork): New function. (dtable::fixup_before_exec): New function. * dtable.h (class dtable): Add member cnt_need_fixup_before. Add declarations for above new functions. (dtable::dec_need_fixup_before): New inline method. (dtable::inc_need_fixup_before): New inline method. (dtable::need_fixup_before): New inline method. * fhandler.h (fhandler_base::fixup_before_fork_exec): New virtual method. (fhandler_base::need_fixup_before): New virtual method. (class fhandler_socket): Add member prot_info_ptr. (fhandler_socket::init_fixup_before): Declare. (fhandler_socket::need_fixup_before): New inline method. (fhandler_socket::fixup_before_fork_exec): Declare. (fhandler_socket::fixup_after_exec): Declare. * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize prot_info_ptr to NULL. (fhandler_socket::~fhandler_socket): Free prot_info_ptr conditionally. (fhandler_socket::init_fixup_before): New method. (fhandler_socket::fixup_before_fork_exec): Ditto. (fhandler_socket::fixup_after_fork): Use WSASocketW to duplicate socket if necessary. (fhandler_socket::fixup_after_exec): New method. (fhandler_socket::dup): Use fixup_before_fork_exec/fixup_after_fork to duplicate socket if necessary. * fork.cc (frok::parent): Start child suspended if some fhandler needs fixup before fork. If so, call dtable::fixup_before_fork after CreateProcess and resume child. * net.cc (fdsock): Try to find out if socket needs fixup before and initialize socket accordingly. Add HUGE comment to explain what happens and why. * spawn.cc (spawn_guts): Start child suspended if some fhandler needs fixup before exec. If so, call dtable::fixup_before_exec after CreateProcess.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog41
-rw-r--r--winsup/cygwin/autoload.cc2
-rw-r--r--winsup/cygwin/dtable.cc30
-rw-r--r--winsup/cygwin/dtable.h12
-rw-r--r--winsup/cygwin/fhandler.h10
-rw-r--r--winsup/cygwin/fhandler_socket.cc85
-rw-r--r--winsup/cygwin/fork.cc13
-rw-r--r--winsup/cygwin/net.cc28
-rw-r--r--winsup/cygwin/spawn.cc8
9 files changed, 221 insertions, 8 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d03e04701..c82b603e9 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,44 @@
+2009-11-17 Corinna Vinschen <corinna@vinschen.de>
+
+ Reintegrate socket duplication via WSADuplicateSocket/WSASocket.
+ * autoload.cc (WSADuplicateSocketW): Define.
+ (WSASocketW): Define.
+ * dtable.cc (dtable::release): Call dec_need_fixup_before if necessary.
+ (dtable::fixup_before_fork): New function.
+ (dtable::fixup_before_exec): New function.
+ * dtable.h (class dtable): Add member cnt_need_fixup_before. Add
+ declarations for above new functions.
+ (dtable::dec_need_fixup_before): New inline method.
+ (dtable::inc_need_fixup_before): New inline method.
+ (dtable::need_fixup_before): New inline method.
+ * fhandler.h (fhandler_base::fixup_before_fork_exec): New virtual
+ method.
+ (fhandler_base::need_fixup_before): New virtual method.
+ (class fhandler_socket): Add member prot_info_ptr.
+ (fhandler_socket::init_fixup_before): Declare.
+ (fhandler_socket::need_fixup_before): New inline method.
+ (fhandler_socket::fixup_before_fork_exec): Declare.
+ (fhandler_socket::fixup_after_exec): Declare.
+ * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize
+ prot_info_ptr to NULL.
+ (fhandler_socket::~fhandler_socket): Free prot_info_ptr conditionally.
+ (fhandler_socket::init_fixup_before): New method.
+ (fhandler_socket::fixup_before_fork_exec): Ditto.
+ (fhandler_socket::fixup_after_fork): Use WSASocketW to duplicate
+ socket if necessary.
+ (fhandler_socket::fixup_after_exec): New method.
+ (fhandler_socket::dup): Use fixup_before_fork_exec/fixup_after_fork
+ to duplicate socket if necessary.
+ * fork.cc (frok::parent): Start child suspended if some fhandler
+ needs fixup before fork. If so, call dtable::fixup_before_fork after
+ CreateProcess and resume child.
+ * net.cc (fdsock): Try to find out if socket needs fixup before and
+ initialize socket accordingly. Add HUGE comment to explain what happens
+ and why.
+ * spawn.cc (spawn_guts): Start child suspended if some fhandler needs
+ fixup before exec. If so, call dtable::fixup_before_exec after
+ CreateProcess.
+
2009-11-16 Eric Blake <ebb9@byu.net>
* environ.cc (setenv): Detect invalid argument.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 942891303..bac1c1979 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -387,6 +387,7 @@ LoadDLLfunc (setsockopt, 20, ws2_32)
LoadDLLfunc (shutdown, 8, ws2_32)
LoadDLLfunc (socket, 12, ws2_32)
LoadDLLfunc (WSAAsyncSelect, 16, ws2_32)
+LoadDLLfunc (WSADuplicateSocketW, 12, ws2_32)
LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32)
LoadDLLfunc (WSAEventSelect, 12, ws2_32)
LoadDLLfunc (WSAGetLastError, 0, ws2_32)
@@ -396,6 +397,7 @@ LoadDLLfunc (WSARecvFrom, 36, ws2_32)
LoadDLLfunc (WSASendMsg, 24, ws2_32)
LoadDLLfunc (WSASendTo, 36, ws2_32)
LoadDLLfunc (WSASetLastError, 4, ws2_32)
+LoadDLLfunc (WSASocketW, 24, ws2_32)
// LoadDLLfunc (WSAStartup, 8, ws2_32)
LoadDLLfunc (WSAWaitForMultipleEvents, 20, ws2_32)
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 61be7fc97..77055ef29 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -248,6 +248,8 @@ dtable::release (int fd)
{
if (!not_open (fd))
{
+ if (fds[fd]->need_fixup_before ())
+ dec_need_fixup_before ();
fhandler_base *arch = fds[fd]->archetype;
delete fds[fd];
if (arch && !arch->usecount)
@@ -1020,3 +1022,31 @@ handle_to_fn (HANDLE h, char *posix_fn)
strcpy (posix_fn, unknown_file);
return false;
}
+
+void
+dtable::fixup_before_fork (DWORD target_proc_id)
+{
+ lock ();
+ fhandler_base *fh;
+ for (size_t i = 0; i < size; i++)
+ if ((fh = fds[i]) != NULL)
+ {
+ debug_printf ("fd %d (%s)", i, fh->get_name ());
+ fh->fixup_before_fork_exec (target_proc_id);
+ }
+ unlock ();
+}
+void
+dtable::fixup_before_exec (DWORD target_proc_id)
+{
+ lock ();
+ fhandler_base *fh;
+ for (size_t i = 0; i < size; i++)
+ if ((fh = fds[i]) != NULL && !fh->close_on_exec ())
+ {
+ debug_printf ("fd %d (%s)", i, fh->get_name ());
+ fh->fixup_before_fork_exec (target_proc_id);
+ }
+ unlock ();
+}
+
diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h
index c1344549e..7b5af6fb8 100644
--- a/winsup/cygwin/dtable.h
+++ b/winsup/cygwin/dtable.h
@@ -31,14 +31,22 @@ class dtable
unsigned farchetype;
static const int initial_archetype_size = 8;
int first_fd_for_open;
+ int cnt_need_fixup_before;
void lock () {lock_process::locker.acquire ();}
void unlock () {lock_process::locker.release ();}
public:
size_t size;
- dtable () : archetypes (NULL), narchetypes (0), farchetype (0), first_fd_for_open(3) {}
+ dtable () : archetypes (NULL), narchetypes (0), farchetype (0), first_fd_for_open(3), cnt_need_fixup_before(0) {}
void init () {first_fd_for_open = 3;}
+ void dec_need_fixup_before ()
+ { if (cnt_need_fixup_before > 0) --cnt_need_fixup_before; }
+ void inc_need_fixup_before ()
+ { cnt_need_fixup_before++; }
+ bool need_fixup_before ()
+ { return cnt_need_fixup_before > 0; }
+
void move_fd (int, int);
int vfork_child_dup ();
void vfork_parent_restore ();
@@ -73,6 +81,8 @@ public:
fhandler_base *find_archetype (device& dev);
fhandler_base **add_archetype ();
void delete_archetype (fhandler_base *);
+ void fixup_before_exec (DWORD win_proc_id);
+ void fixup_before_fork (DWORD win_proc_id);
friend void dtable_init ();
friend void __stdcall close_all_files (bool);
friend class fhandler_disk_file;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index bc08dd182..275509227 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -226,6 +226,7 @@ class fhandler_base
return close_on_exec () ? &sec_none_nih : &sec_none;
}
+ virtual int fixup_before_fork_exec (DWORD) { return 0; }
virtual void fixup_after_fork (HANDLE);
virtual void fixup_after_exec ();
void create_read_state (LONG n)
@@ -270,6 +271,7 @@ class fhandler_base
/* fixup fd possibly non-inherited handles after fork */
bool fork_fixup (HANDLE, HANDLE &, const char *);
+ virtual bool need_fixup_before () const {return false;}
virtual int open (int, mode_t = 0);
int open_fs (int, mode_t = 0);
@@ -464,6 +466,12 @@ class fhandler_socket: public fhandler_base
void wmem (int nwmem) { _wmem = nwmem; }
private:
+ struct _WSAPROTOCOL_INFOW *prot_info_ptr;
+ public:
+ void init_fixup_before ();
+ bool need_fixup_before () const {return prot_info_ptr != NULL;}
+
+ private:
char *sun_path;
char *peer_sun_path;
struct status_flags
@@ -524,7 +532,9 @@ class fhandler_socket: public fhandler_base
int dup (fhandler_base *child);
void set_close_on_exec (bool val);
+ int fixup_before_fork_exec (DWORD);
void fixup_after_fork (HANDLE);
+ void fixup_after_exec ();
char *get_proc_fd_name (char *buf);
select_record *select_read (select_stuff *);
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index a1cfce30f..6a6620686 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -151,6 +151,7 @@ fhandler_socket::fhandler_socket () :
wsock_events (NULL),
wsock_mtx (NULL),
wsock_evt (NULL),
+ prot_info_ptr (NULL),
sun_path (NULL),
peer_sun_path (NULL),
status ()
@@ -160,6 +161,8 @@ fhandler_socket::fhandler_socket () :
fhandler_socket::~fhandler_socket ()
{
+ if (prot_info_ptr)
+ cfree (prot_info_ptr);
if (sun_path)
cfree (sun_path);
if (peer_sun_path)
@@ -631,12 +634,62 @@ fhandler_socket::release_events ()
NtClose (wsock_mtx);
}
+/* Called from net.cc:fdsock() if a freshly created socket is not
+ inheritable. In that case we use fixup_before_fork_exec. See
+ the comment in fdsock() for a description of the problem. */
+void
+fhandler_socket::init_fixup_before ()
+{
+ prot_info_ptr = (LPWSAPROTOCOL_INFOW)
+ cmalloc_abort (HEAP_BUF, sizeof (WSAPROTOCOL_INFOW));
+ cygheap->fdtab.inc_need_fixup_before ();
+}
+
+int
+fhandler_socket::fixup_before_fork_exec (DWORD win_pid)
+{
+ SOCKET ret = WSADuplicateSocketW (get_socket (), win_pid, prot_info_ptr);
+ if (ret)
+ set_winsock_errno ();
+ else
+ debug_printf ("WSADuplicateSocket succeeded");
+ return (int) ret;
+}
+
void
fhandler_socket::fixup_after_fork (HANDLE parent)
{
fork_fixup (parent, wsock_mtx, "wsock_mtx");
fork_fixup (parent, wsock_evt, "wsock_evt");
- fhandler_base::fixup_after_fork (parent);
+
+ if (!need_fixup_before ())
+ {
+ fhandler_base::fixup_after_fork (parent);
+ return;
+ }
+
+ SOCKET new_sock = WSASocketW (FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO, prot_info_ptr, 0, 0);
+ if (new_sock == INVALID_SOCKET)
+ {
+ set_winsock_errno ();
+ set_io_handle ((HANDLE) INVALID_SOCKET);
+ }
+ else
+ {
+ /* Even though the original socket was not inheritable, the duplicated
+ socket is potentially inheritable again. */
+ SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0);
+ set_io_handle ((HANDLE) new_sock);
+ debug_printf ("WSASocket succeeded");
+ }
+}
+
+void
+fhandler_socket::fixup_after_exec ()
+{
+ if (need_fixup_before () && !close_on_exec ())
+ fixup_after_fork (NULL);
}
int
@@ -679,13 +732,33 @@ fhandler_socket::dup (fhandler_base *child)
}
}
fhs->connect_state (connect_state ());
- int ret = fhandler_base::dup (child);
- if (ret)
+
+ if (!need_fixup_before ())
{
- NtClose (fhs->wsock_evt);
- NtClose (fhs->wsock_mtx);
+ int ret = fhandler_base::dup (child);
+ if (ret)
+ {
+ NtClose (fhs->wsock_evt);
+ NtClose (fhs->wsock_mtx);
+ }
+ return ret;
}
- return ret;
+
+ cygheap->user.deimpersonate ();
+ fhs->init_fixup_before ();
+ fhs->set_io_handle (get_io_handle ());
+ if (!fhs->fixup_before_fork_exec (GetCurrentProcessId ()))
+ {
+ cygheap->user.reimpersonate ();
+ fhs->fixup_after_fork (hMainProc);
+ if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET)
+ return 0;
+ }
+ cygheap->user.reimpersonate ();
+ cygheap->fdtab.dec_need_fixup_before ();
+ NtClose (fhs->wsock_evt);
+ NtClose (fhs->wsock_mtx);
+ return -1;
}
int __stdcall
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index ac2e9ca5e..ea162519f 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -302,6 +302,13 @@ frok::parent (volatile char * volatile stack_here)
else
c_flags |= DETACHED_PROCESS;
+ /* Some file types (currently only sockets) need extra effort in the
+ parent after CreateProcess and before copying the datastructures
+ to the child. So we have to start the child in suspend state,
+ unfortunately, to avoid a race condition. */
+ if (cygheap->fdtab.need_fixup_before ())
+ c_flags |= CREATE_SUSPENDED;
+
/* Remember if we need to load dynamically linked dlls.
We do this here so that this information will be available
in the parent and, when the stack is copied, in the child. */
@@ -369,6 +376,12 @@ frok::parent (volatile char * volatile stack_here)
goto cleanup;
}
+ if (cygheap->fdtab.need_fixup_before ())
+ {
+ cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
+ ResumeThread (pi.hThread);
+ }
+
CloseHandle (pi.hThread);
/* Protect the handle but name it similarly to the way it will
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 509269a83..f9cb1de15 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -495,6 +495,34 @@ fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
fd->uninterruptible_io (true);
debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc);
+ /* Usually sockets are inheritable IFS objects. Unfortunately some virus
+ scanners or other network-oriented software replace normal sockets
+ with their own kind, which is running through a filter driver.
+
+ The result is that these new sockets are not normal kernel objects
+ anymore. They are typically not marked as inheritable, nor are they
+ IFS handles, as normal OS sockets are. They are in fact not inheritable
+ to child processes, and subsequent socket calls in the child process
+ will fail with error 10038, WSAENOTSOCK. And worse, while DuplicateHandle
+ on these sockets mostly works in the process which created the socket,
+ DuplicateHandle does quite often not work anymore in a child process.
+ It does not help to mark them inheritable via SetHandleInformation.
+
+ The only way to make these sockets usable in child processes is to
+ duplicate them via WSADuplicateSocket/WSASocket calls. This requires
+ some incredible amount of extra processing so we only do this on
+ affected systems. If we recognize a non-inheritable socket, or if
+ the XP1_IFS_HANDLES flag is not set in a call to WSADuplicateSocket,
+ we switch to inheritance/dup via WSADuplicateSocket/WSASocket for
+ that socket. */
+ DWORD flags;
+ WSAPROTOCOL_INFOW wpi;
+ if (!GetHandleInformation ((HANDLE) soc, &flags)
+ || !(flags & HANDLE_FLAG_INHERIT)
+ || WSADuplicateSocketW (soc, GetCurrentProcessId (), &wpi)
+ || !(wpi.dwServiceFlags1 & XP1_IFS_HANDLES))
+ ((fhandler_socket *) fd)->init_fixup_before ();
+
/* Raise default buffer sizes (instead of WinSock default 8K).
64K appear to have the best size/performance ratio for a default
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index b9304ff70..88b9bf21f 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -529,7 +529,8 @@ spawn_guts (const char *prog_arg, const char *const *argv,
and before copying the datastructures to the child. So we have to start
the child in suspend state, unfortunately, to avoid a race condition. */
if (!newargv.win16_exe
- && (!ch.iscygwin () || mode != _P_OVERLAY))
+ && (!ch.iscygwin () || mode != _P_OVERLAY
+ || cygheap->fdtab.need_fixup_before ()))
c_flags |= CREATE_SUSPENDED;
/* When ruid != euid we create the new process under the current original
@@ -656,6 +657,11 @@ loop:
if (!(c_flags & CREATE_SUSPENDED))
strace.write_childpid (ch, pi.dwProcessId);
+ /* Fixup the parent data structures if needed and resume the child's
+ main thread. */
+ if (cygheap->fdtab.need_fixup_before ())
+ cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
+
if (mode != _P_OVERLAY)
cygpid = cygwin_pid (pi.dwProcessId);
else