summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/util.c')
-rw-r--r--fs/overlayfs/util.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 921747223991..1df6230dde7c 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -10,6 +10,7 @@
#include <linux/cred.h>
#include <linux/xattr.h>
#include <linux/exportfs.h>
+#include <linux/file.h>
#include <linux/fileattr.h>
#include <linux/uuid.h>
#include <linux/namei.h>
@@ -1112,6 +1113,18 @@ out:
return res;
}
+int ovl_set_metacopy_xattr(struct ovl_fs *ofs, struct dentry *d, struct ovl_metacopy *metacopy)
+{
+ size_t len = metacopy->len;
+
+ /* If no flags or digest fall back to empty metacopy file */
+ if (metacopy->version == 0 && metacopy->flags == 0 && metacopy->digest_algo == 0)
+ len = 0;
+
+ return ovl_check_setxattr(ofs, d, OVL_XATTR_METACOPY,
+ metacopy, len, -EOPNOTSUPP);
+}
+
bool ovl_is_metacopy_dentry(struct dentry *dentry)
{
struct ovl_entry *oe = OVL_E(dentry);
@@ -1174,6 +1187,81 @@ err_free:
return ERR_PTR(res);
}
+/* Call with mounter creds as it may open the file */
+static int ovl_ensure_verity_loaded(struct path *datapath)
+{
+ struct inode *inode = d_inode(datapath->dentry);
+ struct file *filp;
+
+ if (!fsverity_active(inode) && IS_VERITY(inode)) {
+ /*
+ * If this inode was not yet opened, the verity info hasn't been
+ * loaded yet, so we need to do that here to force it into memory.
+ */
+ filp = kernel_file_open(datapath, O_RDONLY, inode, current_cred());
+ if (IS_ERR(filp))
+ return PTR_ERR(filp);
+ fput(filp);
+ }
+
+ return 0;
+}
+
+int ovl_validate_verity(struct ovl_fs *ofs,
+ struct path *metapath,
+ struct path *datapath)
+{
+ struct ovl_metacopy metacopy_data;
+ u8 actual_digest[FS_VERITY_MAX_DIGEST_SIZE];
+ int xattr_digest_size, digest_size;
+ int xattr_size, err;
+ u8 verity_algo;
+
+ if (!ofs->config.verity_mode ||
+ /* Verity only works on regular files */
+ !S_ISREG(d_inode(metapath->dentry)->i_mode))
+ return 0;
+
+ xattr_size = ovl_check_metacopy_xattr(ofs, metapath, &metacopy_data);
+ if (xattr_size < 0)
+ return xattr_size;
+
+ if (!xattr_size || !metacopy_data.digest_algo) {
+ if (ofs->config.verity_mode == OVL_VERITY_REQUIRE) {
+ pr_warn_ratelimited("metacopy file '%pd' has no digest specified\n",
+ metapath->dentry);
+ return -EIO;
+ }
+ return 0;
+ }
+
+ xattr_digest_size = ovl_metadata_digest_size(&metacopy_data);
+
+ err = ovl_ensure_verity_loaded(datapath);
+ if (err < 0) {
+ pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n",
+ datapath->dentry);
+ return -EIO;
+ }
+
+ digest_size = fsverity_get_digest(d_inode(datapath->dentry), actual_digest,
+ &verity_algo, NULL);
+ if (digest_size == 0) {
+ pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n", datapath->dentry);
+ return -EIO;
+ }
+
+ if (xattr_digest_size != digest_size ||
+ metacopy_data.digest_algo != verity_algo ||
+ memcmp(metacopy_data.digest, actual_digest, xattr_digest_size) != 0) {
+ pr_warn_ratelimited("lower file '%pd' has the wrong fs-verity digest\n",
+ datapath->dentry);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/*
* ovl_sync_status() - Check fs sync status for volatile mounts
*