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>
index | next in thread | previous in thread | raw e-mail
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
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.NEB.3.96L.1010627150012.16165D-100000>
