@@ -30,6 +30,19 @@ config IPE_PROP_DM_VERITY
that was mounted with a signed root-hash or the volume's
root hash matches the supplied value in the policy.
+ If unsure, answer Y.
+
+config IPE_PROP_FS_VERITY
+ bool "Enable property for fs-verity files"
+ depends on FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES
+ help
+ This option enables the usage of properties "fsverity_signature"
+ and "fsverity_digest". These properties evaluates to TRUE when
+ a file is fsverity enabled and with a signed digest or its
+ diegst matches the supplied value in the policy.
+
+ if unsure, answer Y.
+
endmenu
endif
@@ -46,6 +46,11 @@ static const char *const audit_prop_names[__IPE_PROP_MAX] = {
"dmverity_signature=FALSE",
"dmverity_signature=TRUE",
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+ "fsverity_digest=",
+ "fsverity_signature=FALSE",
+ "fsverity_signature=TRUE"
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
};
#ifdef CONFIG_IPE_PROP_DM_VERITY
@@ -64,6 +69,22 @@ static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh)
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+/**
+ * audit_fsv_digest - audit a digest of a fsverity file.
+ * @ab: Supplies a pointer to the audit_buffer to append to.
+ * @d: Supplies a pointer to the digest structure.
+ */
+static void audit_fsv_digest(struct audit_buffer *ab, const void *d)
+{
+ ipe_digest_audit(ab, d);
+}
+#else
+static void audit_fsv_digest(struct audit_buffer *ab, const void *d)
+{
+}
+#endif /* CONFIG_IPE_PROP_DM_VERITY */
+
/**
* audit_rule - audit an IPE policy rule approximation.
* @ab: Supplies a pointer to the audit_buffer to append to.
@@ -79,6 +100,8 @@ static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
if (ptr->type == IPE_PROP_DMV_ROOTHASH)
audit_dmv_roothash(ab, ptr->value);
+ if (ptr->type == IPE_PROP_FSV_DIGEST)
+ audit_fsv_digest(ab, ptr->value);
audit_log_format(ab, " ");
}
@@ -11,6 +11,7 @@
#include <linux/rcupdate.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
+#include <linux/fsverity.h>
#include "ipe.h"
#include "eval.h"
@@ -78,6 +79,23 @@ static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *con
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+/**
+ * build_ipe_inode_ctx - Build inode fields of an evaluation context.
+ * @ctx: Supplies a pointer to the context to be populdated.
+ * @ino: Supplies the inode struct of the file triggered IPE event.
+ */
+static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
+{
+ ctx->ino = ino;
+ ctx->ipe_inode = ipe_inode(ctx->ino);
+}
+#else
+static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
+{
+}
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
+
/**
* build_eval_ctx - Build an evaluation context.
* @ctx: Supplies a pointer to the context to be populdated.
@@ -100,6 +118,7 @@ void build_eval_ctx(struct ipe_eval_ctx *ctx,
ctx->from_init_sb = from_pinned(FILE_SUPERBLOCK(file));
ino = d_real_inode(file->f_path.dentry);
build_ipe_bdev_ctx(ctx, ino);
+ build_ipe_inode_ctx(ctx, ino);
}
}
@@ -172,6 +191,91 @@ static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx,
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+/**
+ * evaluate_fsv_digest - Analyze @ctx against a fsv digest property.
+ * @ctx: Supplies a pointer to the context being evaluated.
+ * @p: Supplies a pointer to the property being evaluated.
+ *
+ * Return:
+ * * true - The current @ctx match the @p
+ * * false - The current @ctx doesn't match the @p
+ */
+static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ enum hash_algo alg;
+ u8 digest[FS_VERITY_MAX_DIGEST_SIZE];
+
+ if (!ctx->ino)
+ return false;
+ if (!fsverity_get_digest((struct inode *)ctx->ino,
+ digest,
+ NULL,
+ &alg))
+ return false;
+
+ return ipe_digest_eval(p->value,
+ digest,
+ hash_digest_size[alg],
+ hash_algo_name[alg]);
+}
+
+/**
+ * evaluate_fsv_sig_false - Analyze @ctx against a fsv sig false property.
+ * @ctx: Supplies a pointer to the context being evaluated.
+ * @p: Supplies a pointer to the property being evaluated.
+ *
+ * Return:
+ * * true - The current @ctx match the @p
+ * * false - The current @ctx doesn't match the @p
+ */
+static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ return !ctx->ino ||
+ !IS_VERITY(ctx->ino) ||
+ !ctx->ipe_inode ||
+ !ctx->ipe_inode->fs_verity_signed;
+}
+
+/**
+ * evaluate_fsv_sig_true - Analyze @ctx against a fsv sig true property.
+ * @ctx: Supplies a pointer to the context being evaluated.
+ * @p: Supplies a pointer to the property being evaluated.
+ *
+ * Return:
+ * * true - The current @ctx match the @p
+ * * false - The current @ctx doesn't match the @p
+ */
+static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ return ctx->ino &&
+ IS_VERITY(ctx->ino) &&
+ ctx->ipe_inode &&
+ ctx->ipe_inode->fs_verity_signed;
+}
+#else
+static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ return false;
+}
+
+static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ return false;
+}
+
+static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx,
+ struct ipe_prop *p)
+{
+ return false;
+}
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
+
/**
* evaluate_property - Analyze @ctx against a property.
* @ctx: Supplies a pointer to the context to be evaluated.
@@ -195,6 +299,12 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
return evaluate_dmv_sig_false(ctx, p);
case IPE_PROP_DMV_SIG_TRUE:
return evaluate_dmv_sig_true(ctx, p);
+ case IPE_PROP_FSV_DIGEST:
+ return evaluate_fsv_digest(ctx, p);
+ case IPE_PROP_FSV_SIG_FALSE:
+ return evaluate_fsv_sig_false(ctx, p);
+ case IPE_PROP_FSV_SIG_TRUE:
+ return evaluate_fsv_sig_true(ctx, p);
default:
return false;
}
@@ -27,6 +27,12 @@ struct ipe_bdev {
};
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+struct ipe_inode {
+ bool fs_verity_signed;
+};
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
+
struct ipe_eval_ctx {
enum ipe_op_type op;
@@ -35,6 +41,10 @@ struct ipe_eval_ctx {
#ifdef CONFIG_IPE_PROP_DM_VERITY
const struct ipe_bdev *ipe_bdev;
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+ const struct inode *ino;
+ const struct ipe_inode *ipe_inode;
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
};
enum ipe_match {
@@ -244,3 +244,33 @@ int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
return -EOPNOTSUPP;
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+/**
+ * ipe_inode_setsecurity - Sets fields of a inode security blob from @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;
+}
+#endif /* CONFIG_CONFIG_IPE_PROP_FS_VERITY */
@@ -9,6 +9,7 @@
#include <linux/binfmts.h>
#include <linux/security.h>
#include <linux/blk_types.h>
+#include <linux/fsverity.h>
int ipe_bprm_check_security(struct linux_binprm *bprm);
@@ -32,4 +33,10 @@ int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
const void *value, size_t len);
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+int ipe_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size,
+ int flags);
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
+
#endif /* _IPE_HOOKS_H */
@@ -13,6 +13,9 @@ static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
#ifdef CONFIG_IPE_PROP_DM_VERITY
.lbs_bdev = sizeof(struct ipe_bdev),
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+ .lbs_inode = sizeof(struct ipe_inode),
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
};
#ifdef CONFIG_IPE_PROP_DM_VERITY
@@ -22,6 +25,13 @@ struct ipe_bdev *ipe_bdev(struct block_device *b)
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+struct ipe_inode *ipe_inode(const struct inode *inode)
+{
+ return inode->i_security + ipe_blobs.lbs_inode;
+}
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
+
static struct security_hook_list ipe_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security),
LSM_HOOK_INIT(mmap_file, ipe_mmap_file),
@@ -33,6 +43,9 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security),
LSM_HOOK_INIT(bdev_setsecurity, ipe_bdev_setsecurity),
#endif
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+ LSM_HOOK_INIT(inode_setsecurity, ipe_inode_setsecurity),
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
};
/**
@@ -18,5 +18,8 @@ extern bool ipe_enabled;
#ifdef CONFIG_IPE_PROP_DM_VERITY
struct ipe_bdev *ipe_bdev(struct block_device *b);
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+struct ipe_inode *ipe_inode(const struct inode *inode);
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
#endif /* _IPE_H */
@@ -36,6 +36,9 @@ enum ipe_prop_type {
IPE_PROP_DMV_ROOTHASH,
IPE_PROP_DMV_SIG_FALSE,
IPE_PROP_DMV_SIG_TRUE,
+ IPE_PROP_FSV_DIGEST,
+ IPE_PROP_FSV_SIG_FALSE,
+ IPE_PROP_FSV_SIG_TRUE,
__IPE_PROP_MAX
};
@@ -275,6 +275,11 @@ static const match_table_t property_tokens = {
{IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"},
{IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"},
#endif /* CONFIG_IPE_PROP_DM_VERITY */
+#ifdef CONFIG_IPE_PROP_FS_VERITY
+ {IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"},
+ {IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
+ {IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
+#endif /* CONFIG_IPE_PROP_FS_VERITY */
{IPE_PROP_INVALID, NULL}
};
@@ -304,6 +309,7 @@ static int parse_property(char *t, struct ipe_rule *r)
switch (token) {
case IPE_PROP_DMV_ROOTHASH:
+ case IPE_PROP_FSV_DIGEST:
dup = match_strdup(&args[0]);
if (!dup) {
rc = -ENOMEM;
@@ -317,6 +323,8 @@ static int parse_property(char *t, struct ipe_rule *r)
case IPE_PROP_BOOT_VERIFIED_TRUE:
case IPE_PROP_DMV_SIG_FALSE:
case IPE_PROP_DMV_SIG_TRUE:
+ case IPE_PROP_FSV_SIG_FALSE:
+ case IPE_PROP_FSV_SIG_TRUE:
p->type = token;
break;
default: