Commit 0c71faf5 authored by Alexander Larsson's avatar Alexander Larsson Committed by Amir Goldstein
Browse files

ovl: Handle verity during copy-up



During regular metacopy, if lowerdata file has fs-verity enabled, and
the verity option is enabled, we add the digest to the metacopy xattr.

If verity is required, and lowerdata does not have fs-verity enabled,
fall back to full copy-up (or the generated metacopy would not
validate).

Signed-off-by: default avatarAlexander Larsson <alexl@redhat.com>
Reviewed-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
parent 184996e9
Loading
Loading
Loading
Loading
+44 −4
Original line number Diff line number Diff line
@@ -544,6 +544,7 @@ struct ovl_copy_up_ctx {
	bool origin;
	bool indexed;
	bool metacopy;
	bool metacopy_digest;
};

static int ovl_link_up(struct ovl_copy_up_ctx *c)
@@ -641,8 +642,20 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
	}

	if (c->metacopy) {
		err = ovl_check_setxattr(ofs, temp, OVL_XATTR_METACOPY,
					 NULL, 0, -EOPNOTSUPP);
		struct path lowerdatapath;
		struct ovl_metacopy metacopy_data = OVL_METACOPY_INIT;

		ovl_path_lowerdata(c->dentry, &lowerdatapath);
		if (WARN_ON_ONCE(lowerdatapath.dentry == NULL))
			return -EIO;
		err = ovl_get_verity_digest(ofs, &lowerdatapath, &metacopy_data);
		if (err)
			return err;

		if (metacopy_data.digest_algo)
			c->metacopy_digest = true;

		err = ovl_set_metacopy_xattr(ofs, temp, &metacopy_data);
		if (err)
			return err;
	}
@@ -751,9 +764,15 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
	if (err)
		goto cleanup;

	if (!c->metacopy)
		ovl_set_upperdata(d_inode(c->dentry));
	inode = d_inode(c->dentry);
	if (c->metacopy_digest)
		ovl_set_flag(OVL_HAS_DIGEST, inode);
	else
		ovl_clear_flag(OVL_HAS_DIGEST, inode);
	ovl_clear_flag(OVL_VERIFIED_DIGEST, inode);

	if (!c->metacopy)
		ovl_set_upperdata(inode);
	ovl_inode_update(inode, temp);
	if (S_ISDIR(inode->i_mode))
		ovl_set_flag(OVL_WHITEOUTS, inode);
@@ -813,6 +832,12 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
	if (err)
		goto out_fput;

	if (c->metacopy_digest)
		ovl_set_flag(OVL_HAS_DIGEST, d_inode(c->dentry));
	else
		ovl_clear_flag(OVL_HAS_DIGEST, d_inode(c->dentry));
	ovl_clear_flag(OVL_VERIFIED_DIGEST, d_inode(c->dentry));

	if (!c->metacopy)
		ovl_set_upperdata(d_inode(c->dentry));
	ovl_inode_update(d_inode(c->dentry), dget(temp));
@@ -918,6 +943,19 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode,
	if (flags && ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC)))
		return false;

	/* Fall back to full copy if no fsverity on source data and we require verity */
	if (ofs->config.verity_mode == OVL_VERITY_REQUIRE) {
		struct path lowerdata;

		ovl_path_lowerdata(dentry, &lowerdata);

		if (WARN_ON_ONCE(lowerdata.dentry == NULL) ||
		    ovl_ensure_verity_loaded(&lowerdata) ||
		    !fsverity_active(d_inode(lowerdata.dentry))) {
			return false;
		}
	}

	return true;
}

@@ -984,6 +1022,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
	if (err)
		goto out_free;

	ovl_clear_flag(OVL_HAS_DIGEST, d_inode(c->dentry));
	ovl_clear_flag(OVL_VERIFIED_DIGEST, d_inode(c->dentry));
	ovl_set_upperdata(d_inode(c->dentry));
out_free:
	kfree(capability);
+3 −0
Original line number Diff line number Diff line
@@ -487,11 +487,14 @@ int ovl_set_metacopy_xattr(struct ovl_fs *ofs, struct dentry *d,
			   struct ovl_metacopy *metacopy);
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_ensure_verity_loaded(struct path *path);
int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path,
			 u8 *digest_buf, int *buf_length);
int ovl_validate_verity(struct ovl_fs *ofs,
			struct path *metapath,
			struct path *datapath);
int ovl_get_verity_digest(struct ovl_fs *ofs, struct path *src,
			  struct ovl_metacopy *metacopy);
int ovl_sync_status(struct ovl_fs *ofs);

static inline void ovl_set_flag(unsigned long flag, struct inode *inode)
+32 −1
Original line number Diff line number Diff line
@@ -1188,7 +1188,7 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int pa
}

/* Call with mounter creds as it may open the file */
static int ovl_ensure_verity_loaded(struct path *datapath)
int ovl_ensure_verity_loaded(struct path *datapath)
{
	struct inode *inode = d_inode(datapath->dentry);
	struct file *filp;
@@ -1262,6 +1262,37 @@ int ovl_validate_verity(struct ovl_fs *ofs,
	return 0;
}

int ovl_get_verity_digest(struct ovl_fs *ofs, struct path *src,
			  struct ovl_metacopy *metacopy)
{
	int err, digest_size;

	if (!ofs->config.verity_mode || !S_ISREG(d_inode(src->dentry)->i_mode))
		return 0;

	err = ovl_ensure_verity_loaded(src);
	if (err < 0) {
		pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n",
				    src->dentry);
		return -EIO;
	}

	digest_size = fsverity_get_digest(d_inode(src->dentry),
					  metacopy->digest, &metacopy->digest_algo, NULL);
	if (digest_size == 0 ||
	    WARN_ON_ONCE(digest_size > FS_VERITY_MAX_DIGEST_SIZE)) {
		if (ofs->config.verity_mode == OVL_VERITY_REQUIRE) {
			pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n",
					    src->dentry);
			return -EIO;
		}
		return 0;
	}

	metacopy->len += digest_size;
	return 0;
}

/*
 * ovl_sync_status() - Check fs sync status for volatile mounts
 *