ovl: Add versioned header for overlay.metacopy xattr
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@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
ae8cba4033
commit
bf07089081
@ -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;
|
||||
|
@ -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>
|
||||
@ -132,6 +133,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)
|
||||
{
|
||||
@ -458,7 +479,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);
|
||||
|
@ -1054,8 +1054,12 @@ err:
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user