Author: rmacklem
Date: Tue Feb 14 04:07:35 2012
New Revision: 231633
URL: http://svn.freebsd.org/changeset/base/231633

Log:
  MFC: r230801
  jwd@ reported a problem via email to freebsd-fs@ on Aug 25, 2011
  under the subject "F_RDLCK lock to FreeBSD NFS fails to R/O target file".
  This occurred because the server side NLM always checked for VWRITE
  access, irrespective of the type of lock request. This patch
  replaces VOP_ACCESS(..VWRITE..) with one appropriate to
  the lock operation. It allows unlock and lock cancellation
  to be done without a check of VOP_ACCESS(), so that files
  can't be left locked indefinitely after the file permissions
  have been changed.

Modified:
  stable/9/sys/nlm/nlm_prot_impl.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)

Modified: stable/9/sys/nlm/nlm_prot_impl.c
==============================================================================
--- stable/9/sys/nlm/nlm_prot_impl.c    Tue Feb 14 02:03:17 2012        
(r231632)
+++ stable/9/sys/nlm/nlm_prot_impl.c    Tue Feb 14 04:07:35 2012        
(r231633)
@@ -1774,10 +1774,10 @@ struct vfs_state {
 
 static int
 nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
-    fhandle_t *fhp, struct vfs_state *vs)
+    fhandle_t *fhp, struct vfs_state *vs, accmode_t accmode)
 {
        int error, exflags;
-       struct ucred *cred = NULL, *credanon;
+       struct ucred *cred = NULL, *credanon = NULL;
        
        memset(vs, 0, sizeof(*vs));
 
@@ -1787,14 +1787,19 @@ nlm_get_vfs_state(struct nlm_host *host,
        }
        vs->vs_vfslocked = VFS_LOCK_GIANT(vs->vs_mp);
 
-       error = VFS_CHECKEXP(vs->vs_mp, (struct sockaddr *)&host->nh_addr,
-           &exflags, &credanon, NULL, NULL);
-       if (error)
-               goto out;
+       /* accmode == 0 means don't check, since it is an unlock. */
+       if (accmode != 0) {
+               error = VFS_CHECKEXP(vs->vs_mp,
+                   (struct sockaddr *)&host->nh_addr, &exflags, &credanon,
+                   NULL, NULL);
+               if (error)
+                       goto out;
 
-       if (exflags & MNT_EXRDONLY || (vs->vs_mp->mnt_flag & MNT_RDONLY)) {
-               error = EROFS;
-               goto out;
+               if (exflags & MNT_EXRDONLY ||
+                   (vs->vs_mp->mnt_flag & MNT_RDONLY)) {
+                       error = EROFS;
+                       goto out;
+               }
        }
 
        error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, LK_EXCLUSIVE, &vs->vs_vp);
@@ -1802,22 +1807,31 @@ nlm_get_vfs_state(struct nlm_host *host,
                goto out;
        vs->vs_vnlocked = TRUE;
 
-       if (!svc_getcred(rqstp, &cred, NULL)) {
-               error = EINVAL;
-               goto out;
-       }
-       if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
-               crfree(cred);
-               cred = credanon;
-               credanon = NULL;
-       }
+       if (accmode != 0) {
+               if (!svc_getcred(rqstp, &cred, NULL)) {
+                       error = EINVAL;
+                       goto out;
+               }
+               if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
+                       crfree(cred);
+                       cred = credanon;
+                       credanon = NULL;
+               }
 
-       /*
-        * Check cred.
-        */
-       error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread);
-       if (error)
-               goto out;
+               /*
+                * Check cred.
+                */
+               error = VOP_ACCESS(vs->vs_vp, accmode, cred, curthread);
+               /*
+                * If this failed and accmode != VWRITE, try again with
+                * VWRITE to maintain backwards compatibility with the
+                * old code that always used VWRITE.
+                */
+               if (error != 0 && accmode != VWRITE)
+                       error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread);
+               if (error)
+                       goto out;
+       }
 
 #if __FreeBSD_version < 800011
        VOP_UNLOCK(vs->vs_vp, 0, curthread);
@@ -1871,6 +1885,7 @@ nlm_do_test(nlm4_testargs *argp, nlm4_te
        struct nlm_host *host, *bhost;
        int error, sysid;
        struct flock fl;
+       accmode_t accmode;
        
        memset(result, 0, sizeof(*result));
        memset(&vs, 0, sizeof(vs));
@@ -1896,7 +1911,8 @@ nlm_do_test(nlm4_testargs *argp, nlm4_te
                goto out;
        }
 
-       error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
+       accmode = argp->exclusive ? VWRITE : VREAD;
+       error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
        if (error) {
                result->stat.stat = nlm_convert_error(error);
                goto out;
@@ -1967,6 +1983,7 @@ nlm_do_lock(nlm4_lockargs *argp, nlm4_re
        struct nlm_host *host;
        int error, sysid;
        struct flock fl;
+       accmode_t accmode;
        
        memset(result, 0, sizeof(*result));
        memset(&vs, 0, sizeof(vs));
@@ -2001,7 +2018,8 @@ nlm_do_lock(nlm4_lockargs *argp, nlm4_re
                goto out;
        }
 
-       error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
+       accmode = argp->exclusive ? VWRITE : VREAD;
+       error = nlm_get_vfs_state(host, rqstp, &fh, &vs, accmode);
        if (error) {
                result->stat.stat = nlm_convert_error(error);
                goto out;
@@ -2180,7 +2198,7 @@ nlm_do_cancel(nlm4_cancargs *argp, nlm4_
                goto out;
        }
 
-       error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
+       error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
        if (error) {
                result->stat.stat = nlm_convert_error(error);
                goto out;
@@ -2269,7 +2287,7 @@ nlm_do_unlock(nlm4_unlockargs *argp, nlm
                goto out;
        }
 
-       error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
+       error = nlm_get_vfs_state(host, rqstp, &fh, &vs, (accmode_t)0);
        if (error) {
                result->stat.stat = nlm_convert_error(error);
                goto out;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to