>Number:         176419
>Category:       kern
>Synopsis:       [patch] socketpair support for LOCAL_PEERCRED
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 25 13:00:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Nicholas Wilson
>Release:        Release 7.4 to Release 9.1
>Organization:
>Environment:
FreeBSD EB5-FBSD-7-4-x64.realvnc.ltd 7.4-RELEASE-p9 FreeBSD 7.4-RELEASE-p9 #0: 
Mon Jun 11 19:47:58 UTC 2012     
r...@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
I've noticed that getpeereid/LOCAL_PEERCRED doesn't work with sockets created 
through socketpair, but only through actual listen/connect calls.

I'd like to suggest we support peercred for socketpair-created sockets.

Motivation:
1. All unix-domain STREAM sockets should be created equal.

2. getpeerucred on Solaris and SO_PEERCRED on Linux work fine on socketpair 
sockets. More relevantly, the MacOS X implementation of LOCAL_PEERCRED works 
with socketpair sockets. (A point against is that AIX's getpeereid follows the 
BSD behaviour of requiring a connect/listen call.) Programmers are therefore 
more likely to expect it to work than not. Apart from AIX, we're the only 
people not providing this capability.

3. Real-world uses. I was actually trying to sandbox a daemon with capsicum, 
which requires a certain amount of mucking around with file descriptor passing. 
Being able to establish a channel with a socketpair, hand it to a secure 
daemon, and be able to check the peer's credentials in the daemon, is a 
reasonable use-case.

4. Compatibility. It's not going to break old applications to make the
change.
>How-To-Repeat:
int main() {
  int fds[2];
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) exit(1);
  uid_t uid; gid_t gid;
  return getpeereid(fds[0], &uid, &gid) < 0 ? 1 : 0;
}

Expected result: does not fail
Actual result: fails
>Fix:
I notice that in unp_connect, we stash the peercred of the thread, then call on 
to unp_connect2. In kern_socketpair, we call straight through to unp_connect2 
(through pr_usrreqs->pru_connect2).

Patch attached hopefully fixes the problem in an acceptable way. It's the 
responsibility of the socketpair call to provide stamp the appropriate 
credentials when it makes a connection (unp_connect2 doesn't know enough about 
the calling context to take it on itself to do this).

Patch attached. unix.4.man and getpeereid.3.man would have to be updated also.

Patch attached with submission follows:

--- sys/kern/uipc_syscalls.c.RELEASE-9.1-243808    2013-02-21
13:37:31.778270145 +0000
+++ sys/kern/uipc_syscalls.c   2013-02-21 13:45:58.747896673 +0000
@@ -642,6 +642,19 @@
                 error = soconnect2(so2, so1);
                 if (error)
                        goto free4;
+       } else if (so1->so_proto->pr_flags & PR_CONNREQUIRED) {
+               struct unpcb *unp, *unp2;
+               unp = sotounpcb(so1);
+               unp2 = sotounpcb(so2);
+               UNP_PCB_LOCK(unp);
+               UNP_PCB_LOCK(unp2);
+               cru2x(td->td_ucred, &unp->unp_peercred);
+               memcpy(&unp2->unp_peercred, &unp->unp_peercred,
+                       sizeof(unp2->unp_peercred));
+               unp->unp_flags |= UNP_HAVEPC;
+               unp2->unp_flags |= UNP_HAVEPC;
+               UNP_PCB_UNLOCK(unp);
+               UNP_PCB_UNLOCK(unp2);
        }
        finit(fp1, FREAD | FWRITE, DTYPE_SOCKET, fp1->f_data, &socketops);
        finit(fp2, FREAD | FWRITE, DTYPE_SOCKET, fp2->f_data, &socketops);


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to