tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Adding sc_pid to SCM_CREDS



Hi List

For AF_UNIX SOCK_DGRAM sockets, the only way of obtaining credentials is
via LOCAL_CREDS which returns SCM_CREDS as a cmsg.
However, struct sockcred lacks the process id of the sender which is of
use to many applications.

For SOCK_STREAM and SOCK_SEQPACKET, we do have LOCAL_PEEREID, but that
comes at the extra expense of a syscall after accepting.

There was a previous discussion here:
https://mail-index.netbsd.org/tech-kern/2008/07/05/msg001969.html

And an open gnats ticket with a LOCAL_PROC suggestion under kern/39108
http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=39108

Attached is a patch which adds sc_pid to struct sockcred and correctly
fills it out. The old sockcred structure is available as osockcred in
compat/sys/socket.h and guarded by COMPAT_70.

Everything seems to work ok with old binaries, but would appreciate some
extra eyes on the compat code or any suggestion how it could be done better.

Roy
Index: sys/compat/sys/socket.h
===================================================================
RCS file: /cvsroot/src/sys/compat/sys/socket.h,v
retrieving revision 1.12
diff -u -r1.12 socket.h
--- sys/compat/sys/socket.h	13 Feb 2009 22:41:04 -0000	1.12
+++ sys/compat/sys/socket.h	29 Mar 2016 16:10:34 -0000
@@ -71,12 +71,28 @@
 	int		msg_accrightslen;
 };
 
+/*
+ * 7.0 compat sockcred
+ */
+struct osockcred {
+	uid_t	sc_uid;			/* real user id */
+	uid_t	sc_euid;		/* effective user id */
+	gid_t	sc_gid;			/* real group id */
+	gid_t	sc_egid;		/* effective group id */
+	int	sc_ngroups;		/* number of supplemental groups */
+	gid_t	sc_groups[1];		/* variable length */
+};
+#define	SOCKOCREDSIZE(ngrps) \
+	(/*CONSTCOND*/sizeof(struct osockcred) + (sizeof(gid_t) * \
+	    ((ngrps) ? ((ngrps) - 1) : 0)))
+
 #ifdef _KERNEL
 
 #define	SO_OSNDTIMEO	0x1005
 #define	SO_ORCVTIMEO	0x1006
 #define	SO_OTIMESTAMP	0x0400
 #define	SCM_OTIMESTAMP	0x2
+#define	SCM_OCREDS	0x4
 
 __BEGIN_DECLS
 struct socket;
Index: sys/kern/uipc_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.179
diff -u -r1.179 uipc_usrreq.c
--- sys/kern/uipc_usrreq.c	2 May 2015 17:18:03 -0000	1.179
+++ sys/kern/uipc_usrreq.c	29 Mar 2016 16:10:46 -0000
@@ -120,6 +120,10 @@
 #include <sys/kernel.h>
 #include <sys/kthread.h>
 
+#ifdef COMPAT_70
+#include "compat/sys/socket.h"
+#endif
+
 /*
  * Unix communications domain.
  *
@@ -171,6 +175,9 @@
 ino_t	unp_ino;			/* prototype for fake inode numbers */
 
 static struct mbuf * unp_addsockcred(struct lwp *, struct mbuf *);
+#ifdef COMPAT_70
+static struct mbuf * unp_addosockcred(struct lwp *, struct mbuf *);
+#endif
 static void   unp_discard_later(file_t *);
 static void   unp_discard_now(file_t *);
 static void   unp_disconnect1(struct unpcb *);
@@ -319,6 +326,10 @@
 		sun = &sun_noname;
 	if (unp->unp_conn->unp_flags & UNP_WANTCRED)
 		control = unp_addsockcred(curlwp, control);
+#ifdef COMPAT_70
+	if (unp->unp_conn->unp_flags & UNP_OWANTCRED)
+		control = unp_addosockcred(curlwp, control);
+#endif
 	if (sbappendaddr(&so2->so_rcv, (const struct sockaddr *)sun, m,
 	    control) == 0) {
 		so2->so_rcv.sb_overflowed++;
@@ -491,6 +502,16 @@
 			unp->unp_conn->unp_flags &= ~UNP_WANTCRED;
 			control = unp_addsockcred(l, control);
 		}
+#ifdef COMPAT_70
+		if (unp->unp_conn->unp_flags & UNP_OWANTCRED) {
+			/*
+			 * Credentials are passed only once on
+			 * SOCK_STREAM and SOCK_SEQPACKET.
+			 */
+			unp->unp_conn->unp_flags &= ~UNP_OWANTCRED;
+			control = unp_addsockcred(l, control);
+		}
+#endif
 		/*
 		 * Send to paired receive port, and then reduce
 		 * send buffer hiwater marks to maintain backpressure.
@@ -566,6 +587,9 @@
 		switch (sopt->sopt_name) {
 		case LOCAL_CREDS:
 		case LOCAL_CONNWAIT:
+#ifdef COMPAT_70
+		case LOCAL_OCREDS:
+#endif
 			error = sockopt_getint(sopt, &optval);
 			if (error)
 				break;
@@ -582,7 +606,12 @@
 			case LOCAL_CONNWAIT:
 				OPTSET(UNP_CONNWAIT);
 				break;
-			}
+#ifdef COMPAT_70
+			case LOCAL_OCREDS:
+				OPTSET(UNP_OWANTCRED);
+				break;
+#endif
+		}
 			break;
 #undef OPTSET
 
@@ -609,6 +638,12 @@
 			optval = OPTBIT(UNP_WANTCRED);
 			error = sockopt_setint(sopt, optval);
 			break;
+#ifdef COMPAT_70
+		case LOCAL_OCREDS:
+			optval = OPTBIT(UNP_OWANTCRED);
+			error = sockopt_setint(sopt, optval);
+			break;
+#endif
 #undef OPTBIT
 
 		default:
@@ -1572,7 +1607,34 @@
 		SCM_CREDS, SOL_SOCKET, M_WAITOK);
 	if (m == NULL)
 		return control;
-		
+
+	sc = p;
+	sc->sc_pid = l->l_proc->p_pid;
+	sc->sc_uid = kauth_cred_getuid(l->l_cred);
+	sc->sc_euid = kauth_cred_geteuid(l->l_cred);
+	sc->sc_gid = kauth_cred_getgid(l->l_cred);
+	sc->sc_egid = kauth_cred_getegid(l->l_cred);
+	sc->sc_ngroups = kauth_cred_ngroups(l->l_cred);
+
+	for (int i = 0; i < sc->sc_ngroups; i++)
+		sc->sc_groups[i] = kauth_cred_group(l->l_cred, i);
+
+	return m_add(control, m);
+}
+
+#ifdef COMPAT_70
+struct mbuf *
+unp_addosockcred(struct lwp *l, struct mbuf *control)
+{
+	struct osockcred *sc;
+	struct mbuf *m;
+	void *p;
+
+	m = sbcreatecontrol1(&p, SOCKOCREDSIZE(kauth_cred_ngroups(l->l_cred)),
+		SCM_OCREDS, SOL_SOCKET, M_WAITOK);
+	if (m == NULL)
+		return control;
+
 	sc = p;
 	sc->sc_uid = kauth_cred_getuid(l->l_cred);
 	sc->sc_euid = kauth_cred_geteuid(l->l_cred);
@@ -1585,6 +1647,7 @@
 
 	return m_add(control, m);
 }
+#endif
 
 /*
  * Do a mark-sweep GC of files in the system, to free up any which are
Index: sys/sys/socket.h
===================================================================
RCS file: /cvsroot/src/sys/sys/socket.h,v
retrieving revision 1.118
diff -u -r1.118 socket.h
--- sys/sys/socket.h	13 Oct 2015 21:28:34 -0000	1.118
+++ sys/sys/socket.h	29 Mar 2016 16:10:49 -0000
@@ -349,6 +349,7 @@
  * Socket credentials.
  */
 struct sockcred {
+	pid_t	sc_pid;			/* process id */
 	uid_t	sc_uid;			/* real user id */
 	uid_t	sc_euid;		/* effective user id */
 	gid_t	sc_gid;			/* real group id */
@@ -596,8 +597,9 @@
 #define	SCM_RIGHTS	0x01		/* access rights (array of int) */
 #if defined(_NETBSD_SOURCE)
 /* 			0x02		   timestamp (struct timeval50) */
-#define	SCM_CREDS	0x04		/* credentials (struct sockcred) */
+/*			0x04		   credentials (struct osockcred) */
 #define	SCM_TIMESTAMP	0x08		/* timestamp (struct timeval) */
+#define	SCM_CREDS	0x10		/* credentials (struct sockcred) */
 #endif
 
 /*
Index: sys/sys/un.h
===================================================================
RCS file: /cvsroot/src/sys/sys/un.h,v
retrieving revision 1.56
diff -u -r1.56 un.h
--- sys/sys/un.h	2 May 2015 17:18:04 -0000	1.56
+++ sys/sys/un.h	29 Mar 2016 16:10:49 -0000
@@ -56,9 +56,10 @@
  * Socket options for UNIX IPC domain.
  */
 #if defined(_NETBSD_SOURCE)
-#define	LOCAL_CREDS	0x0001		/* pass credentials to receiver */
+#define	LOCAL_OCREDS	0x0001		/* pass credentials to receiver */
 #define	LOCAL_CONNWAIT	0x0002		/* connects block until accepted */
 #define	LOCAL_PEEREID	0x0003		/* get peer identification */
+#define	LOCAL_CREDS	0x0004		/* pass credentials to receiver */
 #endif
 
 /*
Index: sys/sys/unpcb.h
===================================================================
RCS file: /cvsroot/src/sys/sys/unpcb.h,v
retrieving revision 1.17
diff -u -r1.17 unpcb.h
--- sys/sys/unpcb.h	24 Apr 2008 11:38:39 -0000	1.17
+++ sys/sys/unpcb.h	29 Mar 2016 16:10:49 -0000
@@ -97,11 +97,12 @@
  * in with data for the listening process.  This is set up in unp_bind() when
  * it fills in unp_connid for later consumption by unp_connect().
  */
-#define	UNP_WANTCRED	0x0001		/* credentials wanted */
+#define	UNP_OWANTCRED	0x0001		/* credentials wanted */
 #define	UNP_CONNWAIT	0x0002		/* connect blocks until accepted */
 #define	UNP_EIDSVALID	0x0004		/* unp_connid contains valid data */
 #define	UNP_EIDSBIND	0x0008		/* unp_connid was set by bind() */
 #define	UNP_BUSY	0x0010		/* busy connecting or binding */
+#define	UNP_WANTCRED	0x0020		/* credentials wanted */
 
 #define	sotounpcb(so)	((struct unpcb *)((so)->so_pcb))
 


Home | Main Index | Thread Index | Old Index