Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check

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>

authored by

Satyam Sharma and committed by
Linus Torvalds
3bd858ab 49c13b51

+32 -30
+2 -2
fs/attr.c
··· 42 42 43 43 /* Make sure a caller can chmod. */ 44 44 if (ia_valid & ATTR_MODE) { 45 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 45 + if (!is_owner_or_cap(inode)) 46 46 goto error; 47 47 /* Also check the setgid bit! */ 48 48 if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : ··· 52 52 53 53 /* Check for setting the inode time. */ 54 54 if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { 55 - if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) 55 + if (!is_owner_or_cap(inode)) 56 56 goto error; 57 57 } 58 58 fine:
+1 -1
fs/ext2/acl.c
··· 464 464 465 465 if (!test_opt(inode->i_sb, POSIX_ACL)) 466 466 return -EOPNOTSUPP; 467 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 467 + if (!is_owner_or_cap(inode)) 468 468 return -EPERM; 469 469 470 470 if (value) {
+2 -2
fs/ext2/ioctl.c
··· 36 36 if (IS_RDONLY(inode)) 37 37 return -EROFS; 38 38 39 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 39 + if (!is_owner_or_cap(inode)) 40 40 return -EACCES; 41 41 42 42 if (get_user(flags, (int __user *) arg)) ··· 74 74 case EXT2_IOC_GETVERSION: 75 75 return put_user(inode->i_generation, (int __user *) arg); 76 76 case EXT2_IOC_SETVERSION: 77 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 77 + if (!is_owner_or_cap(inode)) 78 78 return -EPERM; 79 79 if (IS_RDONLY(inode)) 80 80 return -EROFS;
+1 -1
fs/ext3/acl.c
··· 489 489 490 490 if (!test_opt(inode->i_sb, POSIX_ACL)) 491 491 return -EOPNOTSUPP; 492 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 492 + if (!is_owner_or_cap(inode)) 493 493 return -EPERM; 494 494 495 495 if (value) {
+3 -3
fs/ext3/ioctl.c
··· 41 41 if (IS_RDONLY(inode)) 42 42 return -EROFS; 43 43 44 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 44 + if (!is_owner_or_cap(inode)) 45 45 return -EACCES; 46 46 47 47 if (get_user(flags, (int __user *) arg)) ··· 122 122 __u32 generation; 123 123 int err; 124 124 125 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 125 + if (!is_owner_or_cap(inode)) 126 126 return -EPERM; 127 127 if (IS_RDONLY(inode)) 128 128 return -EROFS; ··· 181 181 if (IS_RDONLY(inode)) 182 182 return -EROFS; 183 183 184 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 184 + if (!is_owner_or_cap(inode)) 185 185 return -EACCES; 186 186 187 187 if (get_user(rsv_window_size, (int __user *)arg))
+1 -1
fs/ext4/acl.c
··· 489 489 490 490 if (!test_opt(inode->i_sb, POSIX_ACL)) 491 491 return -EOPNOTSUPP; 492 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 492 + if (!is_owner_or_cap(inode)) 493 493 return -EPERM; 494 494 495 495 if (value) {
+3 -3
fs/ext4/ioctl.c
··· 40 40 if (IS_RDONLY(inode)) 41 41 return -EROFS; 42 42 43 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 43 + if (!is_owner_or_cap(inode)) 44 44 return -EACCES; 45 45 46 46 if (get_user(flags, (int __user *) arg)) ··· 121 121 __u32 generation; 122 122 int err; 123 123 124 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 124 + if (!is_owner_or_cap(inode)) 125 125 return -EPERM; 126 126 if (IS_RDONLY(inode)) 127 127 return -EROFS; ··· 180 180 if (IS_RDONLY(inode)) 181 181 return -EROFS; 182 182 183 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 183 + if (!is_owner_or_cap(inode)) 184 184 return -EACCES; 185 185 186 186 if (get_user(rsv_window_size, (int __user *)arg))
+1 -1
fs/fcntl.c
··· 215 215 216 216 /* O_NOATIME can only be set by the owner or superuser */ 217 217 if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) 218 - if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) 218 + if (!is_owner_or_cap(inode)) 219 219 return -EPERM; 220 220 221 221 /* required for strict SunOS emulation */
+1 -1
fs/generic_acl.c
··· 78 78 79 79 if (S_ISLNK(inode->i_mode)) 80 80 return -EOPNOTSUPP; 81 - if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) 81 + if (!is_owner_or_cap(inode)) 82 82 return -EPERM; 83 83 if (value) { 84 84 acl = posix_acl_from_xattr(value, size);
+1 -1
fs/gfs2/acl.c
··· 74 74 { 75 75 if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) 76 76 return -EOPNOTSUPP; 77 - if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER)) 77 + if (!is_owner_or_cap(&ip->i_inode)) 78 78 return -EPERM; 79 79 if (S_ISLNK(ip->i_inode.i_mode)) 80 80 return -EOPNOTSUPP;
+1 -1
fs/hfsplus/ioctl.c
··· 38 38 if (IS_RDONLY(inode)) 39 39 return -EROFS; 40 40 41 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 41 + if (!is_owner_or_cap(inode)) 42 42 return -EACCES; 43 43 44 44 if (get_user(flags, (int __user *)arg))
+1 -1
fs/jffs2/acl.c
··· 435 435 struct posix_acl *acl; 436 436 int rc; 437 437 438 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 438 + if (!is_owner_or_cap(inode)) 439 439 return -EPERM; 440 440 441 441 if (value) {
+1 -1
fs/jfs/ioctl.c
··· 69 69 if (IS_RDONLY(inode)) 70 70 return -EROFS; 71 71 72 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 72 + if (!is_owner_or_cap(inode)) 73 73 return -EACCES; 74 74 75 75 if (get_user(flags, (int __user *) arg))
+1 -1
fs/jfs/xattr.c
··· 697 697 struct posix_acl *acl; 698 698 int rc; 699 699 700 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 700 + if (!is_owner_or_cap(inode)) 701 701 return -EPERM; 702 702 703 703 /*
+1 -1
fs/namei.c
··· 1576 1576 1577 1577 /* O_NOATIME can only be set by the owner or superuser */ 1578 1578 if (flag & O_NOATIME) 1579 - if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) 1579 + if (!is_owner_or_cap(inode)) 1580 1580 return -EPERM; 1581 1581 1582 1582 /*
+1 -1
fs/ocfs2/ioctl.c
··· 63 63 goto bail_unlock; 64 64 65 65 status = -EACCES; 66 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 66 + if (!is_owner_or_cap(inode)) 67 67 goto bail_unlock; 68 68 69 69 if (!S_ISDIR(inode->i_mode))
+2 -3
fs/reiserfs/ioctl.c
··· 51 51 if (IS_RDONLY(inode)) 52 52 return -EROFS; 53 53 54 - if ((current->fsuid != inode->i_uid) 55 - && !capable(CAP_FOWNER)) 54 + if (!is_owner_or_cap(inode)) 56 55 return -EPERM; 57 56 58 57 if (get_user(flags, (int __user *)arg)) ··· 80 81 case REISERFS_IOC_GETVERSION: 81 82 return put_user(inode->i_generation, (int __user *)arg); 82 83 case REISERFS_IOC_SETVERSION: 83 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 84 + if (!is_owner_or_cap(inode)) 84 85 return -EPERM; 85 86 if (IS_RDONLY(inode)) 86 87 return -EROFS;
+1 -1
fs/reiserfs/xattr_acl.c
··· 21 21 22 22 if (!reiserfs_posixacl(inode->i_sb)) 23 23 return -EOPNOTSUPP; 24 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 24 + if (!is_owner_or_cap(inode)) 25 25 return -EPERM; 26 26 27 27 if (value) {
+1 -1
fs/utimes.c
··· 106 106 if (IS_IMMUTABLE(inode)) 107 107 goto dput_and_out; 108 108 109 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) { 109 + if (!is_owner_or_cap(inode)) { 110 110 if (f) { 111 111 if (!(f->f_mode & FMODE_WRITE)) 112 112 goto dput_and_out;
+1 -2
fs/xattr.c
··· 60 60 if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) 61 61 return -EPERM; 62 62 if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && 63 - (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) && 64 - !capable(CAP_FOWNER)) 63 + (mask & MAY_WRITE) && !is_owner_or_cap(inode)) 65 64 return -EPERM; 66 65 } 67 66
+4
include/linux/fs.h
··· 284 284 #include <linux/pid.h> 285 285 #include <linux/mutex.h> 286 286 #include <linux/sysctl.h> 287 + #include <linux/capability.h> 287 288 288 289 #include <asm/atomic.h> 289 290 #include <asm/semaphore.h> ··· 990 989 #define get_fs_excl() atomic_inc(&current->fs_excl) 991 990 #define put_fs_excl() atomic_dec(&current->fs_excl) 992 991 #define has_fs_excl() atomic_read(&current->fs_excl) 992 + 993 + #define is_owner_or_cap(inode) \ 994 + ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER)) 993 995 994 996 /* not quite ready to be deprecated, but... */ 995 997 extern void lock_super(struct super_block *);
+1 -1
security/selinux/hooks.c
··· 2318 2318 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) 2319 2319 return -EOPNOTSUPP; 2320 2320 2321 - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 2321 + if (!is_owner_or_cap(inode)) 2322 2322 return -EPERM; 2323 2323 2324 2324 AVC_AUDIT_DATA_INIT(&ad,FS);