Fix permissions check for utimes() - owner can call even if u-w.
authorMatt Dillon <dillon@test29.backplane.com>
Thu, 2 Apr 2009 03:56:49 +0000 (03:56 +0000)
committerMatt Dillon <dillon@test29.backplane.com>
Thu, 2 Apr 2009 03:56:49 +0000 (03:56 +0000)
The owner of a file can call utimes() to modify the file's access and
modified times even if the file is not user-writable.  Add a VOWN test
for VOP_ACCESS() / naccess() which performs this check.

As far as I know only kern_utimes() needs to use this particular type
of test.

This also fixes issues with cp -p and a few other programs.

Reported-by: Johannes Hofmann <johannes.hofmann@gmx.de>
12 files changed:
sys/kern/vfs_helper.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_syscalls.c
sys/sys/vnode.h
sys/vfs/gnu/ext2fs/ext2_vnops.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ufs_vnops.c

index 531fd3e..0ea69e5 100644 (file)
@@ -110,6 +110,8 @@ vop_helper_access(struct vop_access_args *ap, uid_t ino_uid, gid_t ino_gid,
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ino_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 3bc8bab..967ad65 100644 (file)
@@ -803,13 +803,15 @@ naccess_va(struct vattr *va, int vmode, struct ucred *cred)
     /*
      * Check owner perms, group perms, and world perms
      */
-    vmode &= S_IRWXU;
     if (cred->cr_uid == va->va_uid) {
-       if ((vmode & va->va_mode) != vmode)
-           return(EACCES);
+       if ((vmode & VOWN) == 0) {
+           vmode &= S_IRWXU;
+           if ((vmode & va->va_mode) != vmode)
+               return(EACCES);
+       }
        return(0);
     }
-
+    vmode &= S_IRWXU;
     vmode >>= 3;
     for (i = 0; i < cred->cr_ngroups; ++i) {
        if (va->va_gid == cred->cr_groups[i]) {
index d174c9a..b5888cf 100644 (file)
@@ -2888,8 +2888,13 @@ kern_utimes(struct nlookupdata *nd, struct timeval *tptr)
                return (error);
        if ((error = cache_vref(&nd->nl_nch, nd->nl_cred, &vp)) != 0)
                return (error);
+
+       /*
+        * NOTE: utimes() succeeds for the owner even if the file
+        * is not user-writable.
+        */
        if ((error = vn_writechk(vp, &nd->nl_nch)) == 0 &&
-           (error = VOP_ACCESS(vp, VWRITE, nd->nl_cred)) == 0) {
+           (error = VOP_ACCESS(vp, VWRITE | VOWN, nd->nl_cred)) == 0) {
                error = setutimes(vp, ts, tptr == NULL);
        }
        vrele(vp);
index 70c7ac4..d12a042 100644 (file)
@@ -315,8 +315,9 @@ struct vnode {
  * Modes.  Note that these V-modes must match file S_I*USR, SUID, SGID,
  * and SVTX flag bits.
  *
- * VCREATE, VDELETE, and VEXCL may only be used in naccess() calls.
+ * VOWN, VCREATE, VDELETE, and VEXCL may only be used in naccess() calls.
  */
+#define VOWN   0100000         /* succeed if file owner or (other flags) */
 #define VDELETE        040000          /* delete if the file/dir exists */
 #define VCREATE        020000          /* create if the file/dir does not exist */
 #define VEXCL  010000          /* error if the file/dir already exists */
index 3b79b1d..8f07518 100644 (file)
@@ -1380,6 +1380,8 @@ ext2_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 08469b6..181c9e5 100644 (file)
@@ -750,6 +750,8 @@ hpfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == hp->h_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index db0296e..bb660ce 100644 (file)
@@ -280,6 +280,8 @@ msdosfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == pmp->pm_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index af1a2d1..c1246fe 100644 (file)
@@ -460,6 +460,8 @@ ntfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_mp->ntm_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 3fc5417..2514d12 100644 (file)
@@ -145,6 +145,8 @@ nwfs_access(struct vop_access_args *ap)
                mode >>= 3;
                if (!groupmember(nmp->m.gid, cred))
                        mode >>= 3;
+       } else if (mode & VOWN) {
+               return (0);
        }
        error = (((vp->v_type == VREG) ? nmp->m.file_mode : nmp->m.dir_mode) & mode) == mode ? 0 : EACCES;
        return error;
index e3a5068..eab915b 100644 (file)
@@ -148,6 +148,8 @@ smbfs_access(struct vop_access_args *ap)
                mode >>= 3;
                if (!groupmember(smp->sm_args.gid, cred))
                        mode >>= 3;
+       } else if (mode & VOWN) {
+               return (0);
        }
        error = (((vp->v_type == VREG) ? smp->sm_args.file_mode : smp->sm_args.dir_mode) & mode) == mode ? 0 : EACCES;
        return error;
index dc9e49c..d358741 100644 (file)
@@ -240,6 +240,8 @@ udf_access(struct vop_access_args *a)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == node->fentry->uid) {
+               if (a_mode & VOWN)
+                       return (0);
                if (a_mode & VEXEC)
                        mask |= S_IXUSR;
                if (a_mode & VREAD)
index dfdf1ea..bb0ef4f 100644 (file)
@@ -361,6 +361,8 @@ ufs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_uid) {
+               if (mode & VOWN)
+                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)