Linux kbuild/kconfig development
 help / color / mirror / Atom feed
From: Jeremy Linton <jeremy.linton@arm.com>
To: linux-kernel@vger.kernel.org
Cc: akpm@linux-foundation.org, hch@lst.de,
	gregkh@linuxfoundation.org, graf@amazon.com, lukas@wunner.de,
	wufan@linux.microsoft.com, brauner@kernel.org,
	jsperbeck@google.com, ardb@kernel.org,
	linux-crypto@vger.kernel.org, linux-kbuild@vger.kernel.org,
	keyrings@vger.kernel.org, Jeremy Linton <jeremy.linton@arm.com>
Subject: [RFC 3/5] initramfs: Use existing module signing infrastructure
Date: Tue, 15 Oct 2024 17:22:33 -0500	[thread overview]
Message-ID: <20241015222235.71040-4-jeremy.linton@arm.com> (raw)
In-Reply-To: <20241015222235.71040-1-jeremy.linton@arm.com>

Adding some security checks around the configuration data and early
init processes running on the machine is a good idea. There is a move
to do this via systemd UKIs using the UEFI and shim infrastructure to
wrap a kernel and its associated initramfs into a single PE
executable, which is then validated and measured together. The
existing kernel boot methods can also provide a similar level of
security by leveraging the kernel's signing and validation
infrastructure to check a signature on the initramfs.

Kernel-validated initramfs images maintain the existing UEFI boot flow
while enabling functionality on non-UEFI machines. They keep the UEFI
secure boot verification separate from current and future choices over
how the kernel verifies data used after it boots. Additionally, this
makes it possible for multiple signed initramfs images, for example,
debug and recovery images, to share a single kernel image.

Let's reuse the kernel's sign-file utility, which appends a trailing
signature, signature description, and module signature string to sign
the initramfs. Then, immediately before we unpack the image, detect if
there is a signature, validate it, and strip it off. Then, with a
later patch, we can decide what happens when the image is unsigned or
cannot be verified.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 include/linux/initrd.h |  3 ++
 init/initramfs.c       | 67 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/include/linux/initrd.h b/include/linux/initrd.h
index f1a1f4c92ded..e123d3cb39bb 100644
--- a/include/linux/initrd.h
+++ b/include/linux/initrd.h
@@ -5,6 +5,9 @@
 
 #define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
 
+/* the len here equals the modsig string len */
+#define INITRD_SIG_STRING "~initrd signature appended~\n"
+
 /* starting block # of image */
 extern int rd_image_start;
 
diff --git a/init/initramfs.c b/init/initramfs.c
index bc911e466d5b..d2d2c68016c2 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/init.h>
+#include <linux/initrd.h>
 #include <linux/async.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
@@ -14,6 +15,7 @@
 #include <linux/kstrtox.h>
 #include <linux/memblock.h>
 #include <linux/mm.h>
+#include <linux/module_signature.h>
 #include <linux/namei.h>
 #include <linux/init_syscalls.h>
 #include <linux/umh.h>
@@ -688,8 +690,69 @@ static void __init populate_initrd_image(char *err)
 }
 #endif /* CONFIG_BLK_DEV_RAM */
 
+static int __init initrd_signature_check(size_t *initrd_len)
+{
+	struct module_signature *ms;
+	size_t sig_len;
+	int ret = -ENODATA;
+	const size_t m_len = sizeof(INITRD_SIG_STRING) - 1;
+
+	*initrd_len = (initrd_end - initrd_start);
+
+	if (*initrd_len < (m_len + sizeof(*ms)))
+		goto fail;
+
+	if (memcmp((char *)(initrd_end - m_len), INITRD_SIG_STRING, m_len)) {
+		pr_info("unsigned initramfs\n");
+		goto fail;
+	}
+
+	/* remove module sig string from len computations going forward */
+	*initrd_len -= m_len;
+
+	ms = (struct module_signature *)(initrd_end - sizeof(*ms) - m_len);
+
+	ret = mod_check_sig(ms, *initrd_len, "initramfs");
+	if (ret)
+		goto fail;
+
+	sig_len = be32_to_cpu(ms->sig_len);
+	*initrd_len -= sizeof(*ms) + sig_len;
+
+#ifdef CONFIG_INITRAMFS_SIG
+	ret = verify_pkcs7_signature((char *)initrd_start, *initrd_len,
+				     (char *)(initrd_start + *initrd_len),
+				     sig_len,
+				     VERIFY_USE_SECONDARY_KEYRING,
+				     VERIFYING_UNSPECIFIED_SIGNATURE,
+				     NULL, NULL);
+
+	switch (ret) {
+	case 0:
+		pr_info("initramfs: valid signature\n");
+		break;
+	case -ENODATA:
+		pr_err("initramfs: invalid signature\n");
+		break;
+	case -ENOPKG:
+		pr_err("initramfs: unsupported crypto\n");
+		break;
+	case -ENOKEY:
+		pr_err("initramfs: unknown key\n");
+		break;
+	default:
+		pr_err("initramfs: unknown error %d\n", ret);
+	}
+#endif
+
+fail:
+	return ret;
+}
+
 static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
 {
+	size_t initrd_len;
+
 	/* Load the built in initramfs */
 	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
 	if (err)
@@ -703,7 +766,9 @@ static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
 	else
 		printk(KERN_INFO "Unpacking initramfs...\n");
 
-	err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
+	initrd_signature_check(&initrd_len);
+
+	err = unpack_to_rootfs((char *)initrd_start, initrd_len);
 	if (err) {
 #ifdef CONFIG_BLK_DEV_RAM
 		populate_initrd_image(err);
-- 
2.46.0


  parent reply	other threads:[~2024-10-15 22:22 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-15 22:22 [RFC 0/5] Another initramfs signature checking set Jeremy Linton
2024-10-15 22:22 ` [RFC 1/5] initramfs: Add initramfs signature checking Jeremy Linton
2024-10-15 22:22 ` [RFC 2/5] KEYS/certs: Start the builtin key and cert system earlier Jeremy Linton
2024-10-15 22:22 ` Jeremy Linton [this message]
2024-10-15 22:22 ` [RFC 4/5] sign-file: Add -i option to sign initramfs images Jeremy Linton
2024-10-15 22:22 ` [RFC 5/5] initramfs: Enforce initramfs signature Jeremy Linton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241015222235.71040-4-jeremy.linton@arm.com \
    --to=jeremy.linton@arm.com \
    --cc=akpm@linux-foundation.org \
    --cc=ardb@kernel.org \
    --cc=brauner@kernel.org \
    --cc=graf@amazon.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@lst.de \
    --cc=jsperbeck@google.com \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=wufan@linux.microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox