Re: [PATCH 1/2] ext4: fix setattr project check upon fssetxattr ioctl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sep 4, 2018, at 8:54 AM, Wang Shilong <wangshilong1991@xxxxxxxxx> wrote:
> 
> Currently, project quota could be changed by fssetxattr
> ioctl, and existed permission check inode_owner_or_capable()
> is obviously not enough, just think that common users could
> change project id of file, that could make users to
> break project quota easily.
> 
> This patch try to follow same regular of xfs project
> quota:
> 
> "Project Quota ID state is only allowed to change from
> within the init namespace. Enforce that restriction only
> if we are trying to change the quota ID state.
> Everything else is allowed in user namespaces."
> 
> Besides that, check and set project id'state should
> be an atomic operation, protect whole operation with
> inode lock.
> 
> Signed-off-by: Wang Shilong <wshilong@xxxxxxx>
> ---
> fs/ext4/ioctl.c | 62 ++++++++++++++++++++++++++++++++++++---------------------
> 1 file changed, 39 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
> index a707411..e860df9 100644
> --- a/fs/ext4/ioctl.c
> +++ b/fs/ext4/ioctl.c
> @@ -339,19 +339,14 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> 	if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
> 		return 0;
> 
> -	err = mnt_want_write_file(filp);
> -	if (err)
> -		return err;
> -
> 	err = -EPERM;
> -	inode_lock(inode);
> 	/* Is it quota file? Do not allow user to mess with it */
> 	if (ext4_is_quota_file(inode))
> -		goto out_unlock;
> +		return err;
> 
> 	err = ext4_get_inode_loc(inode, &iloc);
> 	if (err)
> -		goto out_unlock;
> +		return err;
> 
> 	raw_inode = ext4_raw_inode(&iloc);
> 	if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
> @@ -359,7 +354,7 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> 					      EXT4_SB(sb)->s_want_extra_isize,
> 					      &iloc);
> 		if (err)
> -			goto out_unlock;
> +			return err;
> 	} else {
> 		brelse(iloc.bh);
> 	}
> @@ -369,10 +364,8 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> 	handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
> 		EXT4_QUOTA_INIT_BLOCKS(sb) +
> 		EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
> -	if (IS_ERR(handle)) {
> -		err = PTR_ERR(handle);
> -		goto out_unlock;
> -	}
> +	if (IS_ERR(handle))
> +		return PTR_ERR(handle);
> 
> 	err = ext4_reserve_inode_write(handle, inode, &iloc);
> 	if (err)
> @@ -400,9 +393,6 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> 		err = rc;
> out_stop:
> 	ext4_journal_stop(handle);
> -out_unlock:
> -	inode_unlock(inode);
> -	mnt_drop_write_file(filp);
> 	return err;
> }
> #else
> @@ -626,6 +616,32 @@ static long ext4_ioctl_group_add(struct file *file,
> 	return err;
> }
> 
> +static int
> +ext4_ioctl_setattr_check_projid(struct inode *inode,

One minor complaint is the function name "ext4_ioctl_setattr_check_projid()"
does not match the existing function name "ext4_ioctl_setproject()".  It would
be more consistent to name this "ext4_ioctl_check_project()", or maybe better
to name the current function "ext4_ioctl_set_projid()"?

Also, given that "check_projid()" is used before "setproject()", it makes sense
to locate "check_projid()" before "setproject()" in the code as well?

Cheers, Andreas

> +				struct fsxattr *fa)
> +{
> +	/*
> +	 * Project Quota ID state is only allowed to change from within the init
> +	 * namespace. Enforce that restriction only if we are trying to change
> +	 * the quota ID state. Everything else is allowed in user namespaces.
> +	 */
> +	if (current_user_ns() == &init_user_ns)
> +		return 0;
> +
> +	if (__kprojid_val(EXT4_I(inode)->i_projid) != fa->fsx_projid)
> +		return -EINVAL;
> +
> +	if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT)) {
> +		if (!(fa->fsx_xflags & FS_XFLAG_PROJINHERIT))
> +			return -EINVAL;
> +	} else {
> +		if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> {
> 	struct inode *inode = file_inode(filp);
> @@ -1025,19 +1041,19 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> 			return err;
> 
> 		inode_lock(inode);
> +		err = ext4_ioctl_setattr_check_projid(inode, &fa);
> +		if (err)
> +			goto out;
> 		flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
> 			 (flags & EXT4_FL_XFLAG_VISIBLE);
> 		err = ext4_ioctl_setflags(inode, flags);
> -		inode_unlock(inode);
> -		mnt_drop_write_file(filp);
> 		if (err)
> -			return err;
> -
> +			goto out;
> 		err = ext4_ioctl_setproject(filp, fa.fsx_projid);
> -		if (err)
> -			return err;
> -
> -		return 0;
> +out:
> +		inode_unlock(inode);
> +		mnt_drop_write_file(filp);
> +		return err;
> 	}
> 	case EXT4_IOC_SHUTDOWN:
> 		return ext4_shutdown(sb, arg);


Cheers, Andreas





Attachment: signature.asc
Description: Message signed with OpenPGP


[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux