Skip to content

Commit bf07089

Browse files
alexlarssonamir73il
authored andcommitted
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 <[email protected]> Reviewed-by: Amir Goldstein <[email protected]> Signed-off-by: Amir Goldstein <[email protected]>
1 parent ae8cba4 commit bf07089

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

fs/overlayfs/namei.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct ovl_lookup_data {
2525
bool stop;
2626
bool last;
2727
char *redirect;
28-
bool metacopy;
28+
int metacopy;
2929
/* Referring to last redirect xattr */
3030
bool absolute_redirect;
3131
};
@@ -270,7 +270,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
270270
d->stop = true;
271271
goto put_and_out;
272272
}
273-
err = ovl_check_metacopy_xattr(OVL_FS(d->sb), &path);
273+
err = ovl_check_metacopy_xattr(OVL_FS(d->sb), &path, NULL);
274274
if (err < 0)
275275
goto out_err;
276276

@@ -963,7 +963,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
963963
.stop = false,
964964
.last = ovl_redirect_follow(ofs) ? false : !ovl_numlower(poe),
965965
.redirect = NULL,
966-
.metacopy = false,
966+
.metacopy = 0,
967967
};
968968

969969
if (dentry->d_name.len > ofs->namelen)
@@ -1120,7 +1120,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
11201120

11211121
/* Defer lookup of lowerdata in data-only layers to first access */
11221122
if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) {
1123-
d.metacopy = false;
1123+
d.metacopy = 0;
11241124
ctr++;
11251125
}
11261126

@@ -1211,7 +1211,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
12111211
upperredirect = NULL;
12121212
goto out_free_oe;
12131213
}
1214-
err = ovl_check_metacopy_xattr(ofs, &upperpath);
1214+
err = ovl_check_metacopy_xattr(ofs, &upperpath, NULL);
12151215
if (err < 0)
12161216
goto out_free_oe;
12171217
uppermetacopy = err;

fs/overlayfs/overlayfs.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/kernel.h>
88
#include <linux/uuid.h>
99
#include <linux/fs.h>
10+
#include <linux/fsverity.h>
1011
#include <linux/namei.h>
1112
#include <linux/posix_acl.h>
1213
#include <linux/posix_acl_xattr.h>
@@ -132,6 +133,26 @@ struct ovl_fh {
132133
#define OVL_FH_FID_OFFSET (OVL_FH_WIRE_OFFSET + \
133134
offsetof(struct ovl_fb, fid))
134135

136+
/* On-disk format for "metacopy" xattr (if non-zero size) */
137+
struct ovl_metacopy {
138+
u8 version; /* 0 */
139+
u8 len; /* size of this header + used digest bytes */
140+
u8 flags;
141+
u8 digest_algo; /* FS_VERITY_HASH_ALG_* constant, 0 for no digest */
142+
u8 digest[FS_VERITY_MAX_DIGEST_SIZE]; /* Only the used part on disk */
143+
} __packed;
144+
145+
#define OVL_METACOPY_MAX_SIZE (sizeof(struct ovl_metacopy))
146+
#define OVL_METACOPY_MIN_SIZE (OVL_METACOPY_MAX_SIZE - FS_VERITY_MAX_DIGEST_SIZE)
147+
#define OVL_METACOPY_INIT { 0, OVL_METACOPY_MIN_SIZE }
148+
149+
static inline int ovl_metadata_digest_size(const struct ovl_metacopy *metacopy)
150+
{
151+
if (metacopy->len < OVL_METACOPY_MIN_SIZE)
152+
return 0;
153+
return (int)metacopy->len - OVL_METACOPY_MIN_SIZE;
154+
}
155+
135156
extern const char *const ovl_xattr_table[][2];
136157
static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox)
137158
{
@@ -458,7 +479,8 @@ bool ovl_need_index(struct dentry *dentry);
458479
int ovl_nlink_start(struct dentry *dentry);
459480
void ovl_nlink_end(struct dentry *dentry);
460481
int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
461-
int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path);
482+
int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path,
483+
struct ovl_metacopy *data);
462484
bool ovl_is_metacopy_dentry(struct dentry *dentry);
463485
char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding);
464486
int ovl_sync_status(struct ovl_fs *ofs);

fs/overlayfs/util.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,16 +1054,21 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
10541054
return -EIO;
10551055
}
10561056

1057-
/* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
1058-
int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path)
1057+
/*
1058+
* err < 0, 0 if no metacopy xattr, metacopy data size if xattr found.
1059+
* an empty xattr returns OVL_METACOPY_MIN_SIZE to distinguish from no xattr value.
1060+
*/
1061+
int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path,
1062+
struct ovl_metacopy *data)
10591063
{
10601064
int res;
10611065

10621066
/* Only regular files can have metacopy xattr */
10631067
if (!S_ISREG(d_inode(path->dentry)->i_mode))
10641068
return 0;
10651069

1066-
res = ovl_path_getxattr(ofs, path, OVL_XATTR_METACOPY, NULL, 0);
1070+
res = ovl_path_getxattr(ofs, path, OVL_XATTR_METACOPY,
1071+
data, data ? OVL_METACOPY_MAX_SIZE : 0);
10671072
if (res < 0) {
10681073
if (res == -ENODATA || res == -EOPNOTSUPP)
10691074
return 0;
@@ -1077,7 +1082,31 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path)
10771082
goto out;
10781083
}
10791084

1080-
return 1;
1085+
if (res == 0) {
1086+
/* Emulate empty data for zero size metacopy xattr */
1087+
res = OVL_METACOPY_MIN_SIZE;
1088+
if (data) {
1089+
memset(data, 0, res);
1090+
data->len = res;
1091+
}
1092+
} else if (res < OVL_METACOPY_MIN_SIZE) {
1093+
pr_warn_ratelimited("metacopy file '%pd' has too small xattr\n",
1094+
path->dentry);
1095+
return -EIO;
1096+
} else if (data) {
1097+
if (data->version != 0) {
1098+
pr_warn_ratelimited("metacopy file '%pd' has unsupported version\n",
1099+
path->dentry);
1100+
return -EIO;
1101+
}
1102+
if (res != data->len) {
1103+
pr_warn_ratelimited("metacopy file '%pd' has invalid xattr size\n",
1104+
path->dentry);
1105+
return -EIO;
1106+
}
1107+
}
1108+
1109+
return res;
10811110
out:
10821111
pr_warn_ratelimited("failed to get metacopy (%i)\n", res);
10831112
return res;

0 commit comments

Comments
 (0)