nfsd: Make creates return EEXIST instead of EACCES
authorOleg Drokin <green@linuxhacker.ru>
Fri, 15 Jul 2016 03:20:22 +0000 (23:20 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Thu, 4 Aug 2016 21:11:46 +0000 (17:11 -0400)
When doing a create (mkdir/mknod) on a name, it's worth
checking the name exists first before returning EACCES in case
the directory is not writeable by the user.
This makes return values on the client more consistent
regardless of whenever the entry there is cached in the local
cache or not.
Another positive side effect is certain programs only expect
EEXIST in that case even despite POSIX allowing any valid
error to be returned.

Signed-off-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4proc.c
fs/nfsd/vfs.c

index e0c15f879d8953f895fb5728cd404940659d49a5..9d7e1edf0cca33d74b829300791fbd0278a34671 100644 (file)
@@ -605,8 +605,12 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        fh_init(&resfh, NFS4_FHSIZE);
 
+       /*
+        * We just check that parent is accessible here, nfsd_* do their
+        * own access permission checks
+        */
        status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
-                          NFSD_MAY_CREATE);
+                          NFSD_MAY_EXEC);
        if (status)
                return status;
 
index 6fbd81ecb41080a6e81aa712fc45af77c3a4fde1..fda4f86161f8cbcd5a479e1e134e455d2d1aafac 100644 (file)
@@ -1161,7 +1161,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (isdotent(fname, flen))
                goto out;
 
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+       /*
+        * Even though it is a create, first let's see if we are even allowed
+        * to peek inside the parent
+        */
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
        if (err)
                goto out;
 
@@ -1211,6 +1215,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                goto out; 
        }
 
+       /* Now let's see if we actually have permissions to create */
+       err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
+       if (err)
+               goto out;
+
        if (!(iap->ia_valid & ATTR_MODE))
                iap->ia_mode = 0;
        iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;