Re: [PATCH] overlayfs: check the capability before cred overridden

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

 



On Mon, May 6, 2019 at 10:41 AM Jiufei Xue <jiufei.xue@xxxxxxxxxxxxxxxxx> wrote:
>
> We found that it return success when we set IMMUTABLE_FL flag to a
> file in docker even though the docker didn't have the capability
> CAP_LINUX_IMMUTABLE.
>
> The commit d1d04ef8572b ("ovl: stack file ops") and
> dab5ca8fd9dd ("ovl: add lsattr/chattr support") implemented chattr
> operations on a regular overlay file. ovl_real_ioctl() overridden the
> current process's subjective credentials with ofs->creator_cred which
> have the capability CAP_LINUX_IMMUTABLE so that it will return success
> in vfs_ioctl()->cap_capable().
>
> Fix this by checking the capability before cred overriden. And here we
> only care about APPEND_FL and IMMUTABLE_FL, so get these information from
> inode.

Good idea. My idea was less good ;-)
See one minor comment below.

Will you be able to write an xfstest to cover this bug?
See for reference tests/generic/159 and tests/generic/099

Thanks,
Amir.

>
> Signed-off-by: Jiufei Xue <jiufei.xue@xxxxxxxxxxxxxxxxx>
> ---
>  fs/overlayfs/file.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>
> diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
> index 84dd957efa24..fecf1b43b6fe 100644
> --- a/fs/overlayfs/file.c
> +++ b/fs/overlayfs/file.c
> @@ -11,6 +11,7 @@
>  #include <linux/mount.h>
>  #include <linux/xattr.h>
>  #include <linux/uio.h>
> +#include <linux/uaccess.h>
>  #include "overlayfs.h"
>
>  static char ovl_whatisit(struct inode *inode, struct inode *realinode)
> @@ -372,10 +373,30 @@ 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;
> +       if (flags & S_DIRSYNC)
> +               ovl_iflags |= FS_DIRSYNC_FL;

Since ovl_copyflags() does not copy FS_DIRSYNC_FL, I don't think ovl
inode can have FS_DIRSYNC_FL set.
If you think that is important, you can add it to copied flags.

> +
> +       return ovl_iflags;
> +}
> +
>  static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  {
>         long ret;
>         struct inode *inode = file_inode(file);
> +       unsigned int flags;
>
>         switch (cmd) {
>         case FS_IOC_GETFLAGS:
> @@ -386,6 +407,15 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>                 if (!inode_owner_or_capable(inode))
>                         return -EACCES;
>
> +               if (get_user(flags, (int __user *) arg))
> +                       return -EFAULT;
> +
> +               /* Check the capability before cred overridden */
> +               if ((flags ^ ovl_get_inode_flags(inode)) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
> +                       if (!capable(CAP_LINUX_IMMUTABLE))
> +                               return -EPERM;
> +               }
> +
>                 ret = mnt_want_write_file(file);
>                 if (ret)
>                         return ret;
> --
> 2.19.1.856.g8858448bb
>



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [Monitors]

  Powered by Linux