Re: [PATCH v4 2/4] ovl: Add versioned header for overlay.metacopy xattr

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

 



On Wed, Jun 21, 2023 at 2:18 PM Alexander Larsson <alexl@xxxxxxxxxx> wrote:
>
> Historically overlay.metacopy was a zero-size xattr, and it's
> existence marked a metacopy file. This change adds a versioned header
> with a flag field, a length and a digest. The initial use-case of this
> will be for validating a fs-verity digest, but the flags field could
> also be used later for other new features.
>
> ovl_check_metacopy_xattr() now returns the size of the xattr,
> emulating a size of OVL_METACOPY_MIN_SIZE for empty xattrs to
> distinguish it from the no-xattr case.
>
> Signed-off-by: Alexander Larsson <alexl@xxxxxxxxxx>

Looks good.

Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>

> ---
>  fs/overlayfs/namei.c     | 10 +++++-----
>  fs/overlayfs/overlayfs.h | 24 +++++++++++++++++++++++-
>  fs/overlayfs/util.c      | 37 +++++++++++++++++++++++++++++++++----
>  3 files changed, 61 insertions(+), 10 deletions(-)
>
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index 57adf911735f..3dd480253710 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -25,7 +25,7 @@ struct ovl_lookup_data {
>         bool stop;
>         bool last;
>         char *redirect;
> -       bool metacopy;
> +       int metacopy;
>         /* Referring to last redirect xattr */
>         bool absolute_redirect;
>  };
> @@ -270,7 +270,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
>                         d->stop = true;
>                         goto put_and_out;
>                 }
> -               err = ovl_check_metacopy_xattr(OVL_FS(d->sb), &path);
> +               err = ovl_check_metacopy_xattr(OVL_FS(d->sb), &path, NULL);
>                 if (err < 0)
>                         goto out_err;
>
> @@ -963,7 +963,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                 .stop = false,
>                 .last = ovl_redirect_follow(ofs) ? false : !ovl_numlower(poe),
>                 .redirect = NULL,
> -               .metacopy = false,
> +               .metacopy = 0,
>         };
>
>         if (dentry->d_name.len > ofs->namelen)
> @@ -1120,7 +1120,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>
>         /* Defer lookup of lowerdata in data-only layers to first access */
>         if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) {
> -               d.metacopy = false;
> +               d.metacopy = 0;
>                 ctr++;
>         }
>
> @@ -1211,7 +1211,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                         upperredirect = NULL;
>                         goto out_free_oe;
>                 }
> -               err = ovl_check_metacopy_xattr(ofs, &upperpath);
> +               err = ovl_check_metacopy_xattr(ofs, &upperpath, NULL);
>                 if (err < 0)
>                         goto out_free_oe;
>                 uppermetacopy = err;
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index cf92a9aaf934..6d4e08df0dfe 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -7,6 +7,7 @@
>  #include <linux/kernel.h>
>  #include <linux/uuid.h>
>  #include <linux/fs.h>
> +#include <linux/fsverity.h>
>  #include <linux/namei.h>
>  #include <linux/posix_acl.h>
>  #include <linux/posix_acl_xattr.h>
> @@ -140,6 +141,26 @@ struct ovl_fh {
>  #define OVL_FH_FID_OFFSET      (OVL_FH_WIRE_OFFSET + \
>                                  offsetof(struct ovl_fb, fid))
>
> +/* On-disk format for "metacopy" xattr (if non-zero size) */
> +struct ovl_metacopy {
> +       u8 version;     /* 0 */
> +       u8 len;         /* size of this header + used digest bytes */
> +       u8 flags;
> +       u8 digest_algo; /* FS_VERITY_HASH_ALG_* constant, 0 for no digest */
> +       u8 digest[FS_VERITY_MAX_DIGEST_SIZE];  /* Only the used part on disk */
> +} __packed;
> +
> +#define OVL_METACOPY_MAX_SIZE (sizeof(struct ovl_metacopy))
> +#define OVL_METACOPY_MIN_SIZE (OVL_METACOPY_MAX_SIZE - FS_VERITY_MAX_DIGEST_SIZE)
> +#define OVL_METACOPY_INIT { 0, OVL_METACOPY_MIN_SIZE }
> +
> +static inline int ovl_metadata_digest_size(const struct ovl_metacopy *metacopy)
> +{
> +       if (metacopy->len < OVL_METACOPY_MIN_SIZE)
> +               return 0;
> +       return (int)metacopy->len - OVL_METACOPY_MIN_SIZE;
> +}
> +
>  extern const char *const ovl_xattr_table[][2];
>  static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox)
>  {
> @@ -490,7 +511,8 @@ bool ovl_need_index(struct dentry *dentry);
>  int ovl_nlink_start(struct dentry *dentry);
>  void ovl_nlink_end(struct dentry *dentry);
>  int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
> -int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path);
> +int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path,
> +                            struct ovl_metacopy *data);
>  bool ovl_is_metacopy_dentry(struct dentry *dentry);
>  char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding);
>  int ovl_sync_status(struct ovl_fs *ofs);
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index 7ef9e13c404a..921747223991 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -1054,8 +1054,12 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
>         return -EIO;
>  }
>
> -/* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
> -int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path)
> +/*
> + * err < 0, 0 if no metacopy xattr, metacopy data size if xattr found.
> + * an empty xattr returns OVL_METACOPY_MIN_SIZE to distinguish from no xattr value.
> + */
> +int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path,
> +                            struct ovl_metacopy *data)
>  {
>         int res;
>
> @@ -1063,7 +1067,8 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path)
>         if (!S_ISREG(d_inode(path->dentry)->i_mode))
>                 return 0;
>
> -       res = ovl_path_getxattr(ofs, path, OVL_XATTR_METACOPY, NULL, 0);
> +       res = ovl_path_getxattr(ofs, path, OVL_XATTR_METACOPY,
> +                               data, data ? OVL_METACOPY_MAX_SIZE : 0);
>         if (res < 0) {
>                 if (res == -ENODATA || res == -EOPNOTSUPP)
>                         return 0;
> @@ -1077,7 +1082,31 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path)
>                 goto out;
>         }
>
> -       return 1;
> +       if (res == 0) {
> +               /* Emulate empty data for zero size metacopy xattr */
> +               res = OVL_METACOPY_MIN_SIZE;
> +               if (data) {
> +                       memset(data, 0, res);
> +                       data->len = res;
> +               }
> +       } else if (res < OVL_METACOPY_MIN_SIZE) {
> +               pr_warn_ratelimited("metacopy file '%pd' has too small xattr\n",
> +                                   path->dentry);
> +               return -EIO;
> +       } else if (data) {
> +               if (data->version != 0) {
> +                       pr_warn_ratelimited("metacopy file '%pd' has unsupported version\n",
> +                                           path->dentry);
> +                       return -EIO;
> +               }
> +               if (res != data->len) {
> +                       pr_warn_ratelimited("metacopy file '%pd' has invalid xattr size\n",
> +                                           path->dentry);
> +                       return -EIO;
> +               }
> +       }
> +
> +       return res;
>  out:
>         pr_warn_ratelimited("failed to get metacopy (%i)\n", res);
>         return res;
> --
> 2.40.1
>




[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