Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 615B8C7618E for ; Mon, 30 Jan 2023 22:59:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230342AbjA3W7Q (ORCPT ); Mon, 30 Jan 2023 17:59:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230078AbjA3W6s (ORCPT ); Mon, 30 Jan 2023 17:58:48 -0500 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9CBF5206BF; Mon, 30 Jan 2023 14:58:45 -0800 (PST) Received: by linux.microsoft.com (Postfix, from userid 1052) id ACB3E20EA215; Mon, 30 Jan 2023 14:58:42 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com ACB3E20EA215 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1675119522; bh=+qPOvEL5/cjtz4VuSxa+aNIFeQZXSXbdRSHSnZJj9Js=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z3EsbMo64/T3orUi63xrwtXFYFIJiuRUljSXIIeXSH9JiwCy+hX8dec/edW4i21t1 Xm5MXH88fjAFA8outCoFRi5VRY5h8ODyBoUIuubSAjAXeAoLIFqJs5xDl9NfBICXxl A21DzoPlNJ/IwEfcVjqCS8odIZ2A64Ce0srUqvHY= From: Fan Wu To: corbet@lwn.net, zohar@linux.ibm.com, jmorris@namei.org, serge@hallyn.com, tytso@mit.edu, ebiggers@kernel.org, axboe@kernel.dk, agk@redhat.com, snitzer@kernel.org, eparis@redhat.com, paul@paul-moore.com Cc: linux-doc@vger.kernel.org, linux-integrity@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-block@vger.kernel.org, dm-devel@redhat.com, linux-audit@redhat.com, roberto.sassu@huawei.com, linux-kernel@vger.kernel.org, Deven Bowers , Fan Wu Subject: [RFC PATCH v9 14/16] scripts: add boot policy generation program Date: Mon, 30 Jan 2023 14:57:29 -0800 Message-Id: <1675119451-23180-15-git-send-email-wufan@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675119451-23180-1-git-send-email-wufan@linux.microsoft.com> References: <1675119451-23180-1-git-send-email-wufan@linux.microsoft.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Deven Bowers Enables an IPE policy to be enforced from kernel start, enabling access control based on trust from kernel startup. This is accomplished by transforming an IPE policy indicated by CONFIG_IPE_BOOT_POLICY into a c-string literal that is parsed at kernel startup as an unsigned policy. Signed-off-by: Deven Bowers Signed-off-by: Fan Wu --- v2: + No Changes v3: + No Changes v4: + No Changes v5: + No Changes v6: + No Changes v7: + Move from 01/11 to 14/16 + Don't return errno directly. + Make output of script more user-friendly + Add escaping for tab and '?' + Mark argv pointer const + Invert return code check in the boot policy parsing code path. v8: + No significant changes. v9: + no changes --- MAINTAINERS | 1 + scripts/Makefile | 1 + scripts/ipe/Makefile | 2 + scripts/ipe/polgen/.gitignore | 1 + scripts/ipe/polgen/Makefile | 6 ++ scripts/ipe/polgen/polgen.c | 145 ++++++++++++++++++++++++++++++++++ security/ipe/.gitignore | 1 + security/ipe/Kconfig | 10 +++ security/ipe/Makefile | 11 +++ security/ipe/fs.c | 8 ++ security/ipe/ipe.c | 19 +++++ 11 files changed, 205 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 create mode 100644 security/ipe/.gitignore diff --git a/MAINTAINERS b/MAINTAINERS index 5e27e84763cc..d5b4a6636b0d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10276,6 +10276,7 @@ F: security/integrity/ INTEGRITY POLICY ENFORCEMENT (IPE) M: Fan Wu S: Supported +F: scripts/ipe/ F: security/ipe/ INTEL 810/815 FRAMEBUFFER DRIVER diff --git a/scripts/Makefile b/scripts/Makefile index 1575af84d557..5d1def33df82 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -41,6 +41,7 @@ targets += module.lds 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..066060c22b4a --- /dev/null +++ b/scripts/ipe/polgen/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +hostprogs-always-y := polgen +HOST_EXTRACFLAGS += \ + -I$(srctree)/include \ + -I$(srctree)/include/uapi \ + diff --git a/scripts/ipe/polgen/polgen.c b/scripts/ipe/polgen/polgen.c new file mode 100644 index 000000000000..40b6fe07f47b --- /dev/null +++ b/scripts/ipe/polgen/polgen.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Microsoft Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +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) +{ + int rc = 0; + FILE *fd; + size_t i; + + fd = fopen(pathname, "w"); + if (!fd) { + rc = errno; + goto err; + } + + fprintf(fd, "/* This file is automatically generated."); + fprintf(fd, " Do not edit. */\n"); + fprintf(fd, "#include \n"); + fprintf(fd, "\nextern const char *const ipe_boot_policy;\n\n"); + fprintf(fd, "const char *const ipe_boot_policy =\n"); + + if (!buf || size == 0) { + fprintf(fd, "\tNULL;\n"); + fclose(fd); + return 0; + } + + fprintf(fd, "\t\""); + + for (i = 0; i < size; ++i) { + switch (buf[i]) { + case '"': + fprintf(fd, "\\\""); + break; + case '\'': + fprintf(fd, "'"); + break; + case '\n': + fprintf(fd, "\\n\"\n\t\""); + break; + case '\\': + fprintf(fd, "\\\\"); + break; + case '\t': + fprintf(fd, "\\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 rc; +} + +int main(int argc, const char *const 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; +} diff --git a/security/ipe/.gitignore b/security/ipe/.gitignore new file mode 100644 index 000000000000..eca22ad5ed22 --- /dev/null +++ b/security/ipe/.gitignore @@ -0,0 +1 @@ +boot-policy.c \ No newline at end of file diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig index dd9a066dd35a..691fdb9ae60e 100644 --- a/security/ipe/Kconfig +++ b/security/ipe/Kconfig @@ -17,6 +17,16 @@ menuconfig SECURITY_IPE If unsure, answer N. if SECURITY_IPE +config IPE_BOOT_POLICY + string "Integrity policy to apply on system startup" + help + This option specifies a filepath to a IPE policy that is compiled + into the kernel. This policy will be enforced until a policy update + is deployed via the $securityfs/ipe/policies/$policy_name/active + interface. + + If unsure, leave blank. + menu "IPE Trust Providers" config IPE_PROP_DM_VERITY diff --git a/security/ipe/Makefile b/security/ipe/Makefile index 90203daf0dbb..e6d5176bc20b 100644 --- a/security/ipe/Makefile +++ b/security/ipe/Makefile @@ -5,7 +5,16 @@ # Makefile for building the IPE module as part of the kernel tree. # +quiet_cmd_polgen = IPE_POL $(2) + cmd_polgen = scripts/ipe/polgen/polgen security/ipe/boot-policy.c $(2) + +targets += boot-policy.c + +$(obj)/boot-policy.c: scripts/ipe/polgen/polgen $(CONFIG_IPE_BOOT_POLICY) FORCE + $(call if_changed,polgen,$(CONFIG_IPE_BOOT_POLICY)) + obj-$(CONFIG_SECURITY_IPE) += \ + boot-policy.o \ digest.o \ eval.o \ fs.o \ @@ -16,3 +25,5 @@ obj-$(CONFIG_SECURITY_IPE) += \ policy_parser.o \ digest.o \ audit.o \ + +clean-files := boot-policy.c \ diff --git a/security/ipe/fs.c b/security/ipe/fs.c index bbee17b59b1b..0a371c785e3b 100644 --- a/security/ipe/fs.c +++ b/security/ipe/fs.c @@ -185,6 +185,7 @@ static const struct file_operations enforce_fops = { static int __init ipe_init_securityfs(void) { int rc = 0; + struct ipe_policy *p = NULL; if (!ipe_enabled) return -EOPNOTSUPP; @@ -221,6 +222,13 @@ static int __init ipe_init_securityfs(void) goto err; } + p = ipe_get_policy_rcu(ipe_active_policy); + if (p) { + rc = ipe_new_policyfs_node(p); + if (rc) + goto err; + } + return 0; err: securityfs_remove(np); diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c index 705ce9a003de..458f7a542c66 100644 --- a/security/ipe/ipe.c +++ b/security/ipe/ipe.c @@ -7,6 +7,7 @@ #include "hooks.h" #include "eval.h" +extern const char *const ipe_boot_policy; bool ipe_enabled; static struct lsm_blob_sizes ipe_blobs __lsm_ro_after_init = { @@ -64,10 +65,28 @@ static struct security_hook_list ipe_hooks[] __lsm_ro_after_init = { static int __init ipe_init(void) { int rc = 0; + struct ipe_policy *p = NULL; security_add_hooks(ipe_hooks, ARRAY_SIZE(ipe_hooks), "ipe"); ipe_enabled = true; + if (ipe_boot_policy) { + p = ipe_new_policy(ipe_boot_policy, strlen(ipe_boot_policy), + NULL, 0); + if (IS_ERR(p)) { + rc = PTR_ERR(p); + goto err; + } + + rc = ipe_set_active_pol(p); + if (rc) + goto err; + } + + goto out; +err: + ipe_free_policy(p); +out: return rc; } -- 2.39.0