From a973eeb2c176e00dba8a7ec7bbb2a844ffd832b7 Mon Sep 17 00:00:00 2001
From: Doug Rabson <dfr@FreeBSD.org>
Date: Fri, 9 May 1997 13:18:42 +0000
Subject: [PATCH] Prevent a mapped root which appears on the server as e.g.
 nobody from accessing files which it shouldn't be able to.  This required a
 better approximation of VOP_ACCESS for NFSv2 (NFSv3 already has an ACCESS rpc
 which is a better solution) and adding a call to VOP_ACCESS from VOP_LOOKUP.

PR:		kern/876, kern/2635
Submitted by:	David Malone <dwmalone@maths.tcd.ie> (for kern/2635)
---
 sys/nfs/nfs_vnops.c       | 50 ++++++++++++++++++++++++++++++++++++---
 sys/nfsclient/nfs_vnops.c | 50 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 94 insertions(+), 6 deletions(-)

diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index 72a7a04287b7..a49882017079 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)nfs_vnops.c	8.16 (Berkeley) 5/27/95
- * $Id: nfs_vnops.c,v 1.46 1997/04/04 17:49:33 dfr Exp $
+ * $Id: nfs_vnops.c,v 1.47 1997/05/04 09:17:36 phk Exp $
  */
 
 
@@ -410,8 +410,49 @@ nfs_access(ap)
 		}
 		nfsm_reqdone;
 		return (error);
-	} else
-		return (nfsspec_access(ap));
+	} else {
+		if (error = nfsspec_access(ap))
+			return (error);
+
+		/*
+		 * Attempt to prevent a mapped root from accessing a file
+		 * which it shouldn't.  We try to read a byte from the file
+		 * if the user is root and the file is not zero length.
+		 * After calling nfsspec_access, we should have the correct
+		 * file size cached.
+		 */
+		if (ap->a_cred->cr_uid == 0 && (ap->a_mode & VREAD)
+		    && VTONFS(vp)->n_size > 0) {
+			struct iovec aiov;
+			struct uio auio;
+			char buf[1];
+
+			aiov.iov_base = buf;
+			aiov.iov_len = 1;
+			auio.uio_iov = &aiov;
+			auio.uio_iovcnt = 1;
+			auio.uio_offset = 0;
+			auio.uio_resid = 1;
+			auio.uio_segflg = UIO_SYSSPACE;
+			auio.uio_rw = UIO_READ;
+			auio.uio_procp = ap->a_p;
+
+			if (vp->v_type == VREG)
+				error = nfs_readrpc(vp, &auio, ap->a_cred);
+			else if (vp->v_type == VDIR) {
+				char* buf;
+				buf = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK);
+				aiov.iov_base = buf;
+				aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ;
+				error = nfs_readdirrpc(vp, &auio, ap->a_cred);
+				free(buf, M_TEMP);
+			} else if (vp->v_type = VLNK)
+				error = nfs_readlinkrpc(vp, &auio, ap->a_cred);
+			else
+				error = EACCES;
+		}
+		return (error);
+	}
 }
 
 /*
@@ -834,6 +875,9 @@ nfs_lookup(ap)
 		struct vattr vattr;
 		int vpid;
 
+		if (error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))
+			return (error);
+
 		newvp = *vpp;
 		vpid = newvp->v_id;
 		/*
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 72a7a04287b7..a49882017079 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)nfs_vnops.c	8.16 (Berkeley) 5/27/95
- * $Id: nfs_vnops.c,v 1.46 1997/04/04 17:49:33 dfr Exp $
+ * $Id: nfs_vnops.c,v 1.47 1997/05/04 09:17:36 phk Exp $
  */
 
 
@@ -410,8 +410,49 @@ nfs_access(ap)
 		}
 		nfsm_reqdone;
 		return (error);
-	} else
-		return (nfsspec_access(ap));
+	} else {
+		if (error = nfsspec_access(ap))
+			return (error);
+
+		/*
+		 * Attempt to prevent a mapped root from accessing a file
+		 * which it shouldn't.  We try to read a byte from the file
+		 * if the user is root and the file is not zero length.
+		 * After calling nfsspec_access, we should have the correct
+		 * file size cached.
+		 */
+		if (ap->a_cred->cr_uid == 0 && (ap->a_mode & VREAD)
+		    && VTONFS(vp)->n_size > 0) {
+			struct iovec aiov;
+			struct uio auio;
+			char buf[1];
+
+			aiov.iov_base = buf;
+			aiov.iov_len = 1;
+			auio.uio_iov = &aiov;
+			auio.uio_iovcnt = 1;
+			auio.uio_offset = 0;
+			auio.uio_resid = 1;
+			auio.uio_segflg = UIO_SYSSPACE;
+			auio.uio_rw = UIO_READ;
+			auio.uio_procp = ap->a_p;
+
+			if (vp->v_type == VREG)
+				error = nfs_readrpc(vp, &auio, ap->a_cred);
+			else if (vp->v_type == VDIR) {
+				char* buf;
+				buf = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK);
+				aiov.iov_base = buf;
+				aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ;
+				error = nfs_readdirrpc(vp, &auio, ap->a_cred);
+				free(buf, M_TEMP);
+			} else if (vp->v_type = VLNK)
+				error = nfs_readlinkrpc(vp, &auio, ap->a_cred);
+			else
+				error = EACCES;
+		}
+		return (error);
+	}
 }
 
 /*
@@ -834,6 +875,9 @@ nfs_lookup(ap)
 		struct vattr vattr;
 		int vpid;
 
+		if (error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))
+			return (error);
+
 		newvp = *vpp;
 		vpid = newvp->v_id;
 		/*