@@ -95,6 +95,7 @@ static struct ipe_eval_ctx *build_ctx(const struct file *file,
ctx->ci_ctx = ipe_current_ctx();
ctx->from_init_sb = from_pinned(file);
if (file) {
+ ctx->ipe_inode = ipe_inode(file->f_inode);
if (FILE_BLOCK_DEV(file))
ctx->ipe_bdev = ipe_bdev(FILE_BLOCK_DEV(file));
}
@@ -22,6 +22,10 @@ struct ipe_bdev {
const char *digest_algo;
};
+struct ipe_inode {
+ bool fs_verity_signed;
+};
+
struct ipe_eval_ctx {
enum ipe_operation op;
@@ -29,6 +33,7 @@ struct ipe_eval_ctx {
struct ipe_context *ci_ctx;
const struct ipe_bdev *ipe_bdev;
+ const struct ipe_inode *ipe_inode;
bool from_init_sb;
};
@@ -267,3 +267,32 @@ int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
return -EOPNOTSUPP;
}
+
+/**
+ * ipe_inode_setsecurity: Sets the a certain field of a inode security
+ * blob, based on @key.
+ * @inode: The inode to source the security blob from.
+ * @name: The name representing the information to be stored.
+ * @value: The value to be stored.
+ * @size: The size of @value.
+ * @flags: unused
+ *
+ * Saves fsverity signature & digest into inode security blob
+ *
+ * Return:
+ * 0 - OK
+ * !0 - Error
+ */
+int ipe_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size,
+ int flags)
+{
+ struct ipe_inode *inode_sec = ipe_inode(inode);
+
+ if (!strcmp(name, FS_VERITY_INODE_SEC_NAME)) {
+ inode_sec->fs_verity_signed = size > 0 && value;
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/binfmts.h>
#include <linux/security.h>
+#include <linux/fsverity.h>
#include <linux/device-mapper.h>
int ipe_task_alloc(struct task_struct *task,
@@ -37,4 +38,8 @@ void ipe_bdev_free_security(struct block_device *bdev);
int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
const void *value, size_t len);
+int ipe_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size,
+ int flags);
+
#endif /* IPE_HOOKS_H */
@@ -24,6 +24,7 @@ bool ipe_enabled;
static struct lsm_blob_sizes ipe_blobs __lsm_ro_after_init = {
.lbs_task = sizeof(struct ipe_context __rcu *),
.lbs_bdev = sizeof(struct ipe_bdev),
+ .lbs_inode = sizeof(struct ipe_inode),
};
struct ipe_bdev *ipe_bdev(struct block_device *b)
@@ -31,6 +32,11 @@ struct ipe_bdev *ipe_bdev(struct block_device *b)
return b->security + ipe_blobs.lbs_bdev;
}
+struct ipe_inode *ipe_inode(const struct inode *inode)
+{
+ return inode->i_security + ipe_blobs.lbs_inode;
+}
+
static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_alloc, ipe_task_alloc),
LSM_HOOK_INIT(task_free, ipe_task_free),
@@ -42,6 +48,7 @@ static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_free_security, ipe_sb_free_security),
LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security),
LSM_HOOK_INIT(bdev_setsecurity, ipe_bdev_setsecurity),
+ LSM_HOOK_INIT(inode_setsecurity, ipe_inode_setsecurity),
};
/**
@@ -23,5 +23,6 @@ extern struct ipe_parser __start_ipe_parsers[], __end_ipe_parsers[];
extern struct ipe_module __start_ipe_modules[], __end_ipe_modules[];
struct ipe_bdev *ipe_bdev(struct block_device *b);
+struct ipe_inode *ipe_inode(const struct inode *inode);
#endif /* IPE_H */
@@ -40,4 +40,27 @@ config IPE_PROP_DM_VERITY_ROOTHASH
If unsure, answer Y.
+config IPE_PROP_FS_VERITY_SIGNATURE
+ bool "Enable property for signed fs-verity files"
+ depends on FS_VERITY_BUILTIN_SIGNATURES
+ help
+ This option enables IPE's integration with FSVerity's
+ signed hashes. This enables the usage of the property,
+ "fsverity_signature" in IPE's policy.
+
+ if unsure, answer Y.
+
+config IPE_PROP_FS_VERITY_DIGEST
+ bool "Enable property for authorizing fs-verity files via digest"
+ depends on FS_VERITY
+ help
+ This option enables IPE's integration with FSVerity.
+ This enables the usage of the property "fsverity_digest" in IPE's
+ policy. This property allows authorization or revocation via a
+ a hex-string representing the digest of a fsverity file.
+
+ if unsure, answer Y.
+
+
+
endmenu
@@ -8,3 +8,5 @@
obj-$(CONFIG_IPE_PROP_BOOT_VERIFIED) += boot_verified.o
obj-$(CONFIG_IPE_PROP_DM_VERITY_SIGNATURE) += dmverity_signature.o
obj-$(CONFIG_IPE_PROP_DM_VERITY_ROOTHASH) += dmverity_roothash.o
+obj-$(CONFIG_IPE_PROP_FS_VERITY_SIGNATURE) += fsverity_signature.o
+obj-$(CONFIG_IPE_PROP_FS_VERITY_DIGEST) += fsverity_digest.o
new file mode 100644
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "ipe_module.h"
+
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/fsverity.h>
+#include <crypto/hash_info.h>
+
+static bool evaluate(const struct ipe_eval_ctx *ctx, const void *val)
+{
+ enum hash_algo alg;
+ u8 digest[FS_VERITY_MAX_DIGEST_SIZE];
+ struct inode *ino;
+
+ if (!ctx->file)
+ return false;
+
+ ino = file_inode(ctx->file);
+ if (!ino)
+ return false;
+
+ if (fsverity_get_digest(ino, digest, &alg))
+ return false;
+
+ return ipe_digest_eval(val, digest, hash_digest_size[alg], hash_algo_name[alg]);
+}
+
+IPE_MODULE(fsv_digest) = {
+ .name = "fsverity_digest",
+ .version = 1,
+ .parse = ipe_digest_parse,
+ .free = ipe_digest_free,
+ .eval = evaluate,
+ .audit = ipe_digest_audit,
+};
new file mode 100644
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "ipe_module.h"
+
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/audit.h>
+#include <linux/mount.h>
+
+static bool evaluate(const struct ipe_eval_ctx *ctx, const void *value)
+{
+ bool expect = (bool)value;
+
+ if (!ctx->file || !IS_VERITY(ctx->file->f_inode))
+ return false;
+
+ if (!ctx->ipe_inode)
+ return false;
+
+ return (!!ctx->ipe_inode->fs_verity_signed) == expect;
+}
+
+IPE_MODULE(fsvs) = {
+ .name = "fsverity_signature",
+ .version = 1,
+ .parse = ipe_bool_parse,
+ .free = NULL,
+ .eval = evaluate,
+ .audit = ipe_bool_audit,
+};