Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Jan 2013 09:26:46 -0500 (EST)
From:      Rick Macklem <rmacklem@uoguelph.ca>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        Rick Macklem <rmacklem@FreeBSD.org>, fs@FreeBSD.org
Subject:   Re: [PATCH] Better handle NULL utimes() in the NFS client
Message-ID:  <1642392672.2036529.1358346406018.JavaMail.root@erie.cs.uoguelph.ca>
In-Reply-To: <20130116151051.O1060@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Bruce Evans wrote:
> On Tue, 15 Jan 2013, Rick Macklem wrote:
> 
> > Bruce Evans wrote:
> 
> >> I can't see anything that does the different permissions check for
> >> the VA_UTIMES_NULL case, and testing shows that this case is just
> >> broken,
> >> at least for an old version of the old nfs client -- the same
> >> permissions
> >> are required for all cases, but write permission is supposed to be
> >> enough for the VA_UTIMES_NULL case (since write permission is
> >> sufficient
> >> for setting the mtime to the current time (plus epsilon) using
> >> write(2)
> >> and truncate(2). Setting the atime to the current time should
> >> require
> >> no more and no less than read permission, since it can be done
> >> using
> >> read(2), but utimes(NULL) requires write permission for that too).
> >>
> > I did a quick test on a -current client/server and it seems to work
> > ok.
> > The client uses SET_TIME_TO_SERVER and the server sets
> > VA_UTIMES_NULL
> > for this case. At least it works for a UFS exported volume.
> 
> It's not working for me with newnfs from 4 Mar 2012:
> 
> $ mount | grep /c
> besplex:/c on /c (nfs, asynchronous)
> $ ls -l /c/tmp/z
> -rw-rw-rw- 1 root wheel 0 Jan 16 15:12 /c/tmp/z
> # Not even root owns it, since root on the client is mapped to
> 0xFFFFFFFFE.
> $ touch /c/tmp/z
> touch: /c/tmp/z: Operation not permitted
> $ touch -r . /c/tmp/z
> touch: /c/tmp/z: Operation not permitted
> touch: /c/tmp/z: Operation not permitted
> 
Well, I just ran essentially the same test, using the new client patched
with jhb@'s patch and an up to date server and I got the same behaviour
as when doing the touch locally on the file in the file system.
- when not the file owner, but having write permissions
  touch <file>   - worked for both local and NFS mount
  touch -r <other-file> <file>  - failed with Operation not permitted for
                                  both local and NFS mount

The test I had done before used a trivial program that just did a utimes(NULL)
and it worked as non-owner with write access, as well.

The server appears to have been patched for this at r157325 (Apr. 2006).

Maybe your server hasn't been patched for this?

rick

> The error message from touch are confusing. For plain touch:
> - it fails twice using utimes(), with errno EPERM and no error message
> - it then succeeds using read(), write() and truncate()
> - it then prints an error message
> - it then exits with status 0.
> This is with an old version of touch. It always prints an error
> message
> if it reaches the read()/write()/truncate() step (rw() function):
> - if rw() succeeded, then it prints an error message after the rw()
> returns. rw() fails to preserve errno, so the errno for this step
> is garbage, but it is usually the one from the second failing
> utimes().
> - if rw() fails, it prints an error message internally. The errno for
> this is now correct.
> The current version of touch is even more broken. Someone removed the
> rw() step from it, under the naive assumption that utimes() actually
> works.
> 
> For touch -r:
> - it fails twice using utimes(), with errno EPERM and no error
> message.
> Now even trying the second time (with utimes(NULL) is a bug. A
> comment says that there is nothing else that we can do in this case,
> but the code actually falls through and does something wrong (it
> tries to set to the current time instead of to the specified time).
> This bug fixed in the current version.
> - since it is not supposed to do anything more, it prints an error
> message
> after the first utimes() failure. It also sets rval to 1 to give an
> exit status of 1 later.
> - then it continues the same as for the plain touch case:
> - it then "succeeds" using read(), write() and truncate(), but this
> success is in clobbering the timestamps to the current time
> - it then prints an error message despite "succeeding"
> - it then exits with status 1.
> 
> The nfs error is just for the second utimes() in the plain touch case.
> This should succeed (it succeeds on a local ffs file system). Also,
> when
> it fails, the correct errno is EACCES, not EPERM. This works correctly
> after changing the file mode to readonly and using the buggy touch -r
> to reach the second utimes() -- the error is now EACCES for both nfs
> and local ffs. So it seems that the server ffs is being reached
> correctly, but the non-error case for utimes(NULL) is being mishandled
> somewhere. This is not due to some maproot magic, since the same error
> occurs for the non-error case when the ownership is changed to a mere
> user (!= the test user).
> 
> >> Oops, on looking at the code I now think it _is_ possible to pass
> >> the
> >> request to set the current time on the server, since in the
> >> NFSV3SATTRTIME_TOSERVER case we just pass this case value and not
> >> any time value to the server, so the server has no option but to
> >> use
> >> its current time. It is not surprising that the permissions checks
> >> for this don't work right. I thought that the client was
> >> responsible
> >> for most permissions checks, but can't find many or the relevant
> >> one
> >> here. The NFSV3SATTRTIME_TOSERVER code on the server sets
> >> VA_UTIMES_NULL, so I would have thought that the permissions check
> >> on
> >> the server does the right thing.
> >>
> > As noted above, it seems to work correctly for the new server in
> > -current,
> > at least for UFS exports.
> >
> > Normally a server will do permission checking for NFS RPCs. There is
> > nothing
> > stopping a client from doing a check and returning an error, but
> > traditionally
> > a server has not trusted a client to do so. (I'm not sure if adding
> > a check
> > in the client is what jhb@ was referring to in his reply to this?)
> 
> Checking in the client doesn't seem right now. The bug seems to be a
> different one on the server.
> 
> >> There are some large timestamping bugs nearby:
> >>
> >> - the old nfs server code for NFSV3SATTRTIME_TOSERVER uses
> >> getnanotime()
> >> to read the current time. This violates the system's policy set by
> >> the vfs.timestamp precision in most cases, since using
> >> getnanotime()
> >> is the worst supported policy and is not the defaul.
> >> ...
> >
> >> New nfs code never uses the correct function vfs_timestamp().
> > This needs to be fixed. Until now, I would have had no idea what is
> > the
> > correct interface. (When I did the port, I just used a call that
> > seemed
> > to return what I wanted.;-)
> >
> > Having said that, after reading what you wrote below, it is not
> > obvious
> > to me what the correct fix is? (It seems to be a choice between
> > microtime()
> > and vfs_timestamp()?)
> 
> Just use vfs_timestamp() whenever generating a file timestamp but not
> for
> other purposes. Like permissions checking, the client very rarely
> generates
> file timestamps, and even on the server most timestamps are not
> generated
> by nfs directly. So there are only a few places to check and change.
> We
> know about fifos and the utimes(NULL) case in the server (the latter
> is
> emulating upper layers in vfs) before calling VOP_SETATTR(). I wonder
> how well the fifo code works. Its timestamps aren't very important,
> but
> they should be synced to the server very occasionally.
> 
> Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1642392672.2036529.1358346406018.JavaMail.root>