Re: [PATCH][v3] overlayfs: Do not lose security.capability xattr over metadata file copy-up

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

 



On Wed, Jan 30, 2019 at 9:01 PM Vivek Goyal <vgoyal@xxxxxxxxxx> wrote:
>
> If a file has been copied up metadata only, and later data is copied up,
> upper loses any security.capability xattr it has (underlying filesystem
> clears it as upon file write).
>
> From a user's point of view, this is just a file copy-up and that should
> not result in losing security.capability xattr. Hence, before data copy
> up, save security.capability xattr (if any) and restore it on upper after
> data copy up is complete.
>
> Signed-off-by: Vivek Goyal <vgoyal@xxxxxxxxxx>

Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>

> ---
>  fs/overlayfs/copy_up.c   |   24 ++++++++++++++++++-
>  fs/overlayfs/overlayfs.h |    1
>  fs/overlayfs/util.c      |   58 +++++++++++++++++++++++++++++++++--------------
>  3 files changed, 65 insertions(+), 18 deletions(-)
>
> Index: rhvgoyal-linux/fs/overlayfs/util.c
> ===================================================================
> --- rhvgoyal-linux.orig/fs/overlayfs/util.c     2019-01-30 13:44:46.123840084 -0500
> +++ rhvgoyal-linux/fs/overlayfs/util.c  2019-01-30 13:48:50.433840084 -0500
> @@ -863,31 +863,61 @@ bool ovl_is_metacopy_dentry(struct dentr
>         return (oe->numlower > 1);
>  }
>
> -char *ovl_get_redirect_xattr(struct dentry *dentry, int padding)
> +size_t ovl_getxattr(struct dentry *dentry, char *name, void **value,
> +                               size_t *size, int padding)
>  {
>         int res;
> -       char *s, *next, *buf = NULL;
> +       void *buf = NULL;
>
> -       res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0);
> +       res = vfs_getxattr(dentry, name, NULL, 0);
>         if (res < 0) {
>                 if (res == -ENODATA || res == -EOPNOTSUPP)
> -                       return NULL;
> +                       return 0;
>                 goto fail;
>         }
>
> -       buf = kzalloc(res + padding + 1, GFP_KERNEL);
> -       if (!buf)
> -               return ERR_PTR(-ENOMEM);
> -
>         if (res == 0)
>                 goto invalid;
>
> -       res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res);
> +       buf = kzalloc(res + padding, GFP_KERNEL);
> +       if (!buf)
> +               return -ENOMEM;
> +
> +       res = vfs_getxattr(dentry, name, buf, res);
>         if (res < 0)
>                 goto fail;
> +
>         if (res == 0)
>                 goto invalid;
>
> +       *value = buf;
> +       if (size)
> +               *size = res;
> +
> +       return res;
> +
> +err_free:
> +       kfree(buf);
> +       return res;
> +fail:
> +       pr_warn_ratelimited("overlayfs: failed to get xattr %s: err=%i)\n", name, res);
> +       goto err_free;
> +invalid:
> +       pr_warn_ratelimited("overlayfs: invalid xattr %s \n", name);
> +       res = -EINVAL;
> +       goto err_free;
> +}
> +
> +char *ovl_get_redirect_xattr(struct dentry *dentry, int padding)
> +{
> +       int res;
> +       char *s, *next, *buf = NULL;
> +
> +       res = ovl_getxattr(dentry, OVL_XATTR_REDIRECT, (void **)&buf, NULL,
> +               padding + 1);
> +       if (res <= 0)
> +               return ERR_PTR(res);
> +
>         if (buf[0] == '/') {
>                 for (s = buf; *s++ == '/'; s = next) {
>                         next = strchrnul(s, '/');
> @@ -900,15 +930,9 @@ char *ovl_get_redirect_xattr(struct dent
>         }
>
>         return buf;
> -
> -err_free:
> -       kfree(buf);
> -       return ERR_PTR(res);
> -fail:
> -       pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res);
> -       goto err_free;
>  invalid:
>         pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf);
>         res = -EINVAL;
> -       goto err_free;
> +       kfree(buf);
> +       return ERR_PTR(res);
>  }
> Index: rhvgoyal-linux/fs/overlayfs/overlayfs.h
> ===================================================================
> --- rhvgoyal-linux.orig/fs/overlayfs/overlayfs.h        2019-01-30 13:44:46.121840084 -0500
> +++ rhvgoyal-linux/fs/overlayfs/overlayfs.h     2019-01-30 13:44:48.623840084 -0500
> @@ -277,6 +277,7 @@ int ovl_lock_rename_workdir(struct dentr
>  int ovl_check_metacopy_xattr(struct dentry *dentry);
>  bool ovl_is_metacopy_dentry(struct dentry *dentry);
>  char *ovl_get_redirect_xattr(struct dentry *dentry, int padding);
> +size_t ovl_getxattr(struct dentry *dentry, char *name, void **value, size_t *size, int padding);
>
>  static inline bool ovl_is_impuredir(struct dentry *dentry)
>  {
> Index: rhvgoyal-linux/fs/overlayfs/copy_up.c
> ===================================================================
> --- rhvgoyal-linux.orig/fs/overlayfs/copy_up.c  2019-01-30 13:44:46.119840084 -0500
> +++ rhvgoyal-linux/fs/overlayfs/copy_up.c       2019-01-30 13:44:48.624840084 -0500
> @@ -742,6 +742,8 @@ static int ovl_copy_up_meta_inode_data(s
>  {
>         struct path upperpath, datapath;
>         int err;
> +       void *capability = NULL;
> +       size_t cap_size;
>
>         ovl_path_upper(c->dentry, &upperpath);
>         if (WARN_ON(upperpath.dentry == NULL))
> @@ -751,9 +753,29 @@ static int ovl_copy_up_meta_inode_data(s
>         if (WARN_ON(datapath.dentry == NULL))
>                 return -EIO;
>
> +       if (c->stat.size) {
> +               cap_size = ovl_getxattr(upperpath.dentry, XATTR_NAME_CAPS, &capability, &cap_size, 0);
> +               if (cap_size < 0)
> +                       return cap_size;
> +       }
> +
>         err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size);
> -       if (err)
> +       if (err) {
> +               kfree(capability);
>                 return err;
> +       }
> +
> +       /*
> +        * Writing to upper file will clear security.capability xattr. We
> +        * don't want that to happen for normal copy-up operation.
> +        */
> +       if (capability) {
> +               err = ovl_do_setxattr(upperpath.dentry, XATTR_NAME_CAPS, capability, cap_size, 0);
> +               kfree(capability);
> +               if (err)
> +                       return err;
> +       }
> +
>
>         err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY);
>         if (err)




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux