Skip to content

Commit d14e768

Browse files
jankaratytso
authored andcommitted
ext4: be more strict when verifying flags set via SETFLAGS ioctls
Currently we just silently ignore flags that we don't understand (or that cannot be manipulated) through EXT4_IOC_SETFLAGS and EXT4_IOC_FSSETXATTR ioctls. This makes it problematic for the unused flags to be used in future (some app may be inadvertedly setting them and we won't notice until the flag gets used). Also this is inconsistent with other filesystems like XFS or BTRFS which return EOPNOTSUPP when they see a flag they cannot set. ext4 has the additional problem that there are flags which are returned by EXT4_IOC_GETFLAGS ioctl but which cannot be modified via EXT4_IOC_SETFLAGS. So we have to be careful to ignore value of these flags and not fail the ioctl when they are set (as e.g. chattr(1) passes flags returned from EXT4_IOC_GETFLAGS to EXT4_IOC_SETFLAGS without any masking and thus we'd break this utility). Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent f8011d9 commit d14e768

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

fs/ext4/ext4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ struct flex_groups {
399399
#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
400400
#define EXT4_FL_USER_MODIFIABLE 0x204BC0FF /* User modifiable flags */
401401

402+
/* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
402403
#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
403404
EXT4_IMMUTABLE_FL | \
404405
EXT4_APPEND_FL | \

fs/ext4/ioctl.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
415415
return xflags;
416416
}
417417

418+
#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
419+
FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
420+
FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT)
421+
418422
/* Transfer xflags flags to internal */
419423
static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
420424
{
@@ -459,12 +463,22 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
459463
if (get_user(flags, (int __user *) arg))
460464
return -EFAULT;
461465

466+
if (flags & ~EXT4_FL_USER_VISIBLE)
467+
return -EOPNOTSUPP;
468+
/*
469+
* chattr(1) grabs flags via GETFLAGS, modifies the result and
470+
* passes that to SETFLAGS. So we cannot easily make SETFLAGS
471+
* more restrictive than just silently masking off visible but
472+
* not settable flags as we always did.
473+
*/
474+
flags &= EXT4_FL_USER_MODIFIABLE;
475+
if (ext4_mask_flags(inode->i_mode, flags) != flags)
476+
return -EOPNOTSUPP;
477+
462478
err = mnt_want_write_file(filp);
463479
if (err)
464480
return err;
465481

466-
flags = ext4_mask_flags(inode->i_mode, flags);
467-
468482
inode_lock(inode);
469483
err = ext4_ioctl_setflags(inode, flags);
470484
inode_unlock(inode);
@@ -871,13 +885,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
871885
if (!inode_owner_or_capable(inode))
872886
return -EACCES;
873887

888+
if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
889+
return -EOPNOTSUPP;
890+
891+
flags = ext4_xflags_to_iflags(fa.fsx_xflags);
892+
if (ext4_mask_flags(inode->i_mode, flags) != flags)
893+
return -EOPNOTSUPP;
894+
874895
err = mnt_want_write_file(filp);
875896
if (err)
876897
return err;
877898

878-
flags = ext4_xflags_to_iflags(fa.fsx_xflags);
879-
flags = ext4_mask_flags(inode->i_mode, flags);
880-
881899
inode_lock(inode);
882900
flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
883901
(flags & EXT4_FL_XFLAG_VISIBLE);

0 commit comments

Comments
 (0)