Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Jun 2001 00:06:28 -0700
From:      Dima Dorfman <dima@unixfreak.org>
To:        arch@freebsd.org
Subject:   Peer credentials on a Unix domain socket
Message-ID:  <20010627070628.AB5F13E2F@bazooka.unixfreak.org>

next in thread | raw e-mail | index | archive | help
Hi folks,

Currently, there is no reliable way for a server listening on a Unix
domain socket to find out the credentials of its peer until the peer
sends something over the socket.  Finding its credentials can be
useful if the server only wants to accept connections from certain
users.  We already have SCM_CREDS, which will send the peer's
credentials along with a message, but this is *not* sufficient as it
may be unacceptable for the server to wait until the peer sends
something; think of DoS attacked.  Times don't help, either; think of
SYN flood-like attacks.

I would like to propose implementing such a facility as a socket
option, LOCAL_PEERCRED.  The payload would be am xucred structure with
the effective credentials of the connect(2) caller.  Granted these may
not be the credentials of the process using the socket (think
descriptor passing), but it doesn't matter; if a process hands a
descriptor off to something else, it should be trusting it not to
abuse it (this is a feature: think of opening a privileged port and
dropping privileges).

This has been discussed at least twice before, and nobody has a better
idea.  Again, I would like to stress the two requirements: (1) the
accept(2) caller must be able to reliably obtain the effective
credentials of the connect(2) caller, and (2) the accept(2) caller
must be able to do (1) without relying on the connect(2) caller to
send data (SCM_CREDS doesn't meet (2)).

Patch attached.

Comments?  Suggestions?

Thanks in advance,

					Dima Dorfman
					dima@unixfreak.org


Index: sys/un.h
===================================================================
RCS file: /stl/src/FreeBSD/src/sys/sys/un.h,v
retrieving revision 1.17
diff -u -r1.17 un.h
--- sys/un.h	1999/12/29 04:24:49	1.17
+++ sys/un.h	2001/06/27 06:51:18
@@ -46,12 +46,16 @@
 	char	sun_path[104];		/* path name (gag) */
 };
 
+/* Socket options. */
+#define LOCAL_PEERCRED		0x001		/* retrieve peer credentials */
+
 #ifdef _KERNEL
 struct mbuf;
 struct socket;
 
 int	uipc_usrreq __P((struct socket *so, int req, struct mbuf *m,
 		struct mbuf *nam, struct mbuf *control));
+int	uipc_ctloutput __P((struct socket *so, struct sockopt *sopt));
 int	unp_connect2 __P((struct socket *so, struct socket *so2));
 void	unp_dispose __P((struct mbuf *m));
 int	unp_externalize __P((struct mbuf *rights));
Index: sys/unpcb.h
===================================================================
RCS file: /stl/src/FreeBSD/src/sys/sys/unpcb.h,v
retrieving revision 1.11
diff -u -r1.11 unpcb.h
--- sys/unpcb.h	2000/05/26 02:06:59	1.11
+++ sys/unpcb.h	2001/06/27 06:51:18
@@ -80,7 +80,14 @@
 	int	unp_cc;			/* copy of rcv.sb_cc */
 	int	unp_mbcnt;		/* copy of rcv.sb_mbcnt */
 	unp_gen_t unp_gencnt;		/* generation count of this instance */
+	int	unp_flags;		/* flags */
+	struct	xucred unp_peercred;	/* peer credentials, if applicable */
 };
+
+/*
+ * Flags in unp_flags.
+ */
+#define UNP_HAVEPC	0x001		/* unp_peercred filled in? */
 
 #define	sotounpcb(so)	((struct unpcb *)((so)->so_pcb))
 
Index: kern/uipc_proto.c
===================================================================
RCS file: /stl/src/FreeBSD/src/sys/kern/uipc_proto.c,v
retrieving revision 1.21
diff -u -r1.21 uipc_proto.c
--- kern/uipc_proto.c	1999/10/11 15:19:11	1.21
+++ kern/uipc_proto.c	2001/06/27 06:51:18
@@ -51,7 +51,7 @@
 
 static struct protosw localsw[] = {
 { SOCK_STREAM,	&localdomain,	0,	PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS,
-  0,		0,		0,		0,
+  0,		0,		0,		&uipc_ctloutput,
   0,
   0,		0,		0,		0,
   &uipc_usrreqs
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /stl/src/FreeBSD/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.66
diff -u -r1.66 uipc_usrreq.c
--- kern/uipc_usrreq.c	2001/05/25 16:59:07	1.66
+++ kern/uipc_usrreq.c	2001/06/27 06:51:18
@@ -434,6 +434,23 @@
 	uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr,
 	sosend, soreceive, sopoll
 };
+
+int
+uipc_ctloutput(so, sopt)
+	struct socket *so;
+	struct sockopt *sopt;
+{
+	struct unpcb *unp = sotounpcb(so);
+	int error;
+
+	if (sopt->sopt_dir == SOPT_GET && sopt->sopt_name == LOCAL_PEERCRED &&
+	    unp->unp_flags & UNP_HAVEPC)
+		error = sooptcopyout(sopt, &unp->unp_peercred,
+		    sizeof(unp->unp_peercred));
+	else
+		error = EOPNOTSUPP;
+	return (error);
+}
 	
 /*
  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
@@ -654,6 +671,12 @@
 			unp3->unp_addr = (struct sockaddr_un *)
 				dup_sockaddr((struct sockaddr *)
 					     unp2->unp_addr, 1);
+		bzero(&unp3->unp_peercred, sizeof(unp3->unp_peercred));
+		unp3->unp_peercred.cr_uid = p->p_ucred->cr_uid;
+		unp3->unp_peercred.cr_ngroups = p->p_ucred->cr_ngroups;
+		bcopy(p->p_ucred->cr_groups, unp3->unp_peercred.cr_groups,
+		    sizeof(unp3->unp_peercred.cr_groups));
+		unp3->unp_flags |= UNP_HAVEPC;
 		so2 = so3;
 	}
 	error = unp_connect2(so, so2);

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010627070628.AB5F13E2F>