This is the mail archive of the cygwin-patches mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Disable AF_UNIX handshake with setsockopt(..., SO_PEERCRED, ...)


This is a workaround for this problem which blocks ITP postfix:
https://cygwin.com/ml/cygwin/2014-08/msg00420.html

With the patch, this disables the secret+cred handshakes of the AF_UNIX emulation:

int sd = socket(AF_UNIX, SOCK_STREAM, 0);

setsockopt(sd, SOL_SOCKET, SO_PEERCRED, NULL, 0);

Postfix works if socket() calls are replaced by the above.

Calls of getsockopt(..., SO_PEERCRED, ...) and getpeereid() would fail with ENOTSUP then. These are not used by postfix.

Christian

2014-09-25  Christian Franke  <franke@computer.org>

	Add setsockopt(sd, SOL_SOCKET, SO_PEERCRED, NULL, 0) to disable
	initial handshake on AF_LOCAL sockets.

	* fhandler.h (fhandler_socket::no_getpeereid): New variable.
	(fhandler_socket::af_local_set_no_getpeereid): New prototype.
	* fhandler_socket.cc (fhandler_socket::fhandler_socket):
	Initialize no_getpeereid.
	(fhandler_socket::af_local_connect): Skip handshake if
	no_getpeereid is set.  Add debug output.
	(fhandler_socket::af_local_accept): Likewise.
	(fhandler_socket::af_local_set_no_getpeereid): New function.
	(fhandler_socket::af_local_copy): Copy no_getpeereid.
	(fhandler_socket::getpeereid): Fail if no_getpeereid is set.
	* net.cc (cygwin_setsockop): Add SO_PEERCRED.
	* select.cc (set_bits): Set socket connected state also if read
	bit is requested.

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index cf4de07..6c2c3d4 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -492,6 +492,7 @@ class fhandler_socket: public fhandler_base
   pid_t sec_peer_pid;
   uid_t sec_peer_uid;
   gid_t sec_peer_gid;
+  bool no_getpeereid;
   void af_local_set_secret (char *);
   void af_local_setblocking (bool &, bool &);
   void af_local_unsetblocking (bool, bool);
@@ -504,6 +505,7 @@ class fhandler_socket: public fhandler_base
   int af_local_accept ();
  public:
   int af_local_connect ();
+  int af_local_set_no_getpeereid ();
   void af_local_set_sockpair_cred ();
 
  private:
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 0354ee2..256ac67 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -231,6 +231,7 @@ fhandler_socket::fhandler_socket () :
   wsock_events (NULL),
   wsock_mtx (NULL),
   wsock_evt (NULL),
+  no_getpeereid(false),
   prot_info_ptr (NULL),
   sun_path (NULL),
   peer_sun_path (NULL),
@@ -402,7 +403,10 @@ fhandler_socket::af_local_connect ()
   if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM)
     return 0;
 
-  debug_printf ("af_local_connect called");
+  debug_printf ("af_local_connect called, no_getpeereid=%d", no_getpeereid);
+  if (no_getpeereid)
+    return 0;
+
   connect_state (connect_credxchg);
   af_local_setblocking (orig_async_io, orig_is_nonblocking);
   if (!af_local_send_secret () || !af_local_recv_secret ()
@@ -422,7 +426,10 @@ fhandler_socket::af_local_accept ()
 {
   bool orig_async_io, orig_is_nonblocking;
 
-  debug_printf ("af_local_accept called");
+  debug_printf ("af_local_accept called, no_getpeereid=%d", no_getpeereid);
+  if (no_getpeereid)
+    return 0;
+
   connect_state (connect_credxchg);
   af_local_setblocking (orig_async_io, orig_is_nonblocking);
   if (!af_local_recv_secret () || !af_local_send_secret ()
@@ -438,6 +445,25 @@ fhandler_socket::af_local_accept ()
   return 0;
 }
 
+int
+fhandler_socket::af_local_set_no_getpeereid ()
+{
+  if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  if (connect_state () != unconnected)
+    {
+      set_errno (EALREADY);
+      return -1;
+    }
+
+  debug_printf ("no_getpeereid set");
+  no_getpeereid = true;
+  return 0;
+}
+
 void
 fhandler_socket::af_local_set_cred ()
 {
@@ -462,6 +488,7 @@ fhandler_socket::af_local_copy (fhandler_socket *sock)
   sock->sec_peer_pid = sec_peer_pid;
   sock->sec_peer_uid = sec_peer_uid;
   sock->sec_peer_gid = sec_peer_gid;
+  sock->no_getpeereid = no_getpeereid;
 }
 
 void
@@ -2287,6 +2314,11 @@ fhandler_socket::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid)
       set_errno (EINVAL);
       return -1;
     }
+  if (no_getpeereid)
+    {
+      set_errno (ENOTSUP);
+      return -1;
+    }
   if (connect_state () != connected)
     {
       set_errno (ENOTCONN);
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index b6c0f72..c5ca15e 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -810,6 +810,16 @@ cygwin_setsockopt (int fd, int level, int optname, const void *optval,
       fhandler_socket *fh = get (fd);
       if (!fh)
 	__leave;
+
+      if (optname == SO_PEERCRED && level == SOL_SOCKET)
+	{
+	  if (optval || optlen)
+	    set_errno (EINVAL);
+	  else
+	    res = fh->af_local_set_no_getpeereid ();
+	  __leave;
+	}
+
       /* Old applications still use the old WinSock1 IPPROTO_IP values. */
       if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES)
 	optname = convert_ws1_ip_optname (optname);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 6a39685..75eb726 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -473,6 +473,9 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
   if (me->read_selected && me->read_ready)
     {
       UNIX_FD_SET (me->fd, readfds);
+      /* Special AF_LOCAL handling. */
+      if ((sock = me->fh->is_socket ()) && sock->connect_state () == connect_pending)
+	sock->connect_state (connected);
       ready++;
     }
   if (me->write_selected && me->write_ready)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]