* [RESEND PATCH 01/11] scripts: add ipe tooling to generate boot policy
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 03/11] ipe: add property for trust of boot volume deven.desai
` (10 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a tool for the generation of an IPE policy to be compiled into the
kernel. This policy will be enforced until userland deploys and activates
a new policy.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
scripts/Makefile | 1 +
scripts/ipe/Makefile | 2 +
scripts/ipe/polgen/.gitignore | 1 +
scripts/ipe/polgen/Makefile | 7 ++
scripts/ipe/polgen/polgen.c | 136 ++++++++++++++++++++++++++++++++++
5 files changed, 147 insertions(+)
create mode 100644 scripts/ipe/Makefile
create mode 100644 scripts/ipe/polgen/.gitignore
create mode 100644 scripts/ipe/polgen/Makefile
create mode 100644 scripts/ipe/polgen/polgen.c
diff --git a/scripts/Makefile b/scripts/Makefile
index 5e75802b1a44..9338017a3b6e 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -38,6 +38,7 @@ hostprogs += unifdef
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
+subdir-$(CONFIG_SECURITY_IPE) += ipe
# Let clean descend into subdirs
subdir- += basic dtc gdb kconfig mod
diff --git a/scripts/ipe/Makefile b/scripts/ipe/Makefile
new file mode 100644
index 000000000000..e87553fbb8d6
--- /dev/null
+++ b/scripts/ipe/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+subdir-y := polgen
diff --git a/scripts/ipe/polgen/.gitignore b/scripts/ipe/polgen/.gitignore
new file mode 100644
index 000000000000..80f32f25d200
--- /dev/null
+++ b/scripts/ipe/polgen/.gitignore
@@ -0,0 +1 @@
+polgen
diff --git a/scripts/ipe/polgen/Makefile b/scripts/ipe/polgen/Makefile
new file mode 100644
index 000000000000..a519b594e13c
--- /dev/null
+++ b/scripts/ipe/polgen/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+hostprogs-y := polgen
+HOST_EXTRACFLAGS += \
+ -I$(srctree)/include \
+ -I$(srctree)/include/uapi \
+
+always := $(hostprogs-y)
diff --git a/scripts/ipe/polgen/polgen.c b/scripts/ipe/polgen/polgen.c
new file mode 100644
index 000000000000..a80fffe1b27c
--- /dev/null
+++ b/scripts/ipe/polgen/polgen.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+static void usage(const char *const name)
+{
+ printf("Usage: %s OutputFile (PolicyFile)\n", name);
+ exit(EINVAL);
+}
+
+static int policy_to_buffer(const char *pathname, char **buffer, size_t *size)
+{
+ int rc = 0;
+ FILE *fd;
+ char *lbuf;
+ size_t fsize;
+ size_t read;
+
+ fd = fopen(pathname, "r");
+ if (!fd) {
+ rc = errno;
+ goto out;
+ }
+
+ fseek(fd, 0, SEEK_END);
+ fsize = ftell(fd);
+ rewind(fd);
+
+ lbuf = malloc(fsize);
+ if (!lbuf) {
+ rc = ENOMEM;
+ goto out_close;
+ }
+
+ read = fread((void *)lbuf, sizeof(*lbuf), fsize, fd);
+ if (read != fsize) {
+ rc = -1;
+ goto out_free;
+ }
+
+ *buffer = lbuf;
+ *size = fsize;
+ fclose(fd);
+
+ return rc;
+
+out_free:
+ free(lbuf);
+out_close:
+ fclose(fd);
+out:
+ return rc;
+}
+
+static int write_boot_policy(const char *pathname, const char *buf, size_t size)
+{
+ FILE *fd;
+ size_t i;
+
+ fd = fopen(pathname, "w");
+ if (!fd)
+ goto err;
+
+ fprintf(fd, "/* This file is automatically generated.");
+ fprintf(fd, " Do not edit. */\n");
+ fprintf(fd, "#include <stddef.h>\n");
+ fprintf(fd, "const char *const ipe_boot_policy =\n");
+
+ if (!buf || size == 0) {
+ fprintf(fd, "\tNULL;\n");
+ fclose(fd);
+ return 0;
+ }
+
+ for (i = 0; i < size; ++i) {
+ if (i == 0)
+ fprintf(fd, "\t\"");
+
+ switch (buf[i]) {
+ case '"':
+ fprintf(fd, "\\\"");
+ break;
+ case '\'':
+ fprintf(fd, "'");
+ break;
+ case '\n':
+ fprintf(fd, "\\n\"\n\t\"");
+ break;
+ case '\\':
+ fprintf(fd, "\\\\");
+ break;
+ default:
+ fprintf(fd, "%c", buf[i]);
+ }
+ }
+ fprintf(fd, "\";\n");
+ fclose(fd);
+
+ return 0;
+
+err:
+ if (fd)
+ fclose(fd);
+ return errno;
+}
+
+int main(int argc, const char *argv[])
+{
+ int rc = 0;
+ size_t len = 0;
+ char *policy = NULL;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ if (argc > 2) {
+ rc = policy_to_buffer(argv[2], &policy, &len);
+ if (rc != 0)
+ goto cleanup;
+ }
+
+ rc = write_boot_policy(argv[1], policy, len);
+cleanup:
+ if (policy)
+ free(policy);
+ if (rc != 0)
+ perror("An error occurred during policy conversion: ");
+ return rc;
+}
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 03/11] ipe: add property for trust of boot volume
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
2020-04-06 18:10 ` [RESEND PATCH 01/11] scripts: add ipe tooling to generate boot policy deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 04/11] fs: add security blob and hooks for block_device deven.desai
` (9 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a property for IPE policy to express trust of the first superblock
where a file would be evaluated to determine trust.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
security/ipe/Kconfig | 2 +
security/ipe/Makefile | 4 ++
security/ipe/ipe-engine.c | 4 ++
security/ipe/ipe-hooks.c | 19 +++++
security/ipe/ipe-hooks.h | 2 +
security/ipe/ipe-pin.c | 93 +++++++++++++++++++++++++
security/ipe/ipe-pin.h | 56 +++++++++++++++
security/ipe/ipe.c | 14 +++-
security/ipe/properties/Kconfig | 14 ++++
security/ipe/properties/Makefile | 11 +++
security/ipe/properties/boot-verified.c | 84 ++++++++++++++++++++++
security/ipe/properties/prop-entry.h | 20 ++++++
security/ipe/utility.h | 22 ++++++
13 files changed, 344 insertions(+), 1 deletion(-)
create mode 100644 security/ipe/ipe-pin.c
create mode 100644 security/ipe/ipe-pin.h
create mode 100644 security/ipe/properties/Kconfig
create mode 100644 security/ipe/properties/Makefile
create mode 100644 security/ipe/properties/boot-verified.c
create mode 100644 security/ipe/properties/prop-entry.h
create mode 100644 security/ipe/utility.h
diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
index ef6fb019be6f..b1d89244da3e 100644
--- a/security/ipe/Kconfig
+++ b/security/ipe/Kconfig
@@ -38,4 +38,6 @@ config SECURITY_IPE_PERMISSIVE_SWITCH
If unsure, answer Y.
+source "security/ipe/properties/Kconfig"
+
endif
diff --git a/security/ipe/Makefile b/security/ipe/Makefile
index 4dcfc5b26b58..741914ddc338 100644
--- a/security/ipe/Makefile
+++ b/security/ipe/Makefile
@@ -27,3 +27,7 @@ obj-$(CONFIG_SECURITY_IPE) += \
ipe-sysfs.o \
clean-files := ipe-bp.c
+
+obj-$(CONFIG_IPE_BOOT_PROP) += ipe-pin.o
+
+obj-$(CONFIG_SECURITY_IPE) += properties/
diff --git a/security/ipe/ipe-engine.c b/security/ipe/ipe-engine.c
index 3e05fa911e71..a629ae3c882d 100644
--- a/security/ipe/ipe-engine.c
+++ b/security/ipe/ipe-engine.c
@@ -9,6 +9,8 @@
#include "ipe-policy.h"
#include "ipe-engine.h"
#include "ipe-audit.h"
+#include "ipe-pin.h"
+#include "utility.h"
#include <linux/types.h>
#include <linux/fs.h>
@@ -331,6 +333,8 @@ int ipe_process_event(const struct file *file, enum ipe_op op,
if (IS_ERR(ctx))
goto cleanup;
+ ipe_pin_superblock(ctx->file);
+
rc = prealloc_cache(ctx, &cache);
if (rc != 0)
goto cleanup;
diff --git a/security/ipe/ipe-hooks.c b/security/ipe/ipe-hooks.c
index a5d37b87c0cd..43182ba25cc5 100644
--- a/security/ipe/ipe-hooks.c
+++ b/security/ipe/ipe-hooks.c
@@ -6,6 +6,7 @@
#include "ipe.h"
#include "ipe-hooks.h"
#include "ipe-engine.h"
+#include "ipe-pin.h"
#include <linux/types.h>
#include <linux/fs.h>
@@ -149,3 +150,21 @@ int ipe_on_kernel_load_data(enum kernel_load_data_id id)
ipe_hook_kernel_load);
}
}
+
+/**
+ * ipe_sb_free_security: LSM hook called on sb_free_security.
+ * @mnt_sb: Super block that is being freed.
+ *
+ * IPE does not currently utilize the super block security hook,
+ * it utilizes this hook to invalidate the saved super block for
+ * the boot_verified property.
+ *
+ * For more information, see the LSM hook, sb_free_security.
+ *
+ * Return:
+ * 0 - OK
+ */
+void ipe_sb_free_security(struct super_block *mnt_sb)
+{
+ ipe_invalidate_pinned_sb(mnt_sb);
+}
diff --git a/security/ipe/ipe-hooks.h b/security/ipe/ipe-hooks.h
index 6af706a130ce..55e417c72425 100644
--- a/security/ipe/ipe-hooks.h
+++ b/security/ipe/ipe-hooks.h
@@ -111,4 +111,6 @@ int ipe_on_kernel_read(struct file *file, enum kernel_read_file_id id);
*/
int ipe_on_kernel_load_data(enum kernel_load_data_id id);
+void ipe_sb_free_security(struct super_block *mnt_sb);
+
#endif /* IPE_HOOK_H */
diff --git a/security/ipe/ipe-pin.c b/security/ipe/ipe-pin.c
new file mode 100644
index 000000000000..a963be8e5321
--- /dev/null
+++ b/security/ipe/ipe-pin.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file has been heavily adapted from the source code of the
+ * loadpin LSM. The source code for loadpin is co-located in the linux
+ * tree under security/loadpin/loadpin.c.
+ *
+ * Please see loadpin.c for up-to-date information about
+ * loadpin.
+ */
+
+#include "ipe.h"
+
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/magic.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+
+static DEFINE_SPINLOCK(pinned_sb_spinlock);
+
+static struct super_block *pinned_sb;
+
+/**
+ * ipe_is_from_pinned_sb: Determine if @file originates from the initial
+ * super block that a file was executed from.
+ * @file: File to check if it originates from the super block.
+ *
+ * Return:
+ * true - File originates from the initial super block
+ * false - File does not originate from the initial super block
+ */
+bool ipe_is_from_pinned_sb(const struct file *file)
+{
+ bool rv = false;
+
+ spin_lock(&pinned_sb_spinlock);
+
+ /*
+ * Check if pinned_sb is set:
+ * NULL == not set -> exit
+ * ERR == was once set (and has been unmounted) -> exit
+ * AND check that the pinned sb is the same as the file's.
+ */
+ if (!IS_ERR_OR_NULL(pinned_sb) &&
+ file->f_path.mnt->mnt_sb == pinned_sb) {
+ rv = true;
+ goto cleanup;
+ }
+
+cleanup:
+ spin_unlock(&pinned_sb_spinlock);
+ return rv;
+}
+
+/**
+ * ipe_pin_superblock: Attempt to save a file's super block address to later
+ * determine if a file originates from a super block.
+ * @file: File to source the super block from.
+ */
+void ipe_pin_superblock(const struct file *file)
+{
+ spin_lock(&pinned_sb_spinlock);
+
+ /* if set, return */
+ if (pinned_sb || !file)
+ goto cleanup;
+
+ pinned_sb = file->f_path.mnt->mnt_sb;
+cleanup:
+ spin_unlock(&pinned_sb_spinlock);
+}
+
+/**
+ * ipe_invalidate_pinned_sb: Invalidate the saved super block.
+ * @mnt_sb: Super block to compare against the saved super block.
+ *
+ * This avoids authorizing a file when the super block does not exist anymore.
+ */
+void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb)
+{
+ spin_lock(&pinned_sb_spinlock);
+
+ /*
+ * On pinned sb unload - invalidate the pinned address
+ * by setting the pinned_sb to ERR_PTR(-EIO)
+ */
+ if (!IS_ERR_OR_NULL(pinned_sb) && mnt_sb == pinned_sb)
+ pinned_sb = ERR_PTR(-EIO);
+
+ spin_unlock(&pinned_sb_spinlock);
+}
diff --git a/security/ipe/ipe-pin.h b/security/ipe/ipe-pin.h
new file mode 100644
index 000000000000..7c3773d8387d
--- /dev/null
+++ b/security/ipe/ipe-pin.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+#ifndef IPE_PIN_H
+#define IPE_PIN_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#ifdef CONFIG_IPE_BOOT_PROP
+
+/**
+ * ipe_is_from_pinned_sb: Determine if @file originates from the initial
+ * super block that a file was executed from.
+ * @file: File to check if it originates from the super block.
+ *
+ * Return:
+ * true - File originates from the initial super block
+ * false - File does not originate from the initial super block
+ */
+bool ipe_is_from_pinned_sb(const struct file *file);
+
+/**
+ * ipe_pin_superblock: Attempt to save a file's super block address to later
+ * determine if a file originates from a super block.
+ * @file: File to source the super block from.
+ */
+void ipe_pin_superblock(const struct file *file);
+
+/**
+ * ipe_invalidate_pinned_sb: Invalidate the saved super block.
+ * @mnt_sb: Super block to compare against the saved super block.
+ *
+ * This avoids authorizing a file when the super block does not exist anymore.
+ */
+void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb);
+
+#else /* CONFIG_IPE_BOOT_PROP */
+
+static inline bool ipe_is_from_pinned_sb(const struct file *file)
+{
+ return false;
+}
+
+static inline void ipe_pin_superblock(const struct file *file)
+{
+}
+
+static inline void ipe_invalidate_pinned_sb(const struct super_block *mnt_sb)
+{
+}
+
+#endif /* !CONFIG_IPE_BOOT_PROP */
+
+#endif /* IPE_PIN_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4642a0da57e5..971c50ecadaf 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -8,6 +8,7 @@
#include "ipe-hooks.h"
#include "ipe-secfs.h"
#include "ipe-sysfs.h"
+#include "properties/prop-entry.h"
#include <linux/module.h>
#include <linux/lsm_hooks.h>
@@ -23,6 +24,7 @@ static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(kernel_read_file, ipe_on_kernel_read),
LSM_HOOK_INIT(kernel_load_data, ipe_on_kernel_load_data),
LSM_HOOK_INIT(file_mprotect, ipe_on_mprotect),
+ LSM_HOOK_INIT(sb_free_security, ipe_sb_free_security),
};
/**
@@ -34,7 +36,13 @@ static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = {
*/
static int __init ipe_load_properties(void)
{
- return 0;
+ int rc = 0;
+
+ rc = ipe_init_bootv();
+ if (rc != 0)
+ return rc;
+
+ return rc;
}
/**
@@ -54,6 +62,10 @@ static int __init ipe_init(void)
{
int rc = 0;
+ rc = ipe_load_properties();
+ if (rc != 0)
+ panic("IPE: properties failed to load");
+
rc = ipe_sysctl_init();
if (rc != 0)
pr_err("failed to configure sysctl: %d", -rc);
diff --git a/security/ipe/properties/Kconfig b/security/ipe/properties/Kconfig
new file mode 100644
index 000000000000..9dc0db8817b2
--- /dev/null
+++ b/security/ipe/properties/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Integrity Policy Enforcement (IPE) configuration
+#
+
+config IPE_BOOT_PROP
+ bool "Enable trust for boot volume"
+ help
+ This option enables the property "boot_verified" in IPE policy.
+ This property 'pins' the initial superblock when something is
+ evaluated. This property will evaluate to true when the file
+ being evaluated originates from the initial superblock.
+
+ if unsure, answer N.
diff --git a/security/ipe/properties/Makefile b/security/ipe/properties/Makefile
new file mode 100644
index 000000000000..e3e7fe17cf58
--- /dev/null
+++ b/security/ipe/properties/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) Microsoft Corporation. All rights reserved.
+#
+# Makefile for building the properties that IPE uses
+# as part of the kernel tree.
+#
+
+obj-$(CONFIG_SECURITY_IPE) += properties.o
+
+properties-$(CONFIG_IPE_BOOT_PROP) += boot-verified.o
diff --git a/security/ipe/properties/boot-verified.c b/security/ipe/properties/boot-verified.c
new file mode 100644
index 000000000000..07c8ba768ac5
--- /dev/null
+++ b/security/ipe/properties/boot-verified.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "../ipe.h"
+#include "../ipe-pin.h"
+#include "../ipe-property.h"
+#include "../utility.h"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/audit.h>
+
+#define PROPERTY_NAME "boot_verified"
+
+static void audit(struct audit_buffer *ab, bool value)
+{
+ audit_log_format(ab, "%s", (value) ? "TRUE" : "FALSE");
+}
+
+static inline void audit_rule_value(struct audit_buffer *ab,
+ const void *value)
+{
+ audit(ab, (bool)value);
+}
+
+static inline void audit_ctx(struct audit_buffer *ab,
+ const struct ipe_engine_ctx *ctx,
+ const void *storage)
+{
+ bool b = has_sb(ctx->file) && ipe_is_from_pinned_sb(ctx->file);
+
+ audit(ab, b);
+}
+
+static bool evaluate(const struct ipe_engine_ctx *ctx,
+ const void *value, void **storage)
+{
+ bool expect = (bool)value;
+
+ if (!ctx->file || !has_sb(ctx->file))
+ return false;
+
+ return ipe_is_from_pinned_sb(ctx->file) == expect;
+}
+
+static int parse(const char *val_str, void **value)
+{
+ if (strcmp("TRUE", val_str) == 0)
+ *value = (void *)true;
+ else if (strcmp("FALSE", val_str) == 0)
+ *value = (void *)false;
+ else
+ return -EBADMSG;
+
+ return 0;
+}
+
+static inline int duplicate(const void *src, void **dest)
+{
+ *dest = (void *)(bool)src;
+
+ return 0;
+}
+
+static const struct ipe_property boot_verified = {
+ .property_name = PROPERTY_NAME,
+ .eval = evaluate,
+ .rule_audit = audit_rule_value,
+ .ctx_audit = audit_ctx,
+ .parse = parse,
+ .dup = duplicate,
+ .prealloc = NULL,
+ .free_val = NULL,
+ .free_storage = NULL,
+};
+
+int ipe_init_bootv(void)
+{
+ return ipe_register_property(&boot_verified);
+}
diff --git a/security/ipe/properties/prop-entry.h b/security/ipe/properties/prop-entry.h
new file mode 100644
index 000000000000..f598dd9608b9
--- /dev/null
+++ b/security/ipe/properties/prop-entry.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include <linux/types.h>
+
+#ifndef IPE_PROP_ENTRY_H
+#define IPE_PROP_ENTRY_H
+
+#ifndef CONFIG_IPE_BOOT_PROP
+static inline int __init ipe_init_bootv(void)
+{
+ return 0;
+}
+#else
+int __init ipe_init_bootv(void);
+#endif /* CONFIG_IPE_BOOT_PROP */
+
+#endif /* IPE_PROP_ENTRY_H */
diff --git a/security/ipe/utility.h b/security/ipe/utility.h
new file mode 100644
index 000000000000..a13089bb0d8f
--- /dev/null
+++ b/security/ipe/utility.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#ifndef IPE_UTILITY_H
+#define IPE_UTILITY_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+static inline bool has_mount(const struct file *file)
+{
+ return file && file->f_path.mnt;
+}
+
+static inline bool has_sb(const struct file *file)
+{
+ return has_mount(file) && file->f_path.mnt->mnt_sb;
+}
+
+#endif /* IPE_UTILITY_H */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 04/11] fs: add security blob and hooks for block_device
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
2020-04-06 18:10 ` [RESEND PATCH 01/11] scripts: add ipe tooling to generate boot policy deven.desai
2020-04-06 18:10 ` [RESEND PATCH 03/11] ipe: add property for trust of boot volume deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 05/11] dm-verity: move signature check after tree validation deven.desai
` (8 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a security blob and associated allocation, deallocation and set hooks
for a block_device structure.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
fs/block_dev.c | 8 +++++
include/linux/fs.h | 1 +
include/linux/lsm_hook_defs.h | 5 +++
include/linux/lsm_hooks.h | 11 +++++++
include/linux/security.h | 22 +++++++++++++
security/security.c | 61 +++++++++++++++++++++++++++++++++++
6 files changed, 108 insertions(+)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 52b6f646cdbd..5dfa25f03208 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -35,6 +35,7 @@
#include <linux/falloc.h>
#include <linux/uaccess.h>
#include <linux/suspend.h>
+#include <linux/security.h>
#include "internal.h"
struct bdev_inode {
@@ -773,11 +774,18 @@ static struct inode *bdev_alloc_inode(struct super_block *sb)
struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL);
if (!ei)
return NULL;
+
+ if (unlikely(security_bdev_alloc(&ei->bdev))) {
+ kmem_cache_free(bdev_cachep, ei);
+ return NULL;
+ }
+
return &ei->vfs_inode;
}
static void bdev_free_inode(struct inode *inode)
{
+ security_bdev_free(&BDEV_I(inode)->bdev);
kmem_cache_free(bdev_cachep, BDEV_I(inode));
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f81c822f4d89..03d089f4a511 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -506,6 +506,7 @@ struct block_device {
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
+ void *security;
} __randomize_layout;
/* XArray tags, for tagging dirty and writeback pages in the pagecache. */
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 9cd4455528e5..4782fef7eaf9 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -379,3 +379,8 @@ LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
LSM_HOOK(int, 0, perf_event_read, struct perf_event *event)
LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
#endif /* CONFIG_PERF_EVENTS */
+
+LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev)
+LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev)
+LSM_HOOK(int, 0, bdev_setsecurity, struct block_device *bdev, const char *name,
+ const void *value, size_t size)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 988ca0df7824..7bf0f82bc5d6 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1476,6 +1476,16 @@
*
* @what: kernel feature being accessed
*
+ * @bdev_alloc_security:
+ * Initialize the security field inside a block_device structure.
+ *
+ * @bdev_free_security:
+ * Cleanup the security information stored inside a block_device structure.
+ *
+ * @bdev_setsecurity:
+ * Set the security property associated with @name for @bdev with
+ * value @value. @size indicates the size of the @value in bytes.
+ *
* Security hooks for perf events
*
* @perf_event_open:
@@ -1522,6 +1532,7 @@ struct lsm_blob_sizes {
int lbs_ipc;
int lbs_msg_msg;
int lbs_task;
+ int lbs_bdev;
};
/*
diff --git a/include/linux/security.h b/include/linux/security.h
index a8d9310472df..714eecc82e08 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -446,6 +446,11 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
int security_locked_down(enum lockdown_reason what);
+int security_bdev_alloc(struct block_device *bdev);
+void security_bdev_free(struct block_device *bdev);
+int security_bdev_setsecurity(struct block_device *bdev,
+ const char *name, const void *value,
+ size_t size);
#else /* CONFIG_SECURITY */
static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
@@ -1273,6 +1278,23 @@ static inline int security_locked_down(enum lockdown_reason what)
{
return 0;
}
+
+static inline int security_bdev_alloc(struct block_device *bdev)
+{
+ return 0;
+}
+
+static inline void security_bdev_free(struct block_device *bdev)
+{
+}
+
+static inline int security_bdev_setsecurity(struct block_device *bdev,
+ const char *name,
+ const void *value, size_t size)
+{
+ return 0;
+}
+
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/security.c b/security/security.c
index 7fed24b9d57e..0d1af27711c1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -28,6 +28,7 @@
#include <linux/string.h>
#include <linux/msg.h>
#include <net/flow.h>
+#include <linux/fs.h>
#define MAX_LSM_EVM_XATTR 2
@@ -202,6 +203,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+ lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
}
/* Prepare LSM for initialization. */
@@ -337,6 +339,7 @@ static void __init ordered_lsm_init(void)
init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+ init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
/*
* Create any kmem_caches needed for blobs
@@ -654,6 +657,28 @@ static int lsm_msg_msg_alloc(struct msg_msg *mp)
return 0;
}
+/**
+ * lsm_bdev_alloc - allocate a composite block_device blob
+ * @bdev: the block_device that needs a blob
+ *
+ * Allocate the block_device blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_bdev_alloc(struct block_device *bdev)
+{
+ if (blob_sizes.lbs_bdev == 0) {
+ bdev->security = NULL;
+ return 0;
+ }
+
+ bdev->security = kzalloc(blob_sizes.lbs_bdev, GFP_KERNEL);
+ if (!bdev->security)
+ return -ENOMEM;
+
+ return 0;
+}
+
/**
* lsm_early_task - during initialization allocate a composite task blob
* @task: the task that needs a blob
@@ -2456,6 +2481,42 @@ int security_locked_down(enum lockdown_reason what)
}
EXPORT_SYMBOL(security_locked_down);
+int security_bdev_alloc(struct block_device *bdev)
+{
+ int rc = 0;
+
+ rc = lsm_bdev_alloc(bdev);
+ if (unlikely(rc))
+ return rc;
+
+ rc = call_int_hook(bdev_alloc_security, 0, bdev);
+ if (unlikely(rc))
+ security_bdev_free(bdev);
+
+ return 0;
+}
+EXPORT_SYMBOL(security_bdev_alloc);
+
+void security_bdev_free(struct block_device *bdev)
+{
+ if (!bdev->security)
+ return;
+
+ call_void_hook(bdev_free_security, bdev);
+
+ kfree(bdev->security);
+ bdev->security = NULL;
+}
+EXPORT_SYMBOL(security_bdev_free);
+
+int security_bdev_setsecurity(struct block_device *bdev,
+ const char *name, const void *value,
+ size_t size)
+{
+ return call_int_hook(bdev_setsecurity, 0, bdev, name, value, size);
+}
+EXPORT_SYMBOL(security_bdev_setsecurity);
+
#ifdef CONFIG_PERF_EVENTS
int security_perf_event_open(struct perf_event_attr *attr, int type)
{
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 05/11] dm-verity: move signature check after tree validation
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (2 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 04/11] fs: add security blob and hooks for block_device deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 06/11] dm-verity: add bdev_setsecurity hook for dm-verity signature deven.desai
` (7 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
The CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG introduced by Jaskaran was
intended to be used to allow an LSM to enforce verifications for all
dm-verity volumes.
However, with it's current implementation, this signature verification
occurs after the merkel-tree is validated, as a result the signature can
pass initial verification by passing a matching root-hash and signature.
This results in an unreadable block_device, but that has passed signature
validation (and subsequently, would be marked as verified).
This change moves the signature verification to after the merkel-tree has
finished validation.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
drivers/md/dm-verity-target.c | 42 ++++-----
drivers/md/dm-verity-verify-sig.c | 140 ++++++++++++++++++++++--------
drivers/md/dm-verity-verify-sig.h | 20 ++---
drivers/md/dm-verity.h | 2 +-
4 files changed, 132 insertions(+), 72 deletions(-)
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index eec9f252e935..c507f3a4e237 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -471,9 +471,9 @@ static int verity_verify_io(struct dm_verity_io *io)
struct bvec_iter start;
unsigned b;
struct crypto_wait wait;
+ int r;
for (b = 0; b < io->n_blocks; b++) {
- int r;
sector_t cur_block = io->block + b;
struct ahash_request *req = verity_io_hash_req(v, io);
@@ -530,6 +530,16 @@ static int verity_verify_io(struct dm_verity_io *io)
return -EIO;
}
+ /*
+ * At this point, the merkel tree has finished validating.
+ * if signature was specified, validate the signature here.
+ */
+ r = verity_verify_root_hash(v);
+ if (r < 0) {
+ DMERR_LIMIT("signature mismatch");
+ return r;
+ }
+
return 0;
}
@@ -728,7 +738,7 @@ static void verity_status(struct dm_target *ti, status_type_t type,
args++;
if (v->validated_blocks)
args++;
- if (v->signature_key_desc)
+ if (v->sig)
args += DM_VERITY_ROOT_HASH_VERIFICATION_OPTS;
if (!args)
return;
@@ -751,9 +761,9 @@ static void verity_status(struct dm_target *ti, status_type_t type,
if (v->validated_blocks)
DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
sz = verity_fec_status_table(v, sz, result, maxlen);
- if (v->signature_key_desc)
+ if (v->sig)
DMEMIT(" " DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY
- " %s", v->signature_key_desc);
+ " %s", v->sig->signature_key_desc);
break;
}
}
@@ -819,7 +829,7 @@ static void verity_dtr(struct dm_target *ti)
verity_fec_dtr(v);
- kfree(v->signature_key_desc);
+ verity_verify_dtr(v);
kfree(v);
}
@@ -876,8 +886,7 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
return r;
}
-static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
- struct dm_verity_sig_opts *verify_args)
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
{
int r;
unsigned argc;
@@ -927,9 +936,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
return r;
continue;
} else if (verity_verify_is_sig_opt_arg(arg_name)) {
- r = verity_verify_sig_parse_opt_args(as, v,
- verify_args,
- &argc, arg_name);
+ r = verity_verify_sig_parse_opt_args(as, v, &argc);
if (r)
return r;
continue;
@@ -960,7 +967,6 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
struct dm_verity *v;
- struct dm_verity_sig_opts verify_args = {0};
struct dm_arg_set as;
unsigned int num;
unsigned long long num_ll;
@@ -1128,20 +1134,11 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
as.argc = argc;
as.argv = argv;
- r = verity_parse_opt_args(&as, v, &verify_args);
+ r = verity_parse_opt_args(&as, v);
if (r < 0)
goto bad;
}
- /* Root hash signature is a optional parameter*/
- r = verity_verify_root_hash(root_hash_digest_to_validate,
- strlen(root_hash_digest_to_validate),
- verify_args.sig,
- verify_args.sig_size);
- if (r < 0) {
- ti->error = "Root hash verification failed";
- goto bad;
- }
v->hash_per_block_bits =
__fls((1 << v->hash_dev_block_bits) / v->digest_size);
@@ -1207,13 +1204,10 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->per_io_data_size = roundup(ti->per_io_data_size,
__alignof__(struct dm_verity_io));
- verity_verify_sig_opts_cleanup(&verify_args);
-
return 0;
bad:
- verity_verify_sig_opts_cleanup(&verify_args);
verity_dtr(ti);
return r;
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
index 614e43db93aa..27dac8aa2e5a 100644
--- a/drivers/md/dm-verity-verify-sig.c
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -22,6 +22,16 @@ MODULE_PARM_DESC(require_signatures,
#define DM_VERITY_IS_SIG_FORCE_ENABLED() \
(require_signatures != false)
+static void destroy_verity_sig(struct dm_verity_sig *sig_info)
+{
+ if (!sig_info)
+ return;
+
+ kfree(sig_info->sig);
+ kfree(sig_info->signature_key_desc);
+ kfree(sig_info);
+}
+
bool verity_verify_is_sig_opt_arg(const char *arg_name)
{
return (!strcasecmp(arg_name,
@@ -29,7 +39,7 @@ bool verity_verify_is_sig_opt_arg(const char *arg_name)
}
static int verity_verify_get_sig_from_key(const char *key_desc,
- struct dm_verity_sig_opts *sig_opts)
+ struct dm_verity_sig *sig_info)
{
struct key *key;
const struct user_key_payload *ukp;
@@ -48,14 +58,14 @@ static int verity_verify_get_sig_from_key(const char *key_desc,
goto end;
}
- sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL);
- if (!sig_opts->sig) {
+ sig_info->sig = kmalloc(ukp->datalen, GFP_KERNEL);
+ if (!sig_info->sig) {
ret = -ENOMEM;
goto end;
}
- sig_opts->sig_size = ukp->datalen;
+ sig_info->sig_size = ukp->datalen;
- memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size);
+ memcpy(sig_info->sig, ukp->data, sig_info->sig_size);
end:
up_read(&key->sem);
@@ -64,70 +74,128 @@ static int verity_verify_get_sig_from_key(const char *key_desc,
return ret;
}
+/**
+ * Parse any signature verification arguments.
+ * This function will populate v->sig, it is the caller's
+ * responsibility to free this structure via verity_verify_dtr
+ *
+ * @as: argument set passed in to parse
+ * @v: verity context structure. Should have a NULL v->sig member.
+ * @argc: current argument number
+ */
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
struct dm_verity *v,
- struct dm_verity_sig_opts *sig_opts,
- unsigned int *argc,
- const char *arg_name)
+ unsigned int *argc)
{
struct dm_target *ti = v->ti;
+ struct dm_verity_sig *sig_info = NULL;
int ret = 0;
const char *sig_key = NULL;
if (!*argc) {
ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified");
- return -EINVAL;
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ sig_info = kzalloc(sizeof(*sig_info), GFP_KERNEL);
+ if (!sig_info) {
+ ret = -ENOMEM;
+ goto cleanup;
}
sig_key = dm_shift_arg(as);
(*argc)--;
- ret = verity_verify_get_sig_from_key(sig_key, sig_opts);
- if (ret < 0)
+ ret = verity_verify_get_sig_from_key(sig_key, sig_info);
+ if (ret < 0) {
ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified");
+ goto cleanup;
+ }
- v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL);
- if (!v->signature_key_desc)
- return -ENOMEM;
+ sig_info->signature_key_desc = kstrdup(sig_key, GFP_KERNEL);
+ if (!sig_info->signature_key_desc) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ v->sig = sig_info;
+ sig_info = NULL;
+cleanup:
+ if (sig_info)
+ destroy_verity_sig(sig_info);
return ret;
}
-/*
+/**
* verify_verify_roothash - Verify the root hash of the verity hash device
* using builtin trusted keys.
*
- * @root_hash: For verity, the roothash/data to be verified.
- * @root_hash_len: Size of the roothash/data to be verified.
- * @sig_data: The trusted signature that verifies the roothash/data.
- * @sig_len: Size of the signature.
+ * @v: dm_verity structure containing all context for the dm_verity
+ * operation.
*
*/
-int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
- const void *sig_data, size_t sig_len)
+int verity_verify_root_hash(const struct dm_verity *v)
{
- int ret;
+ int ret = 0;
+ char *root_hash = NULL;
+ size_t root_hash_size = 0;
+ struct dm_verity_sig *sig_target = NULL;
+
+ if (!v || !v->ti || !v->root_digest || v->digest_size == 0) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ sig_target = v->sig;
+
+ if (!sig_target || !sig_target->sig || sig_target->sig_size == 0) {
+ if (DM_VERITY_IS_SIG_FORCE_ENABLED()) {
+ ret = -ENOKEY;
+ goto cleanup;
+ } else {
+ goto cleanup;
+ }
+ }
- if (!root_hash || root_hash_len == 0)
- return -EINVAL;
+ /*
+ * If signature has passed validation once, assume
+ * that future signatures will pass.
+ */
+ if (sig_target->passed)
+ goto cleanup;
- if (!sig_data || sig_len == 0) {
- if (DM_VERITY_IS_SIG_FORCE_ENABLED())
- return -ENOKEY;
- else
- return 0;
+ root_hash_size = v->digest_size * 2;
+ root_hash = kzalloc(root_hash_size, GFP_KERNEL);
+ if (!root_hash) {
+ ret = -ENOMEM;
+ goto cleanup;
}
- ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
- sig_len, NULL, VERIFYING_UNSPECIFIED_SIGNATURE,
- NULL, NULL);
+ bin2hex(root_hash, v->root_digest, v->digest_size);
+
+ ret = verify_pkcs7_signature(root_hash, root_hash_size, v->sig->sig,
+ v->sig->sig_size, NULL,
+ VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
+ NULL);
+ if (ret != 0)
+ goto cleanup;
+ sig_target->passed = true;
+cleanup:
+ kfree(root_hash);
return ret;
}
-void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
+/**
+ * Performs destruction / cleanup of a valid dm_verity_sig struct
+ *
+ * @v: dm_verity structure containing the dm_verity_sig struct to
+ * be freed.
+ */
+
+void verity_verify_dtr(struct dm_verity *v)
{
- kfree(sig_opts->sig);
- sig_opts->sig = NULL;
- sig_opts->sig_size = 0;
+ destroy_verity_sig(v->sig);
+ v->sig = NULL;
}
diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
index 19b1547aa741..9d7b34672c80 100644
--- a/drivers/md/dm-verity-verify-sig.h
+++ b/drivers/md/dm-verity-verify-sig.h
@@ -11,31 +11,30 @@
#define DM_VERITY_ROOT_HASH_VERIFICATION "DM Verity Sig Verification"
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY "root_hash_sig_key_desc"
-struct dm_verity_sig_opts {
+struct dm_verity_sig {
+ char *signature_key_desc;
unsigned int sig_size;
u8 *sig;
+ bool passed;
};
#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 2
-int verity_verify_root_hash(const void *data, size_t data_len,
- const void *sig_data, size_t sig_len);
+int verity_verify_root_hash(const struct dm_verity *v);
bool verity_verify_is_sig_opt_arg(const char *arg_name);
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
- struct dm_verity_sig_opts *sig_opts,
- unsigned int *argc, const char *arg_name);
+ unsigned int *argc);
-void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts);
+void verity_verify_dtr(struct dm_verity *v);
#else
#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 0
-int verity_verify_root_hash(const void *data, size_t data_len,
- const void *sig_data, size_t sig_len)
+int verity_verify_root_hash(const struct dm_verity *v);
{
return 0;
}
@@ -46,13 +45,12 @@ bool verity_verify_is_sig_opt_arg(const char *arg_name)
}
int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
- struct dm_verity_sig_opts *sig_opts,
- unsigned int *argc, const char *arg_name)
+ unsigned int *argc)
{
return -EINVAL;
}
-void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
+void verity_verify_dtr(struct dm_verity *v)
{
}
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 641b9e3a399b..995c495decad 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -64,7 +64,7 @@ struct dm_verity {
struct dm_verity_fec *fec; /* forward error correction */
unsigned long *validated_blocks; /* bitset blocks validated */
- char *signature_key_desc; /* signature keyring reference */
+ struct dm_verity_sig *sig; /* signature verification */
};
struct dm_verity_io {
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 06/11] dm-verity: add bdev_setsecurity hook for dm-verity signature
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (3 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 05/11] dm-verity: move signature check after tree validation deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 07/11] ipe: add property for signed dmverity volumes deven.desai
` (6 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a security hook call to set a security property of a block_device
in dm-verity with the results of a verified, signed root-hash.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
drivers/md/dm-verity-verify-sig.c | 7 +++++++
include/linux/device-mapper.h | 2 ++
2 files changed, 9 insertions(+)
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
index 27dac8aa2e5a..242e2421d3c8 100644
--- a/drivers/md/dm-verity-verify-sig.c
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -8,7 +8,10 @@
#include <linux/device-mapper.h>
#include <linux/verification.h>
#include <keys/user-type.h>
+#include <linux/security.h>
+#include <linux/list.h>
#include <linux/module.h>
+#include "dm-core.h"
#include "dm-verity.h"
#include "dm-verity-verify-sig.h"
@@ -182,6 +185,10 @@ int verity_verify_root_hash(const struct dm_verity *v)
goto cleanup;
sig_target->passed = true;
+
+ ret = security_bdev_setsecurity(dm_table_get_md(v->ti->table)->bdev,
+ DM_VERITY_SIGNATURE_SEC_NAME,
+ v->sig->sig, v->sig->sig_size);
cleanup:
kfree(root_hash);
return ret;
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 475668c69dbc..6bd49aa48186 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -624,4 +624,6 @@ static inline unsigned long to_bytes(sector_t n)
return (n << SECTOR_SHIFT);
}
+#define DM_VERITY_SIGNATURE_SEC_NAME DM_NAME ".verity-sig"
+
#endif /* _LINUX_DEVICE_MAPPER_H */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 07/11] ipe: add property for signed dmverity volumes
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (4 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 06/11] dm-verity: add bdev_setsecurity hook for dm-verity signature deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 08/11] dm-verity: add bdev_setsecurity hook for root-hash deven.desai
` (5 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Allow IPE to leverage the stacked security blob infrastructure,
and enlighten IPE to the block_device security blob.
This allows IPE to have a property to express rules around a device-mapper
verity volume whose root-hash has been signed, and the signature has been
verified against the system keyring. This is property is also added in
this patch.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
security/ipe/Kconfig | 2 +-
security/ipe/Makefile | 1 +
security/ipe/ipe-blobs.c | 80 +++++++++++++++++++
security/ipe/ipe-blobs.h | 18 +++++
security/ipe/ipe-engine.c | 4 +
security/ipe/ipe-engine.h | 9 +++
security/ipe/ipe-hooks.c | 1 +
security/ipe/ipe-hooks.h | 43 ++++++++++
security/ipe/ipe.c | 18 +++++
security/ipe/ipe.h | 2 +
security/ipe/properties/Kconfig | 10 +++
security/ipe/properties/Makefile | 1 +
security/ipe/properties/dmverity-signature.c | 84 ++++++++++++++++++++
security/ipe/properties/prop-entry.h | 9 +++
security/ipe/utility.h | 10 +++
15 files changed, 291 insertions(+), 1 deletion(-)
create mode 100644 security/ipe/ipe-blobs.c
create mode 100644 security/ipe/ipe-blobs.h
create mode 100644 security/ipe/properties/dmverity-signature.c
diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
index b1d89244da3e..2c3012a6047b 100644
--- a/security/ipe/Kconfig
+++ b/security/ipe/Kconfig
@@ -5,7 +5,7 @@
menuconfig SECURITY_IPE
bool "Integrity Policy Enforcement (IPE)"
- depends on SECURITY && AUDIT && SECURITYFS
+ depends on SECURITY && AUDIT && SECURITYFS && BLOCK
select SYSTEM_DATA_VERIFICATION
help
This option enables the Integrity Policy Enforcement subsystem,
diff --git a/security/ipe/Makefile b/security/ipe/Makefile
index 741914ddc338..615797f4cd38 100644
--- a/security/ipe/Makefile
+++ b/security/ipe/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SECURITY_IPE) += \
ipe-hooks.o \
ipe-secfs.o \
ipe-sysfs.o \
+ ipe-blobs.o \
clean-files := ipe-bp.c
diff --git a/security/ipe/ipe-blobs.c b/security/ipe/ipe-blobs.c
new file mode 100644
index 000000000000..a4ee8df02855
--- /dev/null
+++ b/security/ipe/ipe-blobs.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "ipe.h"
+#include "ipe-engine.h"
+#include "ipe-blobs.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/device-mapper.h>
+
+/**
+ * ipe_bdev_alloc_security: Performs the initialization of IPE's security blob.
+ * @bdev: The block device to source the security blob from.
+ *
+ * The allocation is performed earlier by the LSM infrastructure,
+ * (on behalf of all LSMs) in lsm_alloc_bdev. At the moment, IPE uses
+ * this time to zero out the region of memory reserved for IPE.
+ *
+ * Return:
+ * 0 - OK
+ */
+int ipe_bdev_alloc_security(struct block_device *bdev)
+{
+ struct ipe_bdev_blob *bdev_sec = ipe_bdev(bdev);
+
+ memset(bdev_sec, 0x0, sizeof(*bdev_sec));
+
+ return 0;
+}
+
+/**
+ * ipe_bdev_free_security: Frees all fields of IPE's block dev security blob.
+ * @bdev: The block device to source the security blob from.
+ *
+ * The deallocation of the blob itself is performed later by the LSM
+ * infrastructure, (on behalf of all LSMs) in lsm_free_bdev.
+ *
+ * Pointers allocated by the bdev_setsecurity hook and alloc_security
+ * hook need to be deallocated here.
+ */
+void ipe_bdev_free_security(struct block_device *bdev)
+{
+ struct ipe_bdev_blob *bdev_sec = ipe_bdev(bdev);
+
+ memset(bdev_sec, 0x0, sizeof(*bdev_sec));
+}
+
+/**
+ * ipe_bdev_setsecurity: Sets the a certain field of a block device security
+ * blob, based on @key.
+ * @bdev: The block device to source the security blob from.
+ * @key: The key representing the information to be stored.
+ * @value: The value to be stored.
+ * @len: The length of @value.
+ *
+ * As block-devices are a generic implementation across specific stacks,
+ * this allows information to be stored from various stacks.
+ *
+ * Return:
+ * 0 - OK
+ * !0 - Error
+ */
+int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
+ const void *value, size_t len)
+{
+ struct ipe_bdev_blob *bdev_sec = ipe_bdev(bdev);
+
+ if (!strcmp(key, DM_VERITY_SIGNATURE_SEC_NAME)) {
+ bdev_sec->dmverity_rh_sig = kmemdup(value, len, GFP_KERNEL);
+ if (!bdev_sec->dmverity_rh_sig)
+ return -ENOMEM;
+
+ bdev_sec->dmv_rh_sig_len = len;
+ }
+
+ return 0;
+}
diff --git a/security/ipe/ipe-blobs.h b/security/ipe/ipe-blobs.h
new file mode 100644
index 000000000000..7561f4cef558
--- /dev/null
+++ b/security/ipe/ipe-blobs.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#include "ipe.h"
+
+#ifndef IPE_BLOB_H
+#define IPE_BLOB_H
+
+static inline struct ipe_bdev_blob *ipe_bdev(struct block_device *bdev)
+{
+ return bdev->security + ipe_blobs.lbs_bdev;
+}
+
+#endif /* IPE_BLOB_H */
diff --git a/security/ipe/ipe-engine.c b/security/ipe/ipe-engine.c
index a629ae3c882d..43757bbb1fbf 100644
--- a/security/ipe/ipe-engine.c
+++ b/security/ipe/ipe-engine.c
@@ -10,6 +10,7 @@
#include "ipe-engine.h"
#include "ipe-audit.h"
#include "ipe-pin.h"
+#include "ipe-blobs.h"
#include "utility.h"
#include <linux/types.h>
@@ -122,6 +123,9 @@ static struct ipe_engine_ctx *build_ctx(const struct file *file,
local->op = op;
local->hook = hook;
+ if (has_bdev(file))
+ local->sec_bdev = ipe_bdev(bdev(file));
+
return local;
}
diff --git a/security/ipe/ipe-engine.h b/security/ipe/ipe-engine.h
index 3f7c471929e2..be17115861cb 100644
--- a/security/ipe/ipe-engine.h
+++ b/security/ipe/ipe-engine.h
@@ -3,20 +3,29 @@
* Copyright (C) Microsoft Corporation. All rights reserved.
*/
+#include "ipe.h"
#include "ipe-hooks.h"
#include <linux/types.h>
#include <linux/rbtree.h>
#include <linux/fs.h>
+#include <crypto/pkcs7.h>
+
#ifndef IPE_ENGINE_H
#define IPE_ENGINE_H
+struct ipe_bdev_blob {
+ u8 *dmverity_rh_sig;
+ size_t dmv_rh_sig_len;
+};
+
struct ipe_engine_ctx {
enum ipe_op op;
enum ipe_hook hook;
const struct file *file;
const char *audit_pathname;
+ const struct ipe_bdev_blob *sec_bdev;
};
struct ipe_prop_cache {
diff --git a/security/ipe/ipe-hooks.c b/security/ipe/ipe-hooks.c
index 43182ba25cc5..f9728c96d73c 100644
--- a/security/ipe/ipe-hooks.c
+++ b/security/ipe/ipe-hooks.c
@@ -15,6 +15,7 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/security.h>
+#include <linux/device-mapper.h>
#define HAS_EXEC(_p, _rp) (((_rp) & PROT_EXEC) || ((_p) & PROT_EXEC))
diff --git a/security/ipe/ipe-hooks.h b/security/ipe/ipe-hooks.h
index 55e417c72425..35a7a681b4c6 100644
--- a/security/ipe/ipe-hooks.h
+++ b/security/ipe/ipe-hooks.h
@@ -113,4 +113,47 @@ int ipe_on_kernel_load_data(enum kernel_load_data_id id);
void ipe_sb_free_security(struct super_block *mnt_sb);
+/**
+ * ipe_bdev_alloc_security: Performs the initialization of IPE's security blob.
+ * @bdev: The block device to source the security blob from.
+ *
+ * The allocation is performed earlier by the LSM infrastructure,
+ * (on behalf of all LSMs) in lsm_alloc_bdev. At the moment, IPE uses
+ * this time to zero out the region of memory reserved for IPE.
+ *
+ * Return:
+ * 0 - OK
+ */
+int ipe_bdev_alloc_security(struct block_device *bdev);
+
+/**
+ * ipe_bdev_free_security: Frees all fields of IPE's block dev security blob.
+ * @bdev: The block device to source the security blob from.
+ *
+ * The deallocation of the blob itself is performed later by the LSM
+ * infrastructure, (on behalf of all LSMs) in lsm_free_bdev.
+ *
+ * Pointers allocated by the bdev_setsecurity hook and alloc_security
+ * hook need to be deallocated here.
+ */
+void ipe_bdev_free_security(struct block_device *bdev);
+
+/**
+ * ipe_bdev_setsecurity: Sets the a certain field of a block device security
+ * blob, based on @key.
+ * @bdev: The block device to source the security blob from.
+ * @key: The key representing the information to be stored.
+ * @value: The value to be stored.
+ * @len: The length of @value.
+ *
+ * As block-devices are a generic implementation across specific stacks,
+ * this allows information to be stored from various stacks.
+ *
+ * Return:
+ * 0 - OK
+ * !0 - Error
+ */
+int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
+ const void *value, size_t len);
+
#endif /* IPE_HOOK_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 971c50ecadaf..924f535c3d32 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -25,6 +25,9 @@ static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(kernel_load_data, ipe_on_kernel_load_data),
LSM_HOOK_INIT(file_mprotect, ipe_on_mprotect),
LSM_HOOK_INIT(sb_free_security, ipe_sb_free_security),
+ LSM_HOOK_INIT(bdev_alloc_security, ipe_bdev_alloc_security),
+ LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security),
+ LSM_HOOK_INIT(bdev_setsecurity, ipe_bdev_setsecurity),
};
/**
@@ -42,6 +45,10 @@ static int __init ipe_load_properties(void)
if (rc != 0)
return rc;
+ rc = ipe_init_dm_verity_signature();
+ if (rc != 0)
+ return rc;
+
return rc;
}
@@ -80,9 +87,20 @@ static int __init ipe_init(void)
return rc;
}
+struct lsm_blob_sizes ipe_blobs = {
+ .lbs_cred = 0,
+ .lbs_file = 0,
+ .lbs_inode = 0,
+ .lbs_ipc = 0,
+ .lbs_msg_msg = 0,
+ .lbs_task = 0,
+ .lbs_bdev = sizeof(struct ipe_bdev_blob),
+};
+
DEFINE_LSM(ipe) = {
.name = "ipe",
.init = ipe_init,
+ .blobs = &ipe_blobs,
};
int enforce = 1;
diff --git a/security/ipe/ipe.h b/security/ipe/ipe.h
index c016b57aa70b..117ee549861c 100644
--- a/security/ipe/ipe.h
+++ b/security/ipe/ipe.h
@@ -10,10 +10,12 @@
#include <linux/types.h>
#include <linux/fs.h>
+#include <linux/lsm_hooks.h>
#define IPE_MODE_ENFORCE "enforce"
#define IPE_MODE_PERMISSIVE "permissive"
+extern struct lsm_blob_sizes ipe_blobs;
extern int enforce;
extern int success_audit;
extern int strict_parse;
diff --git a/security/ipe/properties/Kconfig b/security/ipe/properties/Kconfig
index 9dc0db8817b2..2d8866ee456e 100644
--- a/security/ipe/properties/Kconfig
+++ b/security/ipe/properties/Kconfig
@@ -12,3 +12,13 @@ config IPE_BOOT_PROP
being evaluated originates from the initial superblock.
if unsure, answer N.
+
+config IPE_DM_VERITY_SIGNATURE
+ bool "Enable property for signature verified dm-verity volumes"
+ depends on DM_VERITY_VERIFY_ROOTHASH_SIG
+ help
+ This option enables IPE's integration with Device-Mapper Verity's
+ signed root-hashes. This enables the usage of the property,
+ "dmverity_signature" in IPE's policy.
+
+ if unsure, answer Y.
diff --git a/security/ipe/properties/Makefile b/security/ipe/properties/Makefile
index e3e7fe17cf58..6b67cbe36e31 100644
--- a/security/ipe/properties/Makefile
+++ b/security/ipe/properties/Makefile
@@ -9,3 +9,4 @@
obj-$(CONFIG_SECURITY_IPE) += properties.o
properties-$(CONFIG_IPE_BOOT_PROP) += boot-verified.o
+properties-$(CONFIG_IPE_DM_VERITY_SIGNATURE) += dmverity-signature.o
diff --git a/security/ipe/properties/dmverity-signature.c b/security/ipe/properties/dmverity-signature.c
new file mode 100644
index 000000000000..448e3b8fd43e
--- /dev/null
+++ b/security/ipe/properties/dmverity-signature.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "../ipe.h"
+#include "../ipe-pin.h"
+#include "../ipe-property.h"
+#include "../utility.h"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/audit.h>
+#include <linux/mount.h>
+
+#define PROPERTY_NAME "dmverity_signature"
+
+static void audit(struct audit_buffer *ab, bool value)
+{
+ audit_log_format(ab, "%s", (value) ? "TRUE" : "FALSE");
+}
+
+static inline void audit_rule_value(struct audit_buffer *ab,
+ const void *value)
+{
+ audit(ab, (bool)value);
+}
+
+static inline void audit_ctx(struct audit_buffer *ab,
+ const struct ipe_engine_ctx *ctx,
+ const void *storage)
+{
+ bool b = has_bdev(ctx->file) && ctx->sec_bdev->dmverity_rh_sig;
+
+ audit(ab, b);
+}
+
+static bool evaluate(const struct ipe_engine_ctx *ctx,
+ const void *value, void **storage)
+{
+ bool expect = (bool)value;
+
+ if (!has_bdev(ctx->file))
+ return false;
+
+ return ((bool)ctx->sec_bdev->dmverity_rh_sig) == expect;
+}
+
+static int parse(const char *val_str, void **value)
+{
+ if (strcmp("TRUE", val_str) == 0)
+ *value = (void *)true;
+ else if (strcmp("FALSE", val_str) == 0)
+ *value = (void *)false;
+ else
+ return -EBADMSG;
+
+ return 0;
+}
+
+static inline int duplicate(const void *src, void **dest)
+{
+ *dest = (void *)(bool)src;
+
+ return 0;
+}
+
+static const struct ipe_property dmv_signature = {
+ .property_name = PROPERTY_NAME,
+ .eval = evaluate,
+ .parse = parse,
+ .rule_audit = audit_rule_value,
+ .ctx_audit = audit_ctx,
+ .dup = duplicate,
+ .prealloc = NULL,
+ .free_val = NULL,
+ .free_storage = NULL,
+};
+
+int ipe_init_dm_verity_signature(void)
+{
+ return ipe_register_property(&dmv_signature);
+}
diff --git a/security/ipe/properties/prop-entry.h b/security/ipe/properties/prop-entry.h
index f598dd9608b9..85366366ff0d 100644
--- a/security/ipe/properties/prop-entry.h
+++ b/security/ipe/properties/prop-entry.h
@@ -17,4 +17,13 @@ static inline int __init ipe_init_bootv(void)
int __init ipe_init_bootv(void);
#endif /* CONFIG_IPE_BOOT_PROP */
+#ifndef CONFIG_IPE_DM_VERITY_SIGNATURE
+static inline int __init ipe_init_dm_verity_signature(void)
+{
+ return 0;
+}
+#else
+int __init ipe_init_dm_verity_signature(void);
+#endif /* CONFIG_IPE_DM_VERITY_SIGNATURE */
+
#endif /* IPE_PROP_ENTRY_H */
diff --git a/security/ipe/utility.h b/security/ipe/utility.h
index a13089bb0d8f..7580f17274a3 100644
--- a/security/ipe/utility.h
+++ b/security/ipe/utility.h
@@ -19,4 +19,14 @@ static inline bool has_sb(const struct file *file)
return has_mount(file) && file->f_path.mnt->mnt_sb;
}
+static inline bool has_bdev(const struct file *file)
+{
+ return has_sb(file) && file->f_path.mnt->mnt_sb->s_bdev;
+}
+
+static inline struct block_device *bdev(const struct file *file)
+{
+ return file->f_path.mnt->mnt_sb->s_bdev;
+}
+
#endif /* IPE_UTILITY_H */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 08/11] dm-verity: add bdev_setsecurity hook for root-hash
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (5 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 07/11] ipe: add property for signed dmverity volumes deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 09/11] ipe: add property for dmverity roothash deven.desai
` (4 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a security hook call to set a security property of a block_device
in dm-verity with the root-hash that was verified to match the merkel-tree.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
drivers/md/dm-verity-target.c | 8 ++++++++
include/linux/device-mapper.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index c507f3a4e237..225f67ab378d 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -16,8 +16,10 @@
#include "dm-verity.h"
#include "dm-verity-fec.h"
#include "dm-verity-verify-sig.h"
+#include "dm-core.h"
#include <linux/module.h>
#include <linux/reboot.h>
+#include <linux/security.h>
#define DM_MSG_PREFIX "verity"
@@ -530,6 +532,12 @@ static int verity_verify_io(struct dm_verity_io *io)
return -EIO;
}
+ r = security_bdev_setsecurity(dm_table_get_md(v->ti->table)->bdev,
+ DM_VERITY_ROOTHASH_SEC_NAME,
+ v->root_digest, v->digest_size);
+ if (unlikely(r < 0))
+ return r;
+
/*
* At this point, the merkel tree has finished validating.
* if signature was specified, validate the signature here.
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 6bd49aa48186..467db44de194 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -625,5 +625,6 @@ static inline unsigned long to_bytes(sector_t n)
}
#define DM_VERITY_SIGNATURE_SEC_NAME DM_NAME ".verity-sig"
+#define DM_VERITY_ROOTHASH_SEC_NAME DM_NAME ".verity-rh"
#endif /* _LINUX_DEVICE_MAPPER_H */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 09/11] ipe: add property for dmverity roothash
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (6 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 08/11] dm-verity: add bdev_setsecurity hook for root-hash deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 10/11] documentation: Add IPE Documentation deven.desai
` (3 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add a property to allow IPE policy to express rules around a specific
root-hash of a dm-verity volume.
This can be used for revocation, (when combined with the previous dm-verity
property) or the authorization of a single dm-verity volume.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
security/ipe/ipe-blobs.c | 10 ++
security/ipe/ipe-engine.h | 3 +
security/ipe/ipe.c | 4 +
security/ipe/properties/Kconfig | 13 +-
security/ipe/properties/Makefile | 1 +
security/ipe/properties/dmverity-roothash.c | 155 ++++++++++++++++++++
security/ipe/properties/prop-entry.h | 9 ++
7 files changed, 194 insertions(+), 1 deletion(-)
create mode 100644 security/ipe/properties/dmverity-roothash.c
diff --git a/security/ipe/ipe-blobs.c b/security/ipe/ipe-blobs.c
index a4ee8df02855..1e054eb13857 100644
--- a/security/ipe/ipe-blobs.c
+++ b/security/ipe/ipe-blobs.c
@@ -45,6 +45,8 @@ void ipe_bdev_free_security(struct block_device *bdev)
{
struct ipe_bdev_blob *bdev_sec = ipe_bdev(bdev);
+ kfree(bdev_sec->dmverity_rh);
+
memset(bdev_sec, 0x0, sizeof(*bdev_sec));
}
@@ -76,5 +78,13 @@ int ipe_bdev_setsecurity(struct block_device *bdev, const char *key,
bdev_sec->dmv_rh_sig_len = len;
}
+ if (!strcmp(key, DM_VERITY_ROOTHASH_SEC_NAME)) {
+ bdev_sec->dmverity_rh = kmemdup(value, len, GFP_KERNEL);
+ if (!bdev_sec->dmverity_rh)
+ return -ENOMEM;
+
+ bdev_sec->rh_size = len;
+ }
+
return 0;
}
diff --git a/security/ipe/ipe-engine.h b/security/ipe/ipe-engine.h
index be17115861cb..d8cdb3cc7af8 100644
--- a/security/ipe/ipe-engine.h
+++ b/security/ipe/ipe-engine.h
@@ -18,6 +18,9 @@
struct ipe_bdev_blob {
u8 *dmverity_rh_sig;
size_t dmv_rh_sig_len;
+
+ u8 *dmverity_rh;
+ size_t rh_size;
};
struct ipe_engine_ctx {
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 924f535c3d32..b398eafa6049 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -49,6 +49,10 @@ static int __init ipe_load_properties(void)
if (rc != 0)
return rc;
+ rc = ipe_init_dm_verity_rh();
+ if (rc != 0)
+ return rc;
+
return rc;
}
diff --git a/security/ipe/properties/Kconfig b/security/ipe/properties/Kconfig
index 2d8866ee456e..57b97b2b3877 100644
--- a/security/ipe/properties/Kconfig
+++ b/security/ipe/properties/Kconfig
@@ -13,8 +13,19 @@ config IPE_BOOT_PROP
if unsure, answer N.
+config IPE_DM_VERITY_ROOTHASH
+ bool "Enable property for authorizing dm-verity volumes via root-hash"
+ depends on DM_VERITY
+ help
+ This option enables IPE's integration with Device-Mapper Verity.
+ This enables the usage of the property "dmverity_roothash" in IPE's
+ policy. This property allows authorization or revocation via a
+ a hex-string representing the roothash of a dmverity volume.
+
+ if unsure, answer Y.
+
config IPE_DM_VERITY_SIGNATURE
- bool "Enable property for signature verified dm-verity volumes"
+ bool "Enable property for verified dm-verity volumes"
depends on DM_VERITY_VERIFY_ROOTHASH_SIG
help
This option enables IPE's integration with Device-Mapper Verity's
diff --git a/security/ipe/properties/Makefile b/security/ipe/properties/Makefile
index 6b67cbe36e31..d9a3807797f4 100644
--- a/security/ipe/properties/Makefile
+++ b/security/ipe/properties/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_SECURITY_IPE) += properties.o
properties-$(CONFIG_IPE_BOOT_PROP) += boot-verified.o
properties-$(CONFIG_IPE_DM_VERITY_SIGNATURE) += dmverity-signature.o
+properties-$(CONFIG_IPE_DM_VERITY_ROOTHASH) += dmverity-roothash.o
diff --git a/security/ipe/properties/dmverity-roothash.c b/security/ipe/properties/dmverity-roothash.c
new file mode 100644
index 000000000000..5c575fc275bc
--- /dev/null
+++ b/security/ipe/properties/dmverity-roothash.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ */
+
+#include "../ipe.h"
+#include "../ipe-pin.h"
+#include "../ipe-property.h"
+#include "../utility.h"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/audit.h>
+#include <linux/kernel.h>
+
+#define PROPERTY_NAME "dmverity_roothash"
+
+struct counted_array {
+ u8 *arr;
+ size_t len;
+};
+
+static void audit(struct audit_buffer *ab, const void *value)
+{
+ const struct counted_array *a = (const struct counted_array *)value;
+
+ if (!a || a->len == 0)
+ audit_log_format(ab, "NULL");
+ else
+ audit_log_n_hex(ab, a->arr, a->len);
+}
+
+static inline void audit_rule_value(struct audit_buffer *ab,
+ const void *value)
+{
+ audit(ab, value);
+}
+
+static inline void audit_ctx(struct audit_buffer *ab,
+ const struct ipe_engine_ctx *ctx,
+ const void *storage)
+{
+ struct counted_array a;
+
+ if (!has_bdev(ctx->file))
+ return audit(ab, NULL);
+
+ a.arr = ctx->sec_bdev->dmverity_rh;
+ a.len = ctx->sec_bdev->rh_size;
+
+ return audit(ab, &a);
+}
+
+static bool evaluate(const struct ipe_engine_ctx *ctx,
+ const void *value, void **storage)
+{
+ const struct counted_array *a = (const struct counted_array *)value;
+
+ if (!has_bdev(ctx->file))
+ return false;
+
+ if (a->len != ctx->sec_bdev->rh_size)
+ return false;
+
+ return memcmp(a->arr, ctx->sec_bdev->dmverity_rh, a->len) == 0;
+}
+
+static int parse(const char *val_str, void **value)
+{
+ struct counted_array *arr = NULL;
+ int rv = 0;
+
+ arr = kzalloc(sizeof(*arr), GFP_KERNEL);
+ if (!arr) {
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ arr->len = strlen(val_str) / 2;
+
+ arr->arr = kzalloc(arr->len, GFP_KERNEL);
+ if (!arr->arr) {
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ rv = hex2bin(arr->arr, val_str, arr->len);
+ if (rv != 0)
+ goto err;
+
+ *value = arr;
+ return rv;
+err:
+ if (arr)
+ kfree(arr->arr);
+ kfree(arr);
+ return rv;
+}
+
+static int duplicate(const void *src, void **dest)
+{
+ struct counted_array *arr = NULL;
+ const struct counted_array *src_arr = src;
+ int rv = 0;
+
+ arr = kmemdup(src_arr, sizeof(*arr), GFP_KERNEL);
+ if (!arr) {
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ arr->arr = kmemdup(src_arr->arr, src_arr->len, GFP_KERNEL);
+ if (!arr->arr) {
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ *dest = arr;
+ return rv;
+err:
+ if (arr)
+ kfree(arr->arr);
+ kfree(arr);
+
+ return rv;
+}
+
+static void free_val(void **value)
+{
+ struct counted_array *a = (struct counted_array *)*value;
+
+ if (a)
+ kfree(a->arr);
+ kfree(a);
+ *value = NULL;
+}
+
+static const struct ipe_property dmv_roothash = {
+ .property_name = PROPERTY_NAME,
+ .eval = evaluate,
+ .parse = parse,
+ .rule_audit = audit_rule_value,
+ .ctx_audit = audit_ctx,
+ .dup = duplicate,
+ .free_val = free_val,
+ .prealloc = NULL,
+ .free_storage = NULL,
+};
+
+int ipe_init_dm_verity_rh(void)
+{
+ return ipe_register_property(&dmv_roothash);
+}
diff --git a/security/ipe/properties/prop-entry.h b/security/ipe/properties/prop-entry.h
index 85366366ff0d..86a360570f3b 100644
--- a/security/ipe/properties/prop-entry.h
+++ b/security/ipe/properties/prop-entry.h
@@ -26,4 +26,13 @@ static inline int __init ipe_init_dm_verity_signature(void)
int __init ipe_init_dm_verity_signature(void);
#endif /* CONFIG_IPE_DM_VERITY_SIGNATURE */
+#ifndef CONFIG_IPE_DM_VERITY_ROOTHASH
+static inline int __init ipe_init_dm_verity_rh(void)
+{
+ return 0;
+}
+#else
+int __init ipe_init_dm_verity_rh(void);
+#endif /* CONFIG_IPE_DM_VERITY_ROOTHASH */
+
#endif /* IPE_PROP_ENTRY_H */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 10/11] documentation: Add IPE Documentation
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (7 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 09/11] ipe: add property for dmverity roothash deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:10 ` [RESEND PATCH 11/11] cleanup: uapi/linux/audit.h deven.desai
` (2 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Add IPE's documentation to the kernel tree.
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
Documentation/admin-guide/LSM/index.rst | 1 +
Documentation/admin-guide/LSM/ipe.rst | 487 ++++++++++++++++++
.../admin-guide/kernel-parameters.txt | 20 +
MAINTAINERS | 1 +
4 files changed, 509 insertions(+)
create mode 100644 Documentation/admin-guide/LSM/ipe.rst
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index a6ba95fbaa9f..ce63be6d64ad 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -47,3 +47,4 @@ subdirectories.
tomoyo
Yama
SafeSetID
+ ipe
diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst
new file mode 100644
index 000000000000..def353e34288
--- /dev/null
+++ b/Documentation/admin-guide/LSM/ipe.rst
@@ -0,0 +1,487 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Integrity Policy Enforcement (IPE)
+==================================
+
+Overview
+--------
+
+IPE is a Linux Security Module, which allows for a configurable policy
+to enforce integrity requirements on the whole system. It attempts to
+solve the issue of Code Integrity: that any code being executed (or
+files being read), are identical to the version that was built by a
+trusted source.
+
+There are multiple implementations within the Linux kernel that solve
+some measure of integrity verification. For instance, device-mapper
+verity, which ensures integrity for a block device, and fs-verity which
+is a system that ensures integrity for a filesystem. What these
+implementations lack is a measure of run-time verification that binaries
+are sourced from these locations. IPE aims to address this gap.
+
+IPE is separated between two major components: A configurable policy,
+provided by the LSM ("IPE Core"), and deterministic attributes provided
+by the kernel to evaluate files against, ("IPE Properties").
+
+Use Cases
+---------
+
+IPE is designed for use is an embedded device with a specific purpose
+(e.g. network firewall device in a data center), where all software and
+configuration is built and provisioned by the owner.
+
+Ideally, a system which leverages IPE is not intended for general
+purpose computing and does not utilize any software or configuration
+built by a third party. An ideal system to leverage IPE has both mutable
+and immutable components, however, all binary executable code is
+immutable.
+
+For the highest level of security, platform firmware should verify the
+the kernel and optionally the root filesystem (e.g. via U-Boot verified
+boot). This allows the entire system to be integrity verified.
+
+Known Gaps
+----------
+
+IPE cannot verify the integrity of anonymous executable memory, such as
+the trampolines created by gcc closures and libffi, or JIT'd code.
+Unfortunately, as this is dynamically generated code, there is no way
+for IPE to detect that this code has not been tampered with in
+transition from where it was built, to where it is running. As a result,
+IPE is incapable of tackling this problem for dynamically generated
+code.
+
+IPE cannot verify the integrity of interpreted languages' programs when
+these scripts invoked via ``<interpreter> <file>``. This is because the
+way interpreters execute these files, the scripts themselves are not
+evaluated as executable code through one of IPE's hooks. Interpreters
+can be enlightened to the usage of IPE by trying to mmap a file into
+executable memory (+X), after opening the file and responding to the
+error code appropriately. This also applies to included files, or high
+value files, such as configuration files of critical system components.
+This specific gap is planned on being addressed within IPE.
+
+Threat Model
+------------
+
+The threat type addressed by IPE is tampering of executable user-land
+code beyond the initially booted kernel, and the initial verification of
+kernel modules that are loaded in userland through ``modprobe`` or
+``insmod``.
+
+Tampering violates the property of integrity. IPE's role in mitigating
+this threat is to verify the integrity (and authenticity) of all
+executable code and to deny their use if integrity verification fails.
+IPE generates audit logs which may be utilized to detect integrity
+verification failures.
+
+Tampering threat scenarios include modification or replacement of
+executable code by a range of actors including:
+
+- Insiders with physical access to the hardware
+- Insiders with local network access to the system
+- Insiders with access to the deployment system
+- Compromised internal systems under external control
+- Malicious end users of the system
+- Compromised end users of the system
+- Remote (external) compromise of the system
+
+IPE does not mitigate threats arising from malicious authorized
+developers, or compromised developer tools used by authorized
+developers. Additionally, IPE draws hard security boundary between user
+mode and kernel mode. As a result, IPE does not provide any protections
+against a kernel level exploit, and a kernel-level exploit can disable
+or tamper with IPE's protections.
+
+The root of trust for all of IPE's verifications is the
+``SYSTEM_TRUSTED_KEYRING``.
+
+IPE Core
+--------
+
+IPE Policy
+~~~~~~~~~~
+
+IPE policy is designed to be both forward compatible and backwards
+compatible. There is one required line, at the top of the policy,
+indicating the policy name, and the policy version, for instance:
+
+::
+
+ policy_name="Ex Policy" policy_version=0.0.0
+
+The policy name is a unique key identifying this policy in a human
+readable name. This is used to create nodes under securityfs as well as
+uniquely identify policies to deploy new policies vs update existing
+policies.
+
+The policy version indicates the current version of the policy (NOT the
+policy syntax version). This is used to prevent roll-back of policy to
+potentially insecure previous versions of the policy.
+
+The next portion of IPE policy, are rules. Rules are formed by key=value
+pairs, known as properties. IPE rules require two properties: "action",
+which determines what IPE does when it encounters a match against the
+rule, and "op", which determines when that rule should be evaluated.
+Thus, a minimal rule is:
+
+::
+
+ op=EXECUTE action=ALLOW
+
+This example will allow any execution. Additional properties are used to
+restrict attributes about the files being evaluated. These properties
+are intended to be deterministic attributes that are resident in the
+kernel.
+
+Order does not matter for the rule's properties - they can be listed in
+any order, however it is encouraged to have the "op" property be first,
+and the "action" property be last for readability. Rules are evaluated
+top-to-bottom. As a result, any revocation rules, or denies should be
+placed early in the file to ensure that these rules are evaluated before
+as rule with "action=ALLOW" is hit.
+
+IPE policy is designed to be forward compatible and backwards
+compatible, thus any failure to parse a rule will result in the line
+being ignored, and a warning being emitted. If backwards compatibility
+is not required, the kernel command line parameter and sysctl,
+``ipe.strict_parse`` can be enabled, which will cause these warnings to
+be fatal.
+
+IPE policy supports comments. The character '#' will function as a
+comment, ignoring all characters to the right of '#' until the newline.
+
+The default behavior of IPE evaluations can also be expressed in policy,
+through the ``DEFAULT`` statement. This can be done at a global level,
+or a per-operation level:
+
+::
+
+ # Global
+ DEFAULT action=ALLOW
+
+ # Operation Specific
+ DEFAULT op=EXECUTE action=ALLOW
+
+If a global default is unset, and a specific operation default is not
+set for an IPE operation, it will assume that the default action should
+be ``ALLOW``. This is to preserve compatibility between policies and the
+LSM.
+
+With configurable policy-based LSMs, there's several issues with
+enforcing the configurable policies at startup, around reading and
+parsing the policy:
+
+1. The kernel *should* not read files from userland, so directly reading
+ the policy file is prohibited.
+2. The kernel command line has a character limit, and one kernel module
+ should not reserve the entire character limit for its own
+ configuration.
+3. There are various boot loaders in the kernel ecosystem, so handing
+ off a memory block would be costly to maintain.
+
+As a result, IPE has addressed this problem through a concept of a "boot
+policy". A boot policy is a minimal policy, compiled into the kernel.
+This policy is intended to get the system to a state where userland is
+setup and ready to receive commands, at which point a more complex
+policy ("user policies") can be deployed via securityfs. The boot policy
+can be specified via the Kconfig, ``SECURITY_IPE_BOOT_POLICY``, which
+accepts a path to a plain-text version of the IPE policy to apply. This
+policy will be compiled into the kernel. If not specified, IPE will be
+disabled until a policy is deployed through securityfs, and activated
+through sysfs.
+
+Deploying Policies
+^^^^^^^^^^^^^^^^^^
+
+User policies as explained above, are policies that are deployed from
+userland, through securityfs. These policies are signed to enforce some
+level of authorization of the policies (prohibiting an attacker from
+gaining root, and deploying an "allow all" policy), through the PKCS#7
+enveloped data format. These policies must be signed by a certificate
+that chains to the ``SYSTEM_TRUSTED_KEYRING``. Through openssl, the
+signing can be done via:
+
+::
+
+ openssl smime -sign -in "$MY_POLICY" -signer "$MY_CERTIFICATE" \
+ -inkey "$MY_PRIVATE_KEY" -binary -outform der -noattr -nodetach \
+ -out "$MY_POLICY.p7s"
+
+Deploying the policies is done through securityfs, through the
+``new_policy`` node. To deploy a policy, simply cat the file into the
+securityfs node:
+
+::
+
+ cat "$MY_POLICY.p7s" > /sys/kernel/security/ipe/new_policy
+
+Upon success, this will create one subdirectory under
+``/sys/kernel/security/ipe/policies/``. The subdirectory will be the
+``policy_name`` field of the policy deployed, so for the example above,
+the directory will be ``/sys/kernel/security/ipe/policies/Ex\ Policy``.
+Within this directory, there will be two files: ``raw`` and ``content``.
+
+The ``raw`` file is rw, reading will provide the raw PKCS#7 data that
+was provided to the kernel, representing the policy. Writing, will
+deploy an in-place policy update - if this policy is the currently
+running policy, the new updated policy will replace it immediately upon
+success.
+
+The ``content`` file is read only. Reading will provide the PKCS#7 inner
+content of the policy, which will be the plain text policy.
+
+Similarly, the ``cat`` command above will result in an error upon
+syntactically invalid or untrusted policies. It will also error if a
+policy already exists with the same ``policy_name``. The write to the
+``raw`` node will error upon syntactically invalid, untrusted policies,
+or if the payload fails the version check. The write will also fail if
+the ``policy_name`` in the payload does not match the existing policy.
+
+Deploying these policies will *not* cause IPE to start enforcing this
+policy. Once deployment is successful, a policy can be marked as active,
+via the sysctl, ``ipe.active_policy``. IPE will enforce whatever policy
+is marked as active. For our example, we can activate the ``Ex Policy``
+via:
+
+::
+
+ sysctl ipe.active_policy="Ex Policy"
+
+At which point, ``Ex Policy`` will now be the enforced policy on the
+system.
+
+IPE also provides a way to delete policies. This can be done via the
+``del_policy`` securityfs node, ``/sys/kernel/security/ipe/del_policy``.
+Writing the ``policy_name`` of the policy to be deleted will delete that
+node:
+
+::
+
+ echo -n "$MY_POLICY_NAME" > /sys/kernel/security/ipe/del_policy
+
+There are two requirements to delete policies:
+
+1. The policy being deleted must not be the active policy.
+2. The policy being deleted must not be the boot policy.
+
+NOTE: It's important to know above that the "echo" command will add a
+newline to the end of the input, and this will be considered as part of
+the filename. You can remove the newline via the -n parameter.
+
+Modes
+~~~~~
+
+IPE supports two modes of operation: permissive (similar to SELinux's
+permissive mode) and enforce. Permissive mode performs the same checks
+as enforce mode, and logs policy violations, but will not enforce the
+policy. This allows users to test policies before enforcing them.
+
+The default mode is enforce, and can be changed via the kernel command
+line parameter ``ipe.enforce=(0|1)``, or the sysctl
+``ipe.enforce=(0|1)``. The ability to switch modes can be compiled out
+of the LSM via setting the Kconfig
+``CONFIG_SECURITY_IPE_PERMISSIVE_SWITCH`` to N.
+
+Audit Events
+~~~~~~~~~~~~
+
+Success Auditing
+^^^^^^^^^^^^^^^^
+
+IPE supports success auditing. When enabled, all events that pass IPE
+policy and are not blocked will emit an audit event. This is disabled by
+default, and can be enabled via the kernel command line
+``ipe.success_audit=(0|1)`` or the sysctl ``ipe.success_audit=(0|1)``.
+
+This is very noisy, as IPE will check every user-mode binary on the
+system, but is useful for debugging policies.
+
+IPE Properties
+--------------
+
+As explained above, IPE properties are ``key=value`` pairs expressed in
+IPE policy. Two properties are built-into the policy parser: 'op' and
+'action'. The other properties are determinstic attributes to express
+across files. Currently those properties are: 'boot_verified',
+'dmverity_signature', 'dmverity_roothash'. A description of all
+properties supported by IPE are listed below:
+
+op
+~~
+
+Indicates the operation for a rule to apply to. Must be in every rule.
+IPE supports the following operations:
+
+``EXECUTE``
+
+ Pertains to any file attempting to be executed, or loaded as an
+ executable.
+
+``FIRMWARE``:
+
+ Pertains to firmware being loaded via the firmware_class interface.
+ This covers both the preallocated buffer and the firmware file
+ itself.
+
+``KMODULE``:
+
+ Pertains to loading kernel modules via ``modprobe`` or ``insmod``.
+
+``KEXEC_IMAGE``:
+
+ Pertains to kernel images loading via ``kexec``.
+
+``KEXEC_INITRAMFS``
+
+ Pertains to initrd images loading via ``kexec --initrd``.
+
+``POLICY``:
+
+ Controls loading IMA policies through the
+ ``/sys/kernel/security/ima/policy`` securityfs entry.
+
+``X509_CERT``:
+
+ Controls loading IMA certificates through the Kconfigs,
+ ``CONFIG_IMA_X509_PATH`` and ``CONFIG_EVM_X509_PATH``.
+
+action
+~~~~~~
+
+Determines what IPE should do when a rule matches. Must be in every
+rule. Can be one of:
+
+``ALLOW``:
+
+ If the rule matches, explicitly allow the call to proceed without
+ executing any more rules.
+
+``DENY``:
+
+ If the rule matches, explicitly prohibit the call from proceeding
+ without executing any more rules.
+
+boot_verified
+~~~~~~~~~~~~~
+
+This property can be utilized for authorization of the first super-block
+that is mounted on the system, where IPE attempts to evaluate a file.
+Typically this is used for systems with an initramfs or other initial
+disk, where this is unmounted before the system becomes available, and
+is not covered by any other property. This property is controlled by the
+Kconfig, ``CONFIG_IPE_BOOT_PROP``. The format of this property is:
+
+::
+
+ boot_verified=(TRUE|FALSE)
+
+
+.. WARNING::
+
+ This property will trust any disk where the first IPE
+ evaluation occurs. If you do not have a startup disk that is
+ unpacked and unmounted (like initramfs), then it will automatically
+ trust the root filesystem and potentially overauthorize the entire
+ disk.
+
+dmverity_roothash
+~~~~~~~~~~~~~~~~~
+
+This property can be utilized for authorization or revocation of
+specific dm-verity volumes, identified via root hash. It has a
+dependency on the DM_VERITY module. This property is controlled by the
+property: ``CONFIG_IPE_DM_VERITY_ROOTHASH``. The format of this property
+is:
+
+::
+
+ dmverity_roothash=HashHexDigest
+
+dmverity_signature
+~~~~~~~~~~~~~~~~~~
+
+This property can be utilized for authorization of all dm-verity volumes
+that have a signed roothash that chains to the system trusted keyring.
+It has a dependency on the ``DM_VERITY_VERIFY_ROOTHASH_SIG`` Kconfig.
+This property is controlled by the Kconfig:
+``CONFIG_IPE_DM_VERITY_SIGNATURE``. The format of this property is:
+
+::
+
+ dmverity_signature=(TRUE|FALSE)
+
+Policy Examples
+---------------
+
+Allow all
+~~~~~~~~~
+
+::
+
+ policy_name="Allow All" policy_version=0.0.0
+ DEFAULT action=ALLOW
+
+Allow only initial superblock
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ policy_name="Allow All Initial SB" policy_version=0.0.0
+ DEFAULT action=DENY
+
+ op=EXECUTE boot_verified=TRUE action=ALLOW
+
+Allow any signed dm-verity volume and the initial superblock
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ policy_name="AllowSignedAndInitial" policy_version=0.0.0
+ DEFAULT action=DENY
+
+ op=EXECUTE boot_verified=TRUE action=ALLOW
+ op=EXECUTE dmverity_signature=TRUE action=ALLOW
+
+Prohibit execution from a specific dm-verity volume
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ policy_name="AllowSignedAndInitial" policy_version=0.0.0
+ DEFAULT action=DENY
+
+ op=EXECUTE dmverity_roothash=401fcec5944823ae12f62726e8184407a5fa9599783f030dec146938 action=DENY
+ op=EXECUTE boot_verified=TRUE action=ALLOW
+ op=EXECUTE dmverity_signature=TRUE action=ALLOW
+
+Allow only a specific dm-verity volume
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ policy_name="AllowSignedAndInitial" policy_version=0.0.0
+ DEFAULT action=DENY
+
+ op=EXECUTE dmverity_roothash=401fcec5944823ae12f62726e8184407a5fa9599783f030dec146938 action=ALLOW
+
+External Information
+--------------------
+
+Please see the github repository at: https://github.com/microsoft/Integrity-Policy-Enforcement-LSM
+
+FAQ
+---
+
+Q: What's the difference between other LSMs which provide integrity
+verification (i.e. IMA)?
+
+A: IPE differs from other LSMs which provide integrity checking, as it
+has no dependency on the filesystem metadata itself. The attributes that
+IPE checks are deterministic properties that exist solely in the kernel.
+Additionally, IPE provides no additional mechanisms of verifying these
+files (e.g. IMA Signatures) - all of the attributes of verifying files
+are existing features within the kernel.
+
+Additionally, IPE is completely restricted to integrity. It offers no
+measurement or attestation features, which IMA addresses.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d5a4fe22703..9eb8b19fe9db 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1913,6 +1913,26 @@
ip= [IP_PNP]
See Documentation/admin-guide/nfs/nfsroot.rst.
+ ipe.enforce= [IPE]
+ Format: { "0" | "1" }
+ 0 - Start IPE in audit mode
+ 1 - Start IPE in enforce mode (default).
+ See Documentation/security/ipe.rst
+
+ ipe.success_audit=
+ [IPE] Start IPE with success auditing
+ Format: { "0" | "1" }
+ 0 - Disable success auditing (default)
+ 1 - Enable success auditing
+ See Documentation/security/ipe.rst
+
+ ipe.strict_parse=
+ [IPE] Start IPE with strict policy parsing enabled
+ Format: { "0" | "1" }
+ 0 - Disable strict parsing (default)
+ 1 - Enable strict parsing
+ See Documentation/security/ipe.rst
+
ipcmni_extend [KNL] Extend the maximum number of unique System V
IPC identifiers from 32,768 to 16,777,216.
diff --git a/MAINTAINERS b/MAINTAINERS
index ab9adcd37a0c..897da80af3f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8441,6 +8441,7 @@ INTEGRITY POLICY ENFORCEMENT (IPE)
M: Deven Bowers <deven.desai@linux.microsoft.com>
L: linux-integrity@vger.kernel.org
S: Supported
+F: Documentation/admin-guide/LSM/ipe.rst
F: scripts/ipe/
F: security/ipe/
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [RESEND PATCH 11/11] cleanup: uapi/linux/audit.h
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (8 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 10/11] documentation: Add IPE Documentation deven.desai
@ 2020-04-06 18:10 ` deven.desai
2020-04-06 18:36 ` [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) Deven Bowers
2020-04-06 18:50 ` Jann Horn
11 siblings, 0 replies; 15+ messages in thread
From: deven.desai @ 2020-04-06 18:10 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
From: Deven Bowers <deven.desai@linux.microsoft.com>
Remove trailing whitespaces and align the integrity #defines in
linux/uapi/audit.h
Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
---
include/uapi/linux/audit.h | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 4e0122a0ed0c..d642ade068b5 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -48,7 +48,7 @@
* 2500 - 2999 future user space (maybe integrity labels and related events)
*
* Messages from 1000-1199 are bi-directional. 1200-1299 & 2100 - 2999 are
- * exclusively user space. 1300-2099 is kernel --> user space
+ * exclusively user space. 1300-2099 is kernel --> user space
* communication.
*/
#define AUDIT_GET 1000 /* Get status */
@@ -78,7 +78,7 @@
#define AUDIT_LAST_USER_MSG 1199
#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */
#define AUDIT_LAST_USER_MSG2 2999
-
+
#define AUDIT_DAEMON_START 1200 /* Daemon startup record */
#define AUDIT_DAEMON_END 1201 /* Daemon normal stop record */
#define AUDIT_DAEMON_ABORT 1202 /* Daemon error stop record */
@@ -139,20 +139,20 @@
#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
-#define AUDIT_FIRST_KERN_ANOM_MSG 1700
-#define AUDIT_LAST_KERN_ANOM_MSG 1799
-#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
-#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
-#define AUDIT_ANOM_LINK 1702 /* Suspicious use of file links */
-#define AUDIT_ANOM_CREAT 1703 /* Suspicious file creation */
-#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
-#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
-#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
-#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
-#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
-#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */
-#define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */
-#define AUDIT_INTEGRITY_POLICY_RULE 1807 /* IMA policy rules */
+#define AUDIT_FIRST_KERN_ANOM_MSG 1700
+#define AUDIT_LAST_KERN_ANOM_MSG 1799
+#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
+#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
+#define AUDIT_ANOM_LINK 1702 /* Suspicious use of file links */
+#define AUDIT_ANOM_CREAT 1703 /* Suspicious file creation */
+#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */
+#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */
+#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */
+#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */
+#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
+#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */
+#define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */
+#define AUDIT_INTEGRITY_POLICY_RULE 1807 /* IMA policy rules */
#define AUDIT_INTEGRITY_POLICY_LOAD 1808 /* IPE Policy Load */
#define AUDIT_INTEGRITY_POLICY_ACTIVATE 1809 /* IPE Policy Activation */
#define AUDIT_INTEGRITY_EVENT 1810 /* IPE Evaluation Event */
--
2.26.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE)
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (9 preceding siblings ...)
2020-04-06 18:10 ` [RESEND PATCH 11/11] cleanup: uapi/linux/audit.h deven.desai
@ 2020-04-06 18:36 ` Deven Bowers
2020-04-06 18:50 ` Jann Horn
11 siblings, 0 replies; 15+ messages in thread
From: Deven Bowers @ 2020-04-06 18:36 UTC (permalink / raw)
To: agk, axboe, snitzer, jmorris, serge, zohar, linux-integrity,
linux-security-module, dm-devel, linux-block
Cc: tyhicks, pasha.tatashin, sashal, jaskarankhurana, nramas, mdsakib
This was resent due to an incorrect domain for dm-devel (redhat.org vs redhat.com), and an email address
that was bouncing.
Additionally, this is an RFC, and this tag will be added in the next iteration.
- Deven
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE)
2020-04-06 18:10 [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) deven.desai
` (10 preceding siblings ...)
2020-04-06 18:36 ` [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE) Deven Bowers
@ 2020-04-06 18:50 ` Jann Horn
2020-04-06 18:59 ` Deven Bowers
11 siblings, 1 reply; 15+ messages in thread
From: Jann Horn @ 2020-04-06 18:50 UTC (permalink / raw)
To: deven.desai
Cc: agk, Jens Axboe, snitzer, James Morris, Serge E. Hallyn,
Mimi Zohar, linux-integrity, linux-security-module, dm-devel,
linux-block, tyhicks, Pavel Tatashin, Sasha Levin,
jaskarankhurana, nramas, mdsakib
On Mon, Apr 6, 2020 at 8:10 PM <deven.desai@linux.microsoft.com> wrote:
> Overview:
> ------------------------------------
> IPE is a Linux Security Module, which allows for a configurable
> policy to enforce integrity requirements on the whole system. It
> attempts to solve the issue of Code Integrity: that any code being
> executed (or files being read), are identical to the version that
> was built by a trusted source.
Where's patch 02/11? lore at
https://lore.kernel.org/linux-security-module/20200406183619.GA77626@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net/T/#t
has everything other than that patch.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE)
2020-04-06 18:50 ` Jann Horn
@ 2020-04-06 18:59 ` Deven Bowers
2020-04-06 20:09 ` Sasha Levin
0 siblings, 1 reply; 15+ messages in thread
From: Deven Bowers @ 2020-04-06 18:59 UTC (permalink / raw)
To: Jann Horn
Cc: agk, Jens Axboe, snitzer, James Morris, Serge E. Hallyn,
Mimi Zohar, linux-integrity, linux-security-module, dm-devel,
linux-block, tyhicks, Pavel Tatashin, Sasha Levin,
jaskarankhurana, nramas, mdsakib
On Mon, Apr 06, 2020 at 08:50:46PM +0200, Jann Horn wrote:
> On Mon, Apr 6, 2020 at 8:10 PM <deven.desai@linux.microsoft.com> wrote:
> > Overview:
> > ------------------------------------
> > IPE is a Linux Security Module, which allows for a configurable
> > policy to enforce integrity requirements on the whole system. It
> > attempts to solve the issue of Code Integrity: that any code being
> > executed (or files being read), are identical to the version that
> > was built by a trusted source.
>
> Where's patch 02/11? lore at
> https://lore.kernel.org/linux-security-module/20200406183619.GA77626@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net/T/#t
> has everything other than that patch.
It looks like it's over majordomo's character limit by 7489 characters.
I'll have to repost with this patch broken up. Apologies.
- Deven
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RESEND PATCH 00/11] Integrity Policy Enforcement LSM (IPE)
2020-04-06 18:59 ` Deven Bowers
@ 2020-04-06 20:09 ` Sasha Levin
0 siblings, 0 replies; 15+ messages in thread
From: Sasha Levin @ 2020-04-06 20:09 UTC (permalink / raw)
To: Deven Bowers
Cc: Jann Horn, agk, Jens Axboe, snitzer, James Morris,
Serge E. Hallyn, Mimi Zohar, linux-integrity,
linux-security-module, dm-devel, linux-block, tyhicks,
Pavel Tatashin, jaskarankhurana, nramas, mdsakib
On Mon, Apr 06, 2020 at 11:59:10AM -0700, Deven Bowers wrote:
>On Mon, Apr 06, 2020 at 08:50:46PM +0200, Jann Horn wrote:
>> On Mon, Apr 6, 2020 at 8:10 PM <deven.desai@linux.microsoft.com> wrote:
>> > Overview:
>> > ------------------------------------
>> > IPE is a Linux Security Module, which allows for a configurable
>> > policy to enforce integrity requirements on the whole system. It
>> > attempts to solve the issue of Code Integrity: that any code being
>> > executed (or files being read), are identical to the version that
>> > was built by a trusted source.
>>
>> Where's patch 02/11? lore at
>> https://lore.kernel.org/linux-security-module/20200406183619.GA77626@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net/T/#t
>> has everything other than that patch.
>
>It looks like it's over majordomo's character limit by 7489 characters.
>I'll have to repost with this patch broken up. Apologies.
Looks like it didn't cc LKML either.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 15+ messages in thread