Date: Wed, 27 Jun 2001 15:19:52 -0400 (EDT) From: Robert Watson <rwatson@freebsd.org> To: Dima Dorfman <dima@unixfreak.org> Cc: arch@freebsd.org Subject: Re: Peer credentials on a Unix domain socket Message-ID: <Pine.NEB.3.96L.1010627150012.16165D-100000@fledge.watson.org> In-Reply-To: <20010627070628.AB5F13E2F@bazooka.unixfreak.org>
next in thread | previous in thread | raw e-mail | index | archive | help
How does this solution compare with similar solutions on other platforms? Robert N M Watson FreeBSD Core Team, TrustedBSD Project robert@fledge.watson.org NAI Labs, Safeport Network Services On Wed, 27 Jun 2001, Dima Dorfman wrote: > 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 > 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?Pine.NEB.3.96L.1010627150012.16165D-100000>