Subject: Re: UBC turns EACCESS into EFAULT (e.g.: with NFS)
To: Ignatios Souvatzis <is@netbsd.org>
From: Chuck Silvers <chuq@chuq.com>
List: tech-kern
Date: 12/07/2003 10:20:21
On Sun, Dec 07, 2003 at 04:33:07PM +0100, Ignatios Souvatzis wrote:
> errno is set to "Bad address" (EFAULT) when a suid-root program is trying
> to read through an open file handle that the NFS server doesn't allow root
> to read.
> 
> [I suspect the same would happen if you replace root by some other user.]
> 
> I suspect this happens because the original NFS EACCESS error is somehow
> lost while being propagated through UBC ...
> 
> NFS / UBC experts: is it possible to propagate the original NFS error code
> to the read system call exit? Actually - the same might happen if you read
> a faulty (e.g. floppy) disk - reading EFAULT instead of EIO will be
> confusing here, too. (I didn't test this.)

this is because of this code in trap():

		error = uvm_fault(map, va, 0, ftype);
...
		if (error == EACCES) {
			ksi.ksi_code = SEGV_ACCERR;
			error = EFAULT;
		} else {
			ksi.ksi_code = SEGV_MAPERR;
		}

(this is from i386/trap.c, but every trap handler does the same thing.)

the reason for this code is so that things that try to (eg.)
copyout() to a read-only part of the address space will get EFAULT
from syscalls instead of EACCES.  NFS is special in this regard,
since other file systems will never return EACCES from their VOP_GETPAGES().

it's really a bug in NFS that reads from an open file descriptor can
fail due to permissions, that violates the normal security model.
solaris doesn't have this problem, my little test program which
reproduces this problem on netbsd works fine on solaris.
a solaris NFS client reading from a solaris NFS server allows
reads from existing file descriptors even if the file has no
read permission for anyone on the server.

looking at the netbsd NFS code, our NFS server will allow reads and writes
for the file owner regardless of the file's modes.  in nfsrv_access():

	error = VOP_ACCESS(vp, flags, cred, p);
	/*
	 * Allow certain operations for the owner (reads and writes
	 * on files that are already open).
	 */
	if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
		error = 0;


so our NFS client should just always use the file's owner in the creds
for read and write RPCs.  according to snoop, this is what solaris does
as well.

-Chuck