ovl: fix wrong flags check in FS_IOC_FS[SG]ETXATTR ioctls

The ioctl argument was parsed as the wrong type.

Fixes: b21d9c435f ("ovl: support the FS_IOC_FS[SG]ETXATTR ioctls")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Amir Goldstein 2019-06-11 18:09:28 +03:00 committed by Miklos Szeredi
parent d1fdb6d8f6
commit 941d935ac7
1 changed files with 65 additions and 26 deletions

View File

@ -409,37 +409,16 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
return ret;
}
static unsigned int ovl_get_inode_flags(struct inode *inode)
{
unsigned int flags = READ_ONCE(inode->i_flags);
unsigned int ovl_iflags = 0;
if (flags & S_SYNC)
ovl_iflags |= FS_SYNC_FL;
if (flags & S_APPEND)
ovl_iflags |= FS_APPEND_FL;
if (flags & S_IMMUTABLE)
ovl_iflags |= FS_IMMUTABLE_FL;
if (flags & S_NOATIME)
ovl_iflags |= FS_NOATIME_FL;
return ovl_iflags;
}
static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
unsigned long arg)
unsigned long arg, unsigned int iflags)
{
long ret;
struct inode *inode = file_inode(file);
unsigned int flags;
unsigned int old_flags;
unsigned int old_iflags;
if (!inode_owner_or_capable(inode))
return -EACCES;
if (get_user(flags, (int __user *) arg))
return -EFAULT;
ret = mnt_want_write_file(file);
if (ret)
return ret;
@ -448,8 +427,8 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
/* Check the capability before cred override */
ret = -EPERM;
old_flags = ovl_get_inode_flags(inode);
if (((flags ^ old_flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
old_iflags = READ_ONCE(inode->i_flags);
if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) &&
!capable(CAP_LINUX_IMMUTABLE))
goto unlock;
@ -469,6 +448,63 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
}
static unsigned int ovl_fsflags_to_iflags(unsigned int flags)
{
unsigned int iflags = 0;
if (flags & FS_SYNC_FL)
iflags |= S_SYNC;
if (flags & FS_APPEND_FL)
iflags |= S_APPEND;
if (flags & FS_IMMUTABLE_FL)
iflags |= S_IMMUTABLE;
if (flags & FS_NOATIME_FL)
iflags |= S_NOATIME;
return iflags;
}
static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned int flags;
if (get_user(flags, (int __user *) arg))
return -EFAULT;
return ovl_ioctl_set_flags(file, cmd, arg,
ovl_fsflags_to_iflags(flags));
}
static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags)
{
unsigned int iflags = 0;
if (xflags & FS_XFLAG_SYNC)
iflags |= S_SYNC;
if (xflags & FS_XFLAG_APPEND)
iflags |= S_APPEND;
if (xflags & FS_XFLAG_IMMUTABLE)
iflags |= S_IMMUTABLE;
if (xflags & FS_XFLAG_NOATIME)
iflags |= S_NOATIME;
return iflags;
}
static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct fsxattr fa;
memset(&fa, 0, sizeof(fa));
if (copy_from_user(&fa, (void __user *) arg, sizeof(fa)))
return -EFAULT;
return ovl_ioctl_set_flags(file, cmd, arg,
ovl_fsxflags_to_iflags(fa.fsx_xflags));
}
static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
@ -480,8 +516,11 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case FS_IOC_SETFLAGS:
ret = ovl_ioctl_set_fsflags(file, cmd, arg);
break;
case FS_IOC_FSSETXATTR:
ret = ovl_ioctl_set_flags(file, cmd, arg);
ret = ovl_ioctl_set_fsxflags(file, cmd, arg);
break;
default: