add patch fix-block_validity-documentation
[ext4-patch-queue.git] / be-more-strict-when-verifying-flags-set-via-SETFLAGS-ioctls
blob1001391fdfc1ef6e9ee2c28f8338925a79dd3962
1 ext4: be more strict when verifying flags set via SETFLAGS ioctls
3 From: Jan Kara <jack@suse.cz>
5 Currently we just silently ignore flags that we don't understand (or
6 that cannot be manipulated) through EXT4_IOC_SETFLAGS and
7 EXT4_IOC_FSSETXATTR ioctls. This makes it problematic for the unused
8 flags to be used in future (some app may be inadvertedly setting them
9 and we won't notice until the flag gets used). Also this is inconsistent
10 with other filesystems like XFS or BTRFS which return EOPNOTSUPP when
11 they see a flag they cannot set.
13 ext4 has the additional problem that there are flags which are returned
14 by EXT4_IOC_GETFLAGS ioctl but which cannot be modified via
15 EXT4_IOC_SETFLAGS. So we have to be careful to ignore value of these
16 flags and not fail the ioctl when they are set (as e.g. chattr(1) passes
17 flags returned from EXT4_IOC_GETFLAGS to EXT4_IOC_SETFLAGS without any
18 masking and thus we'd break this utility).
20 Signed-off-by: Jan Kara <jack@suse.cz>
21 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
22 ---
23  fs/ext4/ext4.h  |  1 +
24  fs/ext4/ioctl.c | 28 +++++++++++++++++++++++-----
25  2 files changed, 24 insertions(+), 5 deletions(-)
27 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
28 index 0814c9570bf1..2874957e3ee2 100644
29 --- a/fs/ext4/ext4.h
30 +++ b/fs/ext4/ext4.h
31 @@ -395,6 +395,7 @@ struct flex_groups {
32  #define EXT4_FL_USER_VISIBLE           0x304BDFFF /* User visible flags */
33  #define EXT4_FL_USER_MODIFIABLE                0x204BC0FF /* User modifiable flags */
35 +/* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
36  #define EXT4_FL_XFLAG_VISIBLE          (EXT4_SYNC_FL | \
37                                          EXT4_IMMUTABLE_FL | \
38                                          EXT4_APPEND_FL | \
39 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
40 index e9433c155454..33af924fa7c4 100644
41 --- a/fs/ext4/ioctl.c
42 +++ b/fs/ext4/ioctl.c
43 @@ -415,6 +415,10 @@ static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
44         return xflags;
45  }
47 +#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
48 +                                 FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
49 +                                 FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT)
51  /* Transfer xflags flags to internal */
52  static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
53  {
54 @@ -459,12 +463,22 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
55                 if (get_user(flags, (int __user *) arg))
56                         return -EFAULT;
58 +               if (flags & ~EXT4_FL_USER_VISIBLE)
59 +                       return -EOPNOTSUPP;
60 +               /*
61 +                * chattr(1) grabs flags via GETFLAGS, modifies the result and
62 +                * passes that to SETFLAGS. So we cannot easily make SETFLAGS
63 +                * more restrictive than just silently masking off visible but
64 +                * not settable flags as we always did.
65 +                */
66 +               flags &= EXT4_FL_USER_MODIFIABLE;
67 +               if (ext4_mask_flags(inode->i_mode, flags) != flags)
68 +                       return -EOPNOTSUPP;
70                 err = mnt_want_write_file(filp);
71                 if (err)
72                         return err;
74 -               flags = ext4_mask_flags(inode->i_mode, flags);
76                 inode_lock(inode);
77                 err = ext4_ioctl_setflags(inode, flags);
78                 inode_unlock(inode);
79 @@ -869,13 +883,17 @@ resizefs_out:
80                 if (!inode_owner_or_capable(inode))
81                         return -EACCES;
83 +               if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
84 +                       return -EOPNOTSUPP;
86 +               flags = ext4_xflags_to_iflags(fa.fsx_xflags);
87 +               if (ext4_mask_flags(inode->i_mode, flags) != flags)
88 +                       return -EOPNOTSUPP;
90                 err = mnt_want_write_file(filp);
91                 if (err)
92                         return err;
94 -               flags = ext4_xflags_to_iflags(fa.fsx_xflags);
95 -               flags = ext4_mask_flags(inode->i_mode, flags);
97                 inode_lock(inode);
98                 flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
99                          (flags & EXT4_FL_XFLAG_VISIBLE);
100 -- 
101 2.6.6