linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
To: linux-security-module@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [RFC 2/2] initramfs with digital signature protection
Date: Tue,  5 Feb 2013 14:34:50 +0200	[thread overview]
Message-ID: <cc87f1242960fad1a9fb44bcec331915e14c832b.1360067333.git.dmitry.kasatkin@intel.com> (raw)
In-Reply-To: <cover.1360067333.git.dmitry.kasatkin@intel.com>
In-Reply-To: <cover.1360067333.git.dmitry.kasatkin@intel.com>

Often initramfs is (re)fabricated on the machine on which it runs.
In such cases it is impossible to sign initramfs image, because
private key is not supposed to be available.

This patch adds support for additional digitaly signed initramfs images.
Digitaly signed initramfs image can be loaded from conventional initramfs
image or from rootfs and '/pre-init' is executed prior 'init' from initramfs
or root file system. If 'pre-init' fails, kernel panics. Signed initramfs
image must be located in '/initramfs-sig.img'.

Digitally signed initramfs can be used to provide protected user-space
environment for initialization purpose. For example, LSM, IMA/EVM can be
securely initialized using such approach.

Signing is done using scripts/sign-file from kernel source code and uses module
signature format and module verification API. Important to note again that
signing of such images should be done on the build machine.

Bellow is an example, how to sign compressed initrd (cpio) image:

scripts/sign-file -v signing_key.priv signing_key.x509 initrd.gz initramfs-sig.img

When using initramfs-tools, initramfs-sig.img can be easily included into the
conventional initramfs using initramfs-tools hooks, for example, by creating
/etc/initramfs-tools/hooks/initramfs_sig.sh, and adding following lines there:

  #!/bin/sh
  . /usr/share/initramfs-tools/hook-functions
  copy_exec /initramfs-sig.img

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
---
 init/Kconfig         |    7 +++
 init/Makefile        |    1 +
 init/do_mounts.h     |   10 +++
 init/initramfs_sig.c |  171 ++++++++++++++++++++++++++++++++++++++++++++++++++
 init/main.c          |    4 ++
 5 files changed, 193 insertions(+)
 create mode 100644 init/initramfs_sig.c

diff --git a/init/Kconfig b/init/Kconfig
index 7d30240..fca6f47 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1738,4 +1738,11 @@ config ASN1
 	  inform it as to what tags are to be expected in a stream and what
 	  functions to call on what tags.
 
+config INITRAMFS_SIG
+	bool "initramfs with digital signature protection"
+	depends on INTEGRITY_ASYMMETRIC_KEYS
+	default n
+	help
+	  This option enables initramfs with digital signature protection.
+
 source "kernel/Kconfig.locks"
diff --git a/init/Makefile b/init/Makefile
index 7bc47ee..0099169 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -7,6 +7,7 @@ ifneq ($(CONFIG_BLK_DEV_INITRD),y)
 obj-y                          += noinitramfs.o
 else
 obj-$(CONFIG_BLK_DEV_INITRD)   += initramfs.o
+obj-$(CONFIG_INITRAMFS_SIG)   += initramfs_sig.o
 endif
 obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
 
diff --git a/init/do_mounts.h b/init/do_mounts.h
index 11829eb..113207f 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -76,3 +76,13 @@ static inline void md_run_setup(void) {}
 #endif
 
 char * __init unpack_to_rootfs(char *buf, unsigned len);
+
+#ifdef CONFIG_INITRAMFS_SIG
+
+int __init initramfs_sig_load(void);
+
+#else
+
+static inline int initramfs_sig_load(void) { return 0; }
+
+#endif
diff --git a/init/initramfs_sig.c b/init/initramfs_sig.c
new file mode 100644
index 0000000..b65f97e
--- /dev/null
+++ b/init/initramfs_sig.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Author:
+ * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ */
+
+#define pr_fmt(fmt) "initramfs_sig: " fmt
+
+/*
+ * Many of the syscalls used in this file expect some of the arguments
+ * to be __user pointers not __kernel pointers.  To limit the sparse
+ * noise, turn off sparse checking for this file.
+ */
+
+#ifdef __CHECKER__
+#undef __CHECKER__
+#warning "Sparse checking disabled for this file"
+#endif
+
+#include <linux/unistd.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/freezer.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+#include "../kernel/module-internal.h"
+#include "do_mounts.h"
+
+#define BUF_SIZE	BLOCK_SIZE
+
+static const char *secmnt = "/root";
+static const char *initramfs_img = "/initramfs-sig.img";
+
+static int __init load_image(const char *from)
+{
+	int err = -EINVAL, fd;
+	char *buf = NULL, *msg;
+	off_t len, offset;
+	int size = BLOCK_SIZE;
+	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+
+	fd = sys_open(from, O_RDONLY, 0);
+	if (fd < 0) {
+		pr_err("cannot open %s: %d\n", from, fd);
+		return fd;
+	}
+
+	len = sys_lseek(fd, 0, SEEK_END);
+	pr_info("%s image size: %lu\n", from, len);
+	if (len < 0)
+		goto out;
+
+	buf = vmalloc(len);
+	if (!buf) {
+		pr_err("unable to allocate large block of memory\n");
+		err = -ENOMEM;
+		goto out_close;
+	}
+
+	sys_lseek(fd, 0, SEEK_SET);
+
+	for (offset = 0; len; offset += size, len -= size) {
+		if (len < size)
+			size = len;
+		if (sys_read(fd, buf + offset, size) != size)
+			goto out;
+	}
+
+	pr_info("image offset: %lu\n", offset);
+
+	offset -= markerlen;
+
+	if (offset < 0 || memcmp(buf + offset, MODULE_SIG_STRING, markerlen)) {
+		pr_err("image has no marker\n");
+		goto out;
+	}
+
+	err = mod_verify_sig(buf, &offset);
+	pr_info("mod_verify_sig() = %d, len: %lu\n", err, offset);
+	if (err)
+		goto out;
+
+	err = sys_mount("tpmfs", (char *)secmnt, "tmpfs", MS_SILENT, NULL);
+	if (err) {
+		pr_err("sys_mount() = %d\n", err);
+		goto out;
+	}
+
+	sys_unshare(CLONE_FS | CLONE_FILES);
+	sys_chdir(secmnt);
+	sys_chroot(".");
+	sys_setsid();
+
+	pr_info("unpack start\n");
+	msg = unpack_to_rootfs(buf, offset);
+	if (msg) {
+		pr_err("unable to unpack rootfs\n");
+		err = -EINVAL;
+		goto out;
+	}
+	pr_info("unpack end\n");
+
+	err = 0;
+
+out:
+	vfree(buf);
+out_close:
+	sys_close(fd);
+
+	return err;
+}
+
+static int __init init_init(struct subprocess_info *info, struct cred *new)
+{
+	return load_image(initramfs_img);
+}
+
+static void init_cleanup(struct subprocess_info *info)
+{
+	int err;
+
+	pr_info("cleanup\n");
+
+	err = sys_umount((char *)secmnt, MNT_DETACH);
+	if (err)
+		pr_err("unable to umount secmnt: %d\n", err);
+}
+
+static int __init load_initramfs(void)
+{
+	static char *argv[] = { "pre-init", NULL, };
+	extern char *envp_init[];
+	int err;
+
+	/*
+	 * In case that a resume from disk is carried out by linuxrc or one of
+	 * its children, we need to tell the freezer not to wait for us.
+	 */
+	current->flags |= PF_FREEZER_SKIP;
+
+	err = call_usermodehelper_fns("/pre-init", argv, envp_init,
+				      UMH_WAIT_PROC, init_init, init_cleanup,
+				      NULL);
+
+	current->flags &= ~PF_FREEZER_SKIP;
+
+	pr_info("initramfs_sig /pre-init completed: %d\n", err);
+
+	return err;
+}
+
+int __init initramfs_sig_load(void)
+{
+	if (sys_access(initramfs_img, 0))
+		panic("signed initramfs image not found (INITRAMFS_SIG is anabled)\n");
+
+	if (load_initramfs())
+		panic("initramfs_sig failed! (INITRAMFS_SIG is anabled)\n");
+
+	pr_info("initramfs_sig finished\n");
+
+	return 0;
+}
diff --git a/init/main.c b/init/main.c
index 85d69df..43ef145 100644
--- a/init/main.c
+++ b/init/main.c
@@ -81,6 +81,8 @@
 #include <asm/smp.h>
 #endif
 
+#include "do_mounts.h"
+
 static int kernel_init(void *);
 
 extern void init_IRQ(void);
@@ -895,6 +897,8 @@ static void __init kernel_init_freeable(void)
 		prepare_namespace();
 	}
 
+	initramfs_sig_load();
+
 	/*
 	 * Ok, we have completed the initial bootup, and
 	 * we're essentially up and running. Get rid of the
-- 
1.7.10.4


  parent reply	other threads:[~2013-02-05 12:35 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-05 12:34 [RFC 0/2] initramfs with digital signature protection Dmitry Kasatkin
2013-02-05 12:34 ` [RFC 1/2] export unpack_to_rootfs Dmitry Kasatkin
2013-02-05 16:48   ` Peter Jones
2013-02-05 17:16     ` Kasatkin, Dmitry
2013-02-08  8:30       ` Kasatkin, Dmitry
2013-02-05 12:34 ` Dmitry Kasatkin [this message]
2013-02-05 18:03   ` [RFC 2/2] initramfs with digital signature protection Peter Jones
2013-02-05 20:08     ` Mimi Zohar
2013-02-05 22:03     ` Kasatkin, Dmitry
2013-02-05 18:19   ` Matthew Garrett
2013-02-05 18:30     ` Matthew Garrett
2013-02-05 18:34     ` Vivek Goyal
2013-02-05 21:55       ` Kasatkin, Dmitry
2013-04-05 13:50         ` Vivek Goyal
2013-04-08 19:43           ` Mimi Zohar
2013-04-08 20:09             ` Vivek Goyal
2013-04-08 20:17               ` Josh Boyer
2013-04-09 14:38                 ` Vivek Goyal
2013-04-10  3:07                   ` Mimi Zohar
2013-04-10 19:42                     ` Vivek Goyal
2013-04-10 21:05                       ` Mimi Zohar
2013-04-11  8:08                         ` Dmitry Kasatkin
2013-04-11 14:52                         ` Vivek Goyal
2013-04-12 11:54                           ` Mimi Zohar
     [not found]                         ` <CACE9dm-GZpjco8u6jNxLQpYA8LYSeoVjsyyRXVwxXHzjO-LvGw@mail.gmail.com>
2013-04-11 14:55                           ` Vivek Goyal
2013-04-11 18:42                             ` Dmitry Kasatkin
2013-04-11 21:13                               ` Vivek Goyal
2013-04-12 12:03                                 ` Mimi Zohar
2013-02-05 20:36   ` Peter Jones
2013-02-05 22:09     ` Kasatkin, Dmitry
2013-02-06  5:04       ` H. Peter Anvin
2013-02-06  8:01         ` Kasatkin, Dmitry
2013-02-06 16:41           ` H. Peter Anvin
2013-02-08  9:16             ` Kasatkin, Dmitry
2013-02-08 15:49               ` H. Peter Anvin
2013-02-08 16:24                 ` Kasatkin, Dmitry
2013-02-08 16:50                   ` H. Peter Anvin
2013-02-07 17:05   ` Vivek Goyal
2013-02-08  8:34     ` Kasatkin, Dmitry
2013-02-08 13:27       ` Kasatkin, Dmitry
2013-02-11 21:59         ` Vivek Goyal

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=cc87f1242960fad1a9fb44bcec331915e14c832b.1360067333.git.dmitry.kasatkin@intel.com \
    --to=dmitry.kasatkin@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    /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;
as well as URLs for NNTP newsgroup(s).