From 23672785ee63ee712b8ef05d0caa92e798683e53 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 8 Jul 2008 20:12:46 +0000 Subject: * fhandler_socket.cc (fhandler_socket::bind): Don't run explicit local socket test in SO_REUSEADDR case on systems supporting enhanced socket security. Explain why. Only call address_in_use for AF_INET sockets. * net.cc (cygwin_setsockopt): Don't call setsockopt to set SO_REUSEADDR on systems supporting enhanced socket security. Add comment. * wincap.h (wincaps::has_enhanced_socket_security): New element. * wincap.cc: Implement above element throughout. --- winsup/cygwin/ChangeLog | 11 +++++++++++ winsup/cygwin/fhandler_socket.cc | 22 +++++++++++++++++----- winsup/cygwin/net.cc | 12 ++++++++++-- winsup/cygwin/wincap.cc | 10 ++++++++++ winsup/cygwin/wincap.h | 2 ++ 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 368ffb49e..9df84c2f5 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,14 @@ +2008-07-08 Corinna Vinschen + + * fhandler_socket.cc (fhandler_socket::bind): Don't run explicit + local socket test in SO_REUSEADDR case on systems supporting + enhanced socket security. Explain why. Only call address_in_use + for AF_INET sockets. + * net.cc (cygwin_setsockopt): Don't call setsockopt to set SO_REUSEADDR + on systems supporting enhanced socket security. Add comment. + * wincap.h (wincaps::has_enhanced_socket_security): New element. + * wincap.cc: Implement above element throughout. + 2008-07-08 Corinna Vinschen * net.cc (ipv6_inited): Make NO_COPY. diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index c0df1fb66..2a39d387e 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -911,17 +911,29 @@ fhandler_socket::bind (const struct sockaddr *name, int namelen) (const char *) &on, sizeof on); debug_printf ("%d = setsockopt (SO_EXCLUSIVEADDRUSE), %E", ret); } - else + else if (!wincap.has_enhanced_socket_security ()) { debug_printf ("SO_REUSEADDR set"); /* There's a bug in SO_REUSEADDR handling in WinSock. Per standards, we must not be able to reuse a complete duplicate of a local TCP address (same IP, same port), even if SO_REUSEADDR has been set. That's unfortunately - possible in WinSock. So we're testing here if the local - address is already in use and don't bind, if so. This - only works for OSes with IP Helper support. */ - if (get_socket_type () == SOCK_STREAM + possible in WinSock. + + So we're testing here if the local address is already in + use and don't bind, if so. This only works for OSes with + IP Helper support and is, of course, still prone to races. + + However, we don't have to do this on systems supporting + "enhanced socket security" (2K3 and later). On these + systems the default binding behaviour is exactly as you'd + expect for SO_REUSEADDR, while setting SO_REUSEADDR re-enables + the wrong behaviour. So all we have to do on these newer + systems is never to set SO_REUSEADDR but only to note that + it has been set for the above SO_EXCLUSIVEADDRUSE setting. + See setsockopt() in net.cc. */ + if (name->sa_family == AF_INET + && get_socket_type () == SOCK_STREAM && wincap.has_ip_helper_lib () && address_in_use ((struct sockaddr_in *) name)) { diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index ded37aa05..8be32197c 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -649,8 +649,16 @@ cygwin_setsockopt (int fd, int level, int optname, const void *optval, if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) optname = convert_ws1_ip_optname (optname); - res = setsockopt (fh->get_socket (), level, optname, - (const char *) optval, optlen); + /* On systems supporting "enhanced socket security (2K3 and later), + the default behaviour of socket binding is equivalent to the POSIX + behaviour with SO_REUSEADDR. Setting SO_REUSEADDR would only result + in wrong behaviour. See also fhandler_socket::bind(). */ + if (level == SOL_SOCKET && optname == SO_REUSEADDR + && wincap.has_enhanced_socket_security ()) + res = 0; + else + res = setsockopt (fh->get_socket (), level, optname, + (const char *) optval, optlen); if (optlen == 4) syscall_printf ("setsockopt optval=%x", *(long *) optval); diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index cf44dcc79..f2a3ef1fe 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -33,6 +33,7 @@ static NO_COPY wincaps wincap_unknown = { has_disabled_user_tos_setting:false, has_fileid_dirinfo:false, has_exclusiveaddruse:false, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:true, @@ -64,6 +65,7 @@ static NO_COPY wincaps wincap_nt4 = { has_disabled_user_tos_setting:false, has_fileid_dirinfo:false, has_exclusiveaddruse:false, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:true, @@ -95,6 +97,7 @@ static NO_COPY wincaps wincap_nt4sp4 = { has_disabled_user_tos_setting:false, has_fileid_dirinfo:false, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:true, @@ -126,6 +129,7 @@ static NO_COPY wincaps wincap_2000 = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:true, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:true, @@ -157,6 +161,7 @@ static NO_COPY wincaps wincap_2000sp4 = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:true, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:true, @@ -188,6 +193,7 @@ static NO_COPY wincaps wincap_xp = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:false, @@ -219,6 +225,7 @@ static NO_COPY wincaps wincap_xpsp1 = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:false, @@ -250,6 +257,7 @@ static NO_COPY wincaps wincap_xpsp2 = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:false, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:false, @@ -281,6 +289,7 @@ static NO_COPY wincaps wincap_2003 = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:false, needs_logon_sid_in_sid_list:false, @@ -312,6 +321,7 @@ static NO_COPY wincaps wincap_vista = { has_disabled_user_tos_setting:true, has_fileid_dirinfo:true, has_exclusiveaddruse:true, + has_enhanced_socket_security:true, has_buggy_restart_scan:false, has_mandatory_integrity_control:true, needs_logon_sid_in_sid_list:false, diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 2035ecc5a..7028402c1 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -31,6 +31,7 @@ struct wincaps unsigned has_disabled_user_tos_setting : 1; unsigned has_fileid_dirinfo : 1; unsigned has_exclusiveaddruse : 1; + unsigned has_enhanced_socket_security : 1; unsigned has_buggy_restart_scan : 1; unsigned has_mandatory_integrity_control : 1; unsigned needs_logon_sid_in_sid_list : 1; @@ -78,6 +79,7 @@ public: bool IMPLEMENT (has_disabled_user_tos_setting) bool IMPLEMENT (has_fileid_dirinfo) bool IMPLEMENT (has_exclusiveaddruse) + bool IMPLEMENT (has_enhanced_socket_security) bool IMPLEMENT (has_buggy_restart_scan) bool IMPLEMENT (has_mandatory_integrity_control) bool IMPLEMENT (needs_logon_sid_in_sid_list) -- cgit v1.2.3