2004-04-29 11:00:49

by Colin Paton

[permalink] [raw]
Subject: Possible permissions bug on NFSv3 kernel client

Hi,

I have found what I think might be a bug with the kernel NFS v3 client
code. It is however more likely that I am doing something wrong -
perhaps someone might verify my attempted fix!

Google suggests that other people might be having the same problem - but
I couldn't find a fix so had a go myself.

I am trying to export a filesystem as read-only from a server. On my
client machine I boot into an initial filesystem, mount the 'real' root
filesystem over NFS, then pivot_root to it.

If I mount the root filesystem as NFSv2 (using mount -o nfsvers=2) then
everything works correctly. If I mount as NFSv3 then I run into problems
when trying to write to block/character device files.

Both the client and the server are using kernel 2.4.25, with knfsd on
the server. I case it matters, I am using busybox 1.00-pre8 mount, but
the same thing happens with mount version 2.11n on a Debian system.

Essentially, it does not appear to be possible to write to device files
which are mounted on a read-only NFSv3 filesystem. The problem only
occurs with NFS v3 - Mounting the filesystem as NFSv2 (using mount -o
nfsvers=2) is fine.

To reproduce:

- On a server machine create a character device file on a read-only NFS
exported directory (called 'tty3' in this example)
- Mount the NFS volume on a client machine.
- From the client machine, run 'cat > /mnt/tty3'

The kernel returns EACCES when trying to open the 'tty3' device.

The 'cat > /mnt/tty3' command works properly if the directory is
exported read-write.

Reading from the device file (cat < /mnt/tty3) is fine in all cases.

Doing a trace with ethereal shows that an NFS 'access' RPC is sent to
the server, with the access bitmask set to 'allow MODIFY+EXTEND'. The
server returns that these are not allowed, as the filesystem is mounted
read-only. This causes the EACCES error.

I modified the client kernel code as follows, to make the NFS client
behave differently:

In file: fs/nfs/nfs3proc.c modify nfs3_proc_access(). This calls the
access RPC on the server. I added the following to the code:

if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
{
// Leave arg.access untouched.

}

...so that the the MODIFY and EXTEND bits aren't set when writing to a
block or character device.

This fix works, yet I believe it might introduce a security problem. I
am not sure where permissions should be properly checked.

The access RPC appears specific to NFS v3. I am not sure how NFS v2 does
permissions checking.

In addition, I am not 100% sure if the problem is at the client end or
the server end - have I just masked the problem rather than actually
fixing it?

Alternatively, of course, there may be some specific reason why NFSv3 is
not recommended for root filesystems - in which case it might be better
to fall back to NFSv2.

Thanks,

Colin



2004-04-29 17:39:48

by Trond Myklebust

[permalink] [raw]
Subject: Re: Possible permissions bug on NFSv3 kernel client

On Thu, 2004-04-29 at 07:02, Colin Paton wrote:

> In file: fs/nfs/nfs3proc.c modify nfs3_proc_access(). This calls the
> access RPC on the server. I added the following to the code:
>
> if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
> {
> // Leave arg.access untouched.
>
> }
>
> ...so that the the MODIFY and EXTEND bits aren't set when writing to a
> block or character device.

Hmm... Why shouldn't the MODIFY bit at least be set if the user
requested write access to the device?

Cheers,
Trond

2004-04-29 20:53:53

by Pascal Schmidt

[permalink] [raw]
Subject: Re: Possible permissions bug on NFSv3 kernel client

On Thu, 29 Apr 2004 19:50:06 +0200, you wrote in linux.kernel:

>> ...so that the the MODIFY and EXTEND bits aren't set when writing to a
>> block or character device.
>
> Hmm... Why shouldn't the MODIFY bit at least be set if the user
> requested write access to the device?

It's somewhat of a mixed-up situation for device nodes exported via
NFSv3. Permission bits are on the server, but the actual write does
not happen via NFS (as v3 WRITE only works on regular files).

--
Ciao,
Pascal

2004-04-29 21:20:54

by Trond Myklebust

[permalink] [raw]
Subject: Re: Possible permissions bug on NFSv3 kernel client

On Thu, 2004-04-29 at 16:49, Pascal Schmidt wrote:
> On Thu, 29 Apr 2004 19:50:06 +0200, you wrote in linux.kernel:
>
> >> ...so that the the MODIFY and EXTEND bits aren't set when writing to a
> >> block or character device.
> >
> > Hmm... Why shouldn't the MODIFY bit at least be set if the user
> > requested write access to the device?
>
> It's somewhat of a mixed-up situation for device nodes exported via
> NFSv3. Permission bits are on the server, but the actual write does
> not happen via NFS (as v3 WRITE only works on regular files).

It's not "mixed up" at all: the permissions checking has to be done by
the server, period.
All the file security information (the mode bits, owner uid, group gid,
ACLs etc) that determine whether or not the open() should succeed are
defined on the *server* not on the client. If the former is doing some
form of mapping of those values (in particular if it is doing some form
of root/uid/gid squashing) then the only way for the client to get it
right is to make an ACCESS call.

The fact that the subsequent writes go to a device on the client is
entirely irrelevant.

Cheers,
Trond

2004-04-30 20:17:53

by Pascal Schmidt

[permalink] [raw]
Subject: Re: Possible permissions bug on NFSv3 kernel client

On Thu, 29 Apr 2004 23:30:50 +0200, you wrote in linux.kernel:

> It's not "mixed up" at all: the permissions checking has to be done by
> the server, period.

Then it's at least inconsistent with local filesystem behaviour. fsck
has no problem opening device nodes for writing on my root filesystem
even though it is mounted read-only at that point.

--
Ciao,
Pascal

2004-04-30 20:40:28

by Trond Myklebust

[permalink] [raw]
Subject: Re: Possible permissions bug on NFSv3 kernel client

On Fri, 2004-04-30 at 16:17, Pascal Schmidt wrote:
> Then it's at least inconsistent with local filesystem behaviour. fsck
> has no problem opening device nodes for writing on my root filesystem
> even though it is mounted read-only at that point.

So why do you think that is inconsistent with my statement: "the
permissions checking has to be done by the server, period"?

The read-only mount option is a *local* override of the write
permissions on the server. It applies to regular files, directories, and
soft links *only*.
The read-only mount option does *not apply* to char/block devices such
as /dev/hd[a-z]*, /dev/tty*. Permission checks on open() for those
devices are done on the server *only* via the ACCESS rpc call.

This should be entirely consistent with local file behaviour.
Particularly since the code to deal with the read-only mount option in
nfs_permission() was pretty much cut-n-pasted from vfs_permission().

Cheers,
Trond