Commit 9e1f1de02c2275d7172e18dc4e7c2065777611bf

Authored by Al Viro
1 parent 1fa7b6a29c

more conservative S_NOSEC handling

Caching "we have already removed suid/caps" was overenthusiastic as merged.
On network filesystems we might have had suid/caps set on another client,
silently picked by this client on revalidate, all of that *without* clearing
the S_NOSEC flag.

AFAICS, the only reasonably sane way to deal with that is
	* new superblock flag; unless set, S_NOSEC is not going to be set.
	* local block filesystems set it in their ->mount() (more accurately,
mount_bdev() does, so does btrfs ->mount(), users of mount_bdev() other than
local block ones clear it)
	* if any network filesystem (or a cluster one) wants to use S_NOSEC,
it'll need to set MS_NOSEC in sb->s_flags *AND* take care to clear S_NOSEC when
inode attribute changes are picked from other clients.

It's not an earth-shattering hole (anybody that can set suid on another client
will almost certainly be able to write to the file before doing that anyway),
but it's a bug that needs fixing.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 6 changed files with 8 additions and 5 deletions Side-by-side Diff

... ... @@ -819,7 +819,7 @@
819 819 } else {
820 820 char b[BDEVNAME_SIZE];
821 821  
822   - s->s_flags = flags;
  822 + s->s_flags = flags | MS_NOSEC;
823 823 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
824 824 error = btrfs_fill_super(s, fs_devices, data,
825 825 flags & MS_SILENT ? 1 : 0);
... ... @@ -921,6 +921,8 @@
921 921 if (sb->s_flags & MS_MANDLOCK)
922 922 goto err;
923 923  
  924 + sb->s_flags &= ~MS_NOSEC;
  925 +
924 926 if (!parse_fuse_opt((char *) data, &d, is_bdev))
925 927 goto err;
926 928  
... ... @@ -1072,7 +1072,7 @@
1072 1072  
1073 1073 sb->s_magic = OCFS2_SUPER_MAGIC;
1074 1074  
1075   - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
  1075 + sb->s_flags = (sb->s_flags & ~(MS_POSIXACL | MS_NOSEC)) |
1076 1076 ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
1077 1077  
1078 1078 /* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
... ... @@ -822,7 +822,7 @@
822 822 } else {
823 823 char b[BDEVNAME_SIZE];
824 824  
825   - s->s_flags = flags;
  825 + s->s_flags = flags | MS_NOSEC;
826 826 s->s_mode = mode;
827 827 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
828 828 sb_set_blocksize(s, block_size(bdev));
... ... @@ -208,6 +208,7 @@
208 208 #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */
209 209 #define MS_I_VERSION (1<<23) /* Update inode I_version field */
210 210 #define MS_STRICTATIME (1<<24) /* Always perform atime updates */
  211 +#define MS_NOSEC (1<<28)
211 212 #define MS_BORN (1<<29)
212 213 #define MS_ACTIVE (1<<30)
213 214 #define MS_NOUSER (1<<31)
... ... @@ -2591,7 +2592,7 @@
2591 2592  
2592 2593 static inline void inode_has_no_xattr(struct inode *inode)
2593 2594 {
2594   - if (!is_sxid(inode->i_mode))
  2595 + if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & MS_NOSEC))
2595 2596 inode->i_flags |= S_NOSEC;
2596 2597 }
2597 2598  
... ... @@ -2000,7 +2000,7 @@
2000 2000 error = security_inode_killpriv(dentry);
2001 2001 if (!error && killsuid)
2002 2002 error = __remove_suid(dentry, killsuid);
2003   - if (!error)
  2003 + if (!error && (inode->i_sb->s_flags & MS_NOSEC))
2004 2004 inode->i_flags |= S_NOSEC;
2005 2005  
2006 2006 return error;