When a Remote Procedure Call arrives with a file handle (or possibly
two file handles) in it, the file handle needs to be converted to a
dentry (the Linux internal representation of a filesystem
object), and this dentry must be checked to see if the required access
is permitted. This checking is performed by nfsfh.c::fh_verify.
Then the file handle arrives, nfsxdr.c::decode_fh copies it in to
a struct svc_fh structure which has been zeroed by
nfsffh.h::fh_init.
The svc_fh structure was described earlier in the section on
Using the File Handle.
The process of verification proceeds as follows:
fh_dev is that same
as fh_xdev. If it isn't a warning is printed and a ESTALE error
is returned. This is simply a consistency check. The code could
equally well simply ignore the value in fh_xdev (as it ignores
many other bytes in the file handle) and copy fh_dev into
fh_xdev for other sections of code to use.
fh_xdev, fh_xino) is
looked up in the export table (with export.c::exp_get) to find
out how, and whether, this file tree is currently exported. If there
is no export entry, then the file handle is rejected with
ESTALE.
There are enhancements being worked on (September 1999) to allow knfsd
to call-back to a userlevel process (such as mountd) to ask that
and appropriate entry be inserted into the table --- possible and
entry denying access.
EPERM and a warning is printed.
dentry by
find_fh_dentry. If the export point has the SUBTREECHECK
flag set, then find_fh_dentry must find a dentry which is
properly located in the file hierarchy . If not, and the file handle
does not refer to a directory, then it is allowed to return a "root"
dentry that simply refers to the appropriate inode.
If an appropriate dentry cannot be found, then the file handle is
rejected, possibly with ESTALE, or ENOENT if a location could not be
found in the tree. (Maybe it should always return ESTALE?)
find_fh_dentry as if the generation number doesn't match then it
isn't the right dentry. This is more of aesthetic than practical
significance.
fh_verify is called, the called may indicate that a
particular type of object is required, possibly a directory, or a file
or a symbolic link.
If a type was specified then the next check is to make sure that the
inode that was found has the right type. If the inode has the wrong
type, then either ENOTDIR or EISDIR is returned depending on whether a
diretory was asked for or not.
SUBTREECHECK flag set.
The sub-tree check involves walking up the dcache tree from the
dentry that was found until we find the dentry for the export point.
If the root of the filesystem is found before finding the export
point, then the dentry found is clearly not in the exported tree, and
so the filehandle is rejected with ESTALE.
While the the tree is being walked another check is made. If the
filesystem is exported ROOTSQUASH then every directory in the path
must give execute access to someone other than root/wheel ???
fh_verify is to call
vfs.c::nfsd_permission.
This checks the access type that was requested in various ways as the
following points outline.
However it first checks if the dentry was mounted on. In this case (if
it is compiled with CONFIG_NFSD_SUN) the filehandle is rejected with
EPERM.
nfsd_iscovered,
however nfsd_iscovered is equivalent to false. See Below.
vfs.c::nfsd_open rejects all read/write access to
IS_APPEND files.
permission routine is called to do normal
access checking. As a special case, read-only requests on a regular
file are allowed to if read OR exec access is available. This allow
executables to be loaded (NFS does not distinguish between loading a
file to read it and loading a file to execute it).
knfsd has a number of other bits of permission checking code
distributed in various places which are worth mentioning.
This function is called from a number of places in vfs.c,
including once in nfsd_permission as mentioned above. In apparent
contradiction to it's name, this routine seems to check if a given
dentry "covers" (i.e. is mounted on) some other dentry. However
it allows through the export point. As linux only allows the root of
a filesystem to cover anything, this function could only return true
for the root of a filesystem, but when given a dentry which is the
root of a filesystem, the export point will be that same root, and so
nfsd_iscovered will still return false.
I am not sure what the intent of this routine is.
The vfs.c:fs_off_limits function rejects any filesystem which is
either an NFS filesystem or a PROC filesystem, as exporting these is a
bad idea for different reasons.
It is called in nfsd_lookup to make sure that the parent dentry
is not on an off-limits file system.
It would seem to make more sense to perform this test in
fh_verify so that those file systems were equally rejected for
all accessed. Further, a more general test would be to reject any
filesystem without the FS_REQUIRES_DEV flag, as this coverred the
two in question and any such filesystem does not have a reliably
stable device number, and so (current) filehandles wouldn't be
guaranteed to remain meaningful across reboots.
Some NFS clients (apparently) try to use the setattr request to
update the access and modify times on a file to the current time.
This should be allowed for any client which has write access to the
file (whereas normally seting these times is restricted to the owner).
nfsd_setattr makes a special case of allowing such a request
through providing that the requested time is "close enough" to the
current time on the server. "Close enough" is a configurable value set
via the /proc/fs/nfs/time-diff-margin file.
This configuation should probably go somewhere in /proc/sys
to meet current (apparent) standards, though where isn't clear.