cvs commit: src/sys/nfsclient nfs_socket.c

John Baldwin jhb at freebsd.org
Fri Jan 11 15:33:10 PST 2008


On Friday 11 January 2008 11:54:44 am John Baldwin wrote:
> On Thursday 10 January 2008 09:36:28 pm Alfred Perlstein wrote:
> > * Peter Wemm <peter at wemm.org> [080110 17:39] wrote:
> > > On Jan 10, 2008 5:00 PM, Alfred Perlstein <alfred at freebsd.org> wrote:
> > > >
> > > > * John Baldwin <jhb at FreeBSD.org> [080110 15:33] wrote:
> > > > > jhb         2008-01-10 23:36:00 UTC
> > > > >
> > > > >   FreeBSD src repository
> > > > >
> > > > >   Modified files:
> > > > >     sys/nfsclient        nfs_socket.c
> > > > >   Log:
> > > > >   Pass curthread to various socket routines (socreate(), sobind(), and
> > > > >   soconnect()) instead of &thread0 when establishing a connection to the NFS
> > > > >   server.  Otherwise inconsistent credentials may be used when setting up
> > > > >   the NFS socket.
> > > >
> > > > I'm not sure, but I think this may be a regression, I seem to recall
> > > > that a long time ago it was switched to &thread0 because otherwise
> > > > certain operations can fail due to curthread not running as root.
> > > 
> > > That's my recollection too.  For example, when nfs is configured to
> > > bind to a priviliged local port for making queries or connections, it
> > > had to be done as root.  With tcp mounts, the connection can be
> > > dropped and a reconnect required at any time.
> > 
> > This could be implemented by a handoff to a thread that does the
> > appropriate setuid call beforehand, or perhaps the credential
> > inconsistencies can be further expained or fixed.
> 
> The problem case I have is doing a mount inside of a jail.  The socket's
> credential is jailed but thread0's credential is not, and you end up with
> odd behavior where sobind() treats the socket as non-jailed (and thus only
> binds the local port and not the local IP address) but soconnect() treats
> the socket as jailed and fails with EINVAL when it sees a partially bound
> socket.  (sobind() of a jailed socket sets both the port and IP.)  What I
> can do as a workaround is to change curthread's ucred to be the NFS mount's
> credential during nfs_connect() by fiddling with td_ucred.  It would be
> safe as it wouldn't affect other threads even in the same process and the
> current thread isn't going to be doing anything else until the function
> returns with the restored credentials, just hackish.

I have a patch to do this and it works both inside and out of jails for both
UDP and TCP mounts.  I used tcpdrop on the server in each case to force the
client to reconnect on a different socket and that worked ok while doing
a ls -l as a mere mortal.  I also verified that this test case (dropping the
existing TCP connection) caused the ls process to hang in "nfscon" with the
change I committed yesterday.  This is relative to what is in HEAD now:

Index: nfs_socket.c
===================================================================
RCS file: /host/cvs/usr/cvs/src/sys/nfsclient/nfs_socket.c,v
retrieving revision 1.156
diff -u -r1.156 nfs_socket.c
--- nfs_socket.c	10 Jan 2008 23:36:00 -0000	1.156
+++ nfs_socket.c	11 Jan 2008 17:20:30 -0000
@@ -264,7 +264,19 @@
 	int error, rcvreserve, sndreserve;
 	int pktscale;
 	struct sockaddr *saddr;
-	struct thread *td = curthread; /* only used for socreate and sobind */
+	struct ucred *origcred;
+	struct thread *td = curthread;
+
+	/*
+	 * We need to establish the socket using the credentials of
+	 * the mountpoint.  Some parts of this process (such as
+	 * sobind() and soconnect()) will use the curent thread's
+	 * credential instead of the socket credential.  To work
+	 * around this, temporarily change the current thread's
+	 * credential to that of the mountpoint.
+	 */
+	origcred = td->td_ucred;
+	td->td_ucred = nmp->nm_mountp->mnt_cred;
 
 	if (nmp->nm_sotype == SOCK_STREAM) {
 		mtx_lock(&nmp->nm_mtx);
@@ -453,6 +465,9 @@
 	so->so_snd.sb_flags |= SB_NOINTR;
 	SOCKBUF_UNLOCK(&so->so_snd);
 
+	/* Restore current thread's credentials. */
+	td->td_ucred = origcred;
+
 	mtx_lock(&nmp->nm_mtx);
 	/* Initialize other non-zero congestion variables */
 	nfs_init_rtt(nmp);
@@ -463,6 +478,9 @@
 	return (0);
 
 bad:
+	/* Restore current thread's credentials. */
+	td->td_ucred = origcred;
+
 	nfs_disconnect(nmp);
 	return (error);
 }


-- 
John Baldwin


More information about the cvs-src mailing list