Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 29 Dec 2001 10:23:57 -0500 (EST)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        arch@FreeBSD.org
Subject:   adding cred argument to socreate(), making NFS connect using , mount-time credential
Message-ID:  <Pine.NEB.3.96L.1011229101514.84600D-100000@fledge.watson.org>

next in thread | raw e-mail | index | archive | help

Attached please find a diff that does the following:

(1) Makes the credential used by socreate() an explicit argument to
    socreate(), rather than getting it implicitly from the thread
    argument.

(2) Make NFS cache the credential provided at mount-time, and use the
    cached credential (nfsmount->nm_so) when making calls to socreate().

This fixes the following bug:

  When NFS re-connects TCP (or initially connects UDP) it uses the
  credential of the process initiating the current NFS vnode operation. 
  When IPFW uid/gid rules are used to limit traffic based on the
  sending/delivering socket credential, NFS traffic may unintentionally be
  limited.  Likewise, use of ident and related getcred() on connections
  will return the wrong credential. 

It also fixes the soon-to-be bug:

  When using mandatory access control to limit interface and socket
  delivery of packets with inappropriate labels (integrity, sensitivity,
  type enforcement), the label on the socket will be set based on the
  credential initiating the NFS vode operation.  This means that the first
  process to generate NFS I/O, or later on a reconnect, will determine the
  label of the NFS requests, which in some cases will result in NFS
  failure due to NFS packets being blocked by access control rules on the
  socket/interface.

It might be worth considering pushing the ucred from struct nfsmount to
struct mount if other filesystems need it.  However, none currently do.  I
plan to commit it in a couple of days unless there are objections.

Robert N M Watson             FreeBSD Core Team, TrustedBSD Project
robert@fledge.watson.org      NAI Labs, Safeport Network Services


==== //depot/vendor/freebsd/sys/dev/streams/streams.c#3 (text+ko) - //depot/user/rwatson/mountcred/sys/dev/streams/streams.c#2 (text+ko) ==== content
@@ -264,7 +264,8 @@
 	if ((error = falloc(td, &fp, &fd)) != 0)
 	  return error;

-	if ((error = socreate(family, &so, type, protocol, td)) != 0) {
+	if ((error = socreate(family, &so, type, protocol,
+	    td->td_proc->p_ucred, td)) != 0) {
 	  p->p_fd->fd_ofiles[fd] = 0;
 	  ffree(fp);
 	  return error;
==== //depot/vendor/freebsd/sys/fs/fifofs/fifo_vnops.c#4 (text+ko) - //depot/user/rwatson/mountcred/sys/fs/fifofs/fifo_vnops.c#2 (text+ko) ==== content
@@ -174,14 +174,16 @@
 	if ((fip = vp->v_fifoinfo) == NULL) {
 		MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
 		vp->v_fifoinfo = fip;
-		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, ap->a_td);
+		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0,
+		    ap->a_td->td_proc->p_ucred, ap->a_td);
 		if (error) {
 			free(fip, M_VNODE);
 			vp->v_fifoinfo = NULL;
 			return (error);
 		}
 		fip->fi_readsock = rso;
-		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, ap->a_td);
+		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0,
+		    ap->a_td->td_proc->p_ucred, ap->a_td);
 		if (error) {
 			(void)soclose(rso);
 			free(fip, M_VNODE);
==== //depot/vendor/freebsd/sys/fs/portalfs/portal_vnops.c#2 (text+ko) - //depot/user/rwatson/mountcred/sys/fs/portalfs/portal_vnops.c#2 (text+ko) ==== content
@@ -246,7 +246,8 @@
 	/*
 	 * Create a new socket.
 	 */
-	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0, ap->a_td);
+	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0,
+	    ap->a_td->td_proc->p_ucred, ap->a_td);
 	if (error)
 		goto bad;
 
==== //depot/vendor/freebsd/sys/kern/uipc_socket.c#9 (text+ko) - //depot/user/rwatson/mountcred/sys/kern/uipc_socket.c#2 (text+ko) ==== content
@@ -137,11 +137,12 @@
  * closed with soclose().
  */
 int
-socreate(dom, aso, type, proto, td)
+socreate(dom, aso, type, proto, cred, td)
 	int dom;
 	struct socket **aso;
 	register int type;
 	int proto;
+	struct ucred *cred;
 	struct thread *td;
 {
 	register struct protosw *prp;
@@ -172,7 +173,7 @@
 	TAILQ_INIT(&so->so_incomp);
 	TAILQ_INIT(&so->so_comp);
 	so->so_type = type;
-	so->so_cred = crhold(td->td_proc->p_ucred);
+	so->so_cred = crhold(cred);
 	so->so_proto = prp;
 	soref(so);
 	error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
==== //depot/vendor/freebsd/sys/kern/uipc_syscalls.c#5 (text+ko) - //depot/user/rwatson/mountcred/sys/kern/uipc_syscalls.c#3 (text+ko) ==== content
@@ -132,7 +132,8 @@
 	if (error)
 		goto done2;
 	fhold(fp);
-	error = socreate(uap->domain, &so, uap->type, uap->protocol, td);
+	error = socreate(uap->domain, &so, uap->type, uap->protocol,
+	    td->td_proc->p_ucred, td);
 	if (error) {
 		if (fdp->fd_ofiles[fd] == fp) {
 			fdp->fd_ofiles[fd] = NULL;
@@ -478,10 +479,12 @@
 	int fd, error, sv[2];
 
 	mtx_lock(&Giant);
-	error = socreate(uap->domain, &so1, uap->type, uap->protocol, td);
+	error = socreate(uap->domain, &so1, uap->type, uap->protocol,
+	    td->td_proc->p_ucred, td);
 	if (error)
 		goto done2;
-	error = socreate(uap->domain, &so2, uap->type, uap->protocol, td);
+	error = socreate(uap->domain, &so2, uap->type, uap->protocol,
+	    td->td_proc->p_ucred, td);
 	if (error)
 		goto free1;
 	error = falloc(td, &fp1, &fd);
==== //depot/vendor/freebsd/sys/netgraph/ng_ksocket.c#6 (text+ko) - //depot/user/rwatson/mountcred/sys/netgraph/ng_ksocket.c#2 (text+ko) ==== content
@@ -586,7 +586,8 @@
 			return (EINVAL);
 
 		/* Create the socket */
-		error = socreate(family, &priv->so, type, protocol, td);
+		error = socreate(family, &priv->so, type, protocol,
+		   td->td_proc->p_ucred, td);
 		if (error != 0)
 			return (error);
 
==== //depot/vendor/freebsd/sys/netsmb/smb_trantcp.c#2 (text+ko) - //depot/user/rwatson/mountcred/sys/netsmb/smb_trantcp.c#2 (text+ko) ==== content
@@ -226,7 +226,8 @@
 	struct socket *so;
 	int error, s;
 
-	error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, td);
+	error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP,
+	    td->td_proc->p_ucred, td);
 	if (error)
 		return error;
 	nbp->nbp_tso = so;
==== //depot/vendor/freebsd/sys/nfsclient/bootp_subr.c#3 (text+ko) - //depot/user/rwatson/mountcred/sys/nfsclient/bootp_subr.c#2 (text+ko) ==== content
@@ -586,7 +586,8 @@
 	/*
 	 * Create socket and set its recieve timeout.
 	 */
-	error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td);
+	error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_proc->p_ucred,
+	    td);
 	if (error != 0)
 		goto out;
 
@@ -971,7 +972,8 @@
 	struct ifaddr *ifa;
 	struct sockaddr_dl *sdl;
 
-	error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td);
+	error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0,
+	    td->td_proc->p_ucred, td);
 	if (error != 0)
 		panic("nfs_boot: socreate, error=%d", error);
 
==== //depot/vendor/freebsd/sys/nfsclient/krpc_subr.c#3 (text+ko) - //depot/user/rwatson/mountcred/sys/nfsclient/krpc_subr.c#2 (text+ko) ==== content
@@ -215,7 +215,8 @@
 	/*
 	 * Create socket and set its recieve timeout.
 	 */
-	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td)))
+	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,
+	    td->td_proc->p_ucred, td)))
 		goto out;
 
 	tv.tv_sec = 1;
==== //depot/vendor/freebsd/sys/nfsclient/nfs_socket.c#6 (text+ko) - //depot/user/rwatson/mountcred/sys/nfsclient/nfs_socket.c#4 (text+ko) ==== content
@@ -162,7 +162,7 @@
 	nmp->nm_so = (struct socket *)0;
 	saddr = nmp->nm_nam;
 	error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype,
-		nmp->nm_soproto, td);
+		nmp->nm_soproto, nmp->nm_cred, td);
 	if (error)
 		goto bad;
 	so = nmp->nm_so;
==== //depot/vendor/freebsd/sys/nfsclient/nfs_vfsops.c#9 (text+ko) - //depot/user/rwatson/mountcred/sys/nfsclient/nfs_vfsops.c#4 (text+ko) ==== content
@@ -92,7 +92,8 @@
 static int	nfs_iosize(struct nfsmount *nmp);
 static void	nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp);
 static int	mountnfs(struct nfs_args *, struct mount *,
-		    struct sockaddr *, char *, char *, struct vnode **);
+		    struct sockaddr *, char *, char *, struct vnode **,
+		    struct ucred *cred);
 static int	nfs_mount(struct mount *mp, char *path, caddr_t data,
 		    struct nameidata *ndp, struct thread *td);
 static int	nfs_unmount(struct mount *mp, int mntflags, struct thread *td);
@@ -377,6 +378,7 @@
 nfs_mountroot(struct mount *mp)
 {
 	struct mount  *swap_mp;
+	struct nfsmount *nmp = VFSTONFS(mp);
 	struct nfsv3_diskless *nd = &nfsv3_diskless;
 	struct socket *so;
 	struct vnode *vp;
@@ -419,7 +421,8 @@
 	 * Do enough of ifconfig(8) so that the critical net interface can
 	 * talk to the server.
 	 */
-	error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, td);
+	error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0,
+	    nmp->nm_cred, td);
 	if (error)
 		panic("nfs_mountroot: socreate(%04x): %d",
 			nd->myif.ifra_addr.sa_family, error);
@@ -557,7 +560,8 @@
 	mp->mnt_kern_flag = 0;
 	mp->mnt_flag = mountflag;
 	nam = dup_sockaddr((struct sockaddr *)sin, 1);
-	if ((error = mountnfs(args, mp, nam, which, path, vpp)) != 0) {
+	if ((error = mountnfs(args, mp, nam, which, path, vpp, td->td_ucred))
+	    != 0) {
 		printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
 		mp->mnt_vfc->vfc_refcount--;
 		vfs_unbusy(mp, td);
@@ -785,7 +789,7 @@
 	if (error)
 		return (error);
 	args.fh = nfh;
-	error = mountnfs(&args, mp, nam, path, hst, &vp);
+	error = mountnfs(&args, mp, nam, path, hst, &vp, td->td_ucred);
 	return (error);
 }
 
@@ -794,7 +798,7 @@
  */
 static int
 mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
-    char *pth, char *hst, struct vnode **vpp)
+    char *pth, char *hst, struct vnode **vpp, struct ucred *cred)
 {
 	struct nfsmount *nmp;
 	struct nfsnode *np;
@@ -814,6 +818,7 @@
 	}
 	vfs_getnewfsid(mp);
 	nmp->nm_mountp = mp;
+	nmp->nm_cred = crhold(cred);
 
 	/*
 	 * V2 can only handle 32 bit filesizes.  A 4GB-1 limit may be too
==== //depot/vendor/freebsd/sys/nfsclient/nfsmount.h#2 (text+ko) - //depot/user/rwatson/mountcred/sys/nfsclient/nfsmount.h#3 (text+ko) ==== content
@@ -53,6 +53,7 @@
 	u_char	nm_fh[NFSX_V3FHMAX];	/* File handle of root dir */
 	int	nm_fhsize;		/* Size of root file handle */
 	struct	socket *nm_so;		/* Rpc socket */
+	struct	ucred *nm_cred;		/* Cached mount-time credential */
 	int	nm_sotype;		/* Type of socket */
 	int	nm_soproto;		/* and protocol */
 	int	nm_soflags;		/* pr_flags for socket protocol */
==== //depot/vendor/freebsd/sys/sys/socketvar.h#9 (text+ko) - //depot/user/rwatson/mountcred/sys/sys/socketvar.h#2 (text+ko) ==== content
@@ -383,7 +383,7 @@
 int	soconnect __P((struct socket *so, struct sockaddr *nam, struct thread *td));
 int	soconnect2 __P((struct socket *so1, struct socket *so2));
 int	socreate __P((int dom, struct socket **aso, int type, int proto,
-	    struct thread *td));
+	    struct ucred *cred, struct thread *td));
 int	sodisconnect __P((struct socket *so));
 void	sofree __P((struct socket *so));
 int	sogetopt __P((struct socket *so, struct sockopt *sopt));


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.1011229101514.84600D-100000>