Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check
authorSatyam Sharma <ssatyam@cse.iitk.ac.in>
Tue, 17 Jul 2007 09:30:08 +0000 (15:00 +0530)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 17 Jul 2007 19:00:03 +0000 (12:00 -0700)
Introduce is_owner_or_cap() macro in fs.h, and convert over relevant
users to it. This is done because we want to avoid bugs in the future
where we check for only effective fsuid of the current task against a
file's owning uid, without simultaneously checking for CAP_FOWNER as
well, thus violating its semantics.
[ XFS uses special macros and structures, and in general looked ...
untouchable, so we leave it alone -- but it has been looked over. ]

The (current->fsuid != inode->i_uid) check in generic_permission() and
exec_permission_lite() is left alone, because those operations are
covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH. Similarly operations
falling under the purview of CAP_CHOWN and CAP_LEASE are also left alone.

Signed-off-by: Satyam Sharma <ssatyam@cse.iitk.ac.in>
Cc: Al Viro <viro@ftp.linux.org.uk>
Acked-by: Serge E. Hallyn <serge@hallyn.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
22 files changed:
fs/attr.c
fs/ext2/acl.c
fs/ext2/ioctl.c
fs/ext3/acl.c
fs/ext3/ioctl.c
fs/ext4/acl.c
fs/ext4/ioctl.c
fs/fcntl.c
fs/generic_acl.c
fs/gfs2/acl.c
fs/hfsplus/ioctl.c
fs/jffs2/acl.c
fs/jfs/ioctl.c
fs/jfs/xattr.c
fs/namei.c
fs/ocfs2/ioctl.c
fs/reiserfs/ioctl.c
fs/reiserfs/xattr_acl.c
fs/utimes.c
fs/xattr.c
include/linux/fs.h
security/selinux/hooks.c

index a0a0c7b07ba3908379d311931254cc5ba9b2d014..f8dfc2269d85634aa61ebb19a761e986ea0bbc93 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -42,7 +42,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        goto error;
                /* Also check the setgid bit! */
                if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
@@ -52,7 +52,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 
        /* Check for setting the inode time. */
        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        goto error;
        }
 fine:
index 7c420b800c3438fd02ab669368f48fb9a6f01c5a..e58669e1b87c6bab0e0a0ac8677713b5b2f3fbb8 100644 (file)
@@ -464,7 +464,7 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index e85c48218239b604948bfad7f41889df2dfbba1e..3bcd25422ee4879781a2785ec92a0f512e0c2567 100644 (file)
@@ -36,7 +36,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
        case EXT2_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *) arg);
        case EXT2_IOC_SETVERSION:
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
index 1e5038d9a01b9f469015b83f8ee7eb07a9abf8f8..d34e9967430a5ff28bebf278faef1882e188252f 100644 (file)
@@ -489,7 +489,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 965006dba6be8d22715dff9f52c2c5038c072c01..4a2a02c95bf94b98fc4534d870f3546a45442c8e 100644 (file)
@@ -41,7 +41,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -122,7 +122,7 @@ flags_err:
                __u32 generation;
                int err;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
@@ -181,7 +181,7 @@ flags_err:
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(rsv_window_size, (int __user *)arg))
index 9e882546d91a098a01b409301f9baa2e00d4fce1..a8bae8cd1d5de707c9a8772464ca4ecaa93044ed 100644 (file)
@@ -489,7 +489,7 @@ ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
 
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 500567dd53b6fd9752096c014162927a730748f0..7b4aa4543c833b6f9b1e0f5eb3db5acafbaa8bdc 100644 (file)
@@ -40,7 +40,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -121,7 +121,7 @@ flags_err:
                __u32 generation;
                int err;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
@@ -180,7 +180,7 @@ flags_err:
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(rsv_window_size, (int __user *)arg))
index 8e382a5d51bd6f757bd694344465de0711d4afb2..3f22e9f4f691ae3cb44312921c0aaf3a6b382086 100644 (file)
@@ -215,7 +215,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 
        /* O_NOATIME can only be set by the owner or superuser */
        if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
 
        /* required for strict SunOS emulation */
index 9ccb789471713dc94a6768c4cd459bf973166ee3..995d63b2e747556c879c52be194375196995b58a 100644 (file)
@@ -78,7 +78,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
-       if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
        if (value) {
                acl = posix_acl_from_xattr(value, size);
index 6e80844367ee9b5edd81143bc659ab14834809a5..1047a8c7226afb56c8a13c5493c2ac66de741cbb 100644 (file)
@@ -74,7 +74,7 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
 {
        if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
                return -EOPNOTSUPP;
-       if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(&ip->i_inode))
                return -EPERM;
        if (S_ISLNK(ip->i_inode.i_mode))
                return -EOPNOTSUPP;
index 79fd10402ea3479d3aaad8b7f6b780fa6a362216..b60c0affbec58af68e45fd063692a933949ad457 100644 (file)
@@ -38,7 +38,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *)arg))
index a46101ee867afa22e5ee94f8161610433fffc00f..65b3a1b5b88dd0fc009ee4fc425f65d1ceda803e 100644 (file)
@@ -435,7 +435,7 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value,
        struct posix_acl *acl;
        int rc;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index fe063af6fd2fb216538d6c4bb0cc82e7ba024d2a..3c8663bea98ca3bf373f3ea83260b33d67548f3a 100644 (file)
@@ -69,7 +69,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
index b2375f0774b72c89cb602358735a0fed289206f7..9b7f2cdaae0a6655538066e104bff5e10bbcab70 100644 (file)
@@ -697,7 +697,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
        struct posix_acl *acl;
        int rc;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        /*
index 5e2d98d10c5d79220a7daa95be76a8ac0616df93..defaa47c11d4e7a1de0d926bc659fd8a03df2d27 100644 (file)
@@ -1576,7 +1576,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
 
        /* O_NOATIME can only be set by the owner or superuser */
        if (flag & O_NOATIME)
-               if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
 
        /*
index bd68c3f2afbeab67a05c32eda336266db7cd7406..87dcece7e1b5cc1d0439da96c7fffe5199af1311 100644 (file)
@@ -63,7 +63,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
                goto bail_unlock;
 
        status = -EACCES;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                goto bail_unlock;
 
        if (!S_ISDIR(inode->i_mode))
index b484d2913c0dc18389fe242fd9c1568d578dd82f..11a0fcc2d402c23ec2c426c00d4181ee89188bb3 100644 (file)
@@ -51,8 +51,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        if (IS_RDONLY(inode))
                                return -EROFS;
 
-                       if ((current->fsuid != inode->i_uid)
-                           && !capable(CAP_FOWNER))
+                       if (!is_owner_or_cap(inode))
                                return -EPERM;
 
                        if (get_user(flags, (int __user *)arg))
@@ -81,7 +80,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        case REISERFS_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *)arg);
        case REISERFS_IOC_SETVERSION:
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               if (!is_owner_or_cap(inode))
                        return -EPERM;
                if (IS_RDONLY(inode))
                        return -EROFS;
index 5296a29cc5eb51779169525a149a98b3206ed0ad..b7e4fa4539deeb9155e97affef199cbacb729f70 100644 (file)
@@ -21,7 +21,7 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
 
        if (!reiserfs_posixacl(inode->i_sb))
                return -EOPNOTSUPP;
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        if (value) {
index 83a7e69e706caeaf576616eeae53d6d5bcfadac6..682eb63b20ad3c4c7452870c3d9e6e832aea21e0 100644 (file)
@@ -106,7 +106,7 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
                 if (IS_IMMUTABLE(inode))
                         goto dput_and_out;
 
-               if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) {
+               if (!is_owner_or_cap(inode)) {
                        if (f) {
                                if (!(f->f_mode & FMODE_WRITE))
                                        goto dput_and_out;
index 4523aca79659c24f5d2ca3b8ee415ddd9588b73f..a44fd92caca31c72aba82e61ec6b321d7ebf5a7d 100644 (file)
@@ -60,8 +60,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
                if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
                        return -EPERM;
                if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
-                   (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) &&
-                   !capable(CAP_FOWNER))
+                   (mask & MAY_WRITE) && !is_owner_or_cap(inode))
                        return -EPERM;
        }
 
index 58ce336d4a6b1c36fec8debf8f962cb10d1ccae9..98205f680476c2b3e94c8b47e4078d0eb5bd579e 100644 (file)
@@ -284,6 +284,7 @@ extern int dir_notify_enable;
 #include <linux/pid.h>
 #include <linux/mutex.h>
 #include <linux/sysctl.h>
+#include <linux/capability.h>
 
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -990,6 +991,9 @@ enum {
 #define put_fs_excl() atomic_dec(&current->fs_excl)
 #define has_fs_excl() atomic_read(&current->fs_excl)
 
+#define is_owner_or_cap(inode) \
+       ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
+
 /* not quite ready to be deprecated, but... */
 extern void lock_super(struct super_block *);
 extern void unlock_super(struct super_block *);
index 78c3f98fcdcfa94b2bf72a2bbcc7158b11756eba..520b9998123efa9a65f41f665105aaaada6d47d7 100644 (file)
@@ -2318,7 +2318,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
        if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
-       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!is_owner_or_cap(inode))
                return -EPERM;
 
        AVC_AUDIT_DATA_INIT(&ad,FS);