@@ -5,6 +5,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fcntl.h>
+#include <linux/fs_struct.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/dirent.h>
@@ -355,6 +356,7 @@ static int __init maybe_link(void)
static __initdata struct file *wfile;
static __initdata loff_t wfile_pos;
+static bool skip_special __initdata;
static int __init do_name(void)
{
@@ -399,7 +401,7 @@ static int __init do_name(void)
dir_add(collected, mtime);
} else if (S_ISBLK(mode) || S_ISCHR(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) {
- if (maybe_link() == 0) {
+ if (!skip_special && maybe_link() == 0) {
init_mknod(collected, mode, rdev);
init_chown(collected, uid, gid, 0);
init_chmod(collected, mode);
@@ -705,6 +707,11 @@ static void __init populate_initrd_image(char *err)
static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
{
+#ifdef CONFIG_INITRAMFS_EXTERNAL_IS_SUBDIR
+ int r;
+ struct path orig_root, sub_root;
+#endif
+
/* Load the built in initramfs */
char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
if (err)
@@ -718,6 +725,28 @@ static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
else
printk(KERN_INFO "Unpacking initramfs...\n");
+#ifdef CONFIG_INITRAMFS_EXTERNAL_IS_SUBDIR
+ /*
+ * Switch the root so that the external initramfs is extracted there.
+ * Use chroot so that paths under absolute symlinks resolve properly.
+ */
+ get_fs_root(current->fs, &orig_root);
+
+ /*
+ * Don't allow the creation of device nodes. Otherwise duplicate entries
+ * may result in writes to devices.
+ */
+ skip_special = true;
+
+ r = init_chdir(CONFIG_INITRAMFS_EXTERNAL_PATH);
+ if (r < 0)
+ panic_show_mem("Failed to open switch to external initramfs directory (%s): %d",
+ CONFIG_INITRAMFS_EXTERNAL_PATH, r);
+ get_fs_pwd(current->fs, &sub_root);
+ set_fs_root(current->fs, &sub_root);
+ path_put(&sub_root);
+#endif
+
err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
if (err) {
#ifdef CONFIG_BLK_DEV_RAM
@@ -727,6 +756,13 @@ static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
#endif
}
+#ifdef CONFIG_INITRAMFS_EXTERNAL_IS_SUBDIR
+ /* Restore the original root now that the external initramfs is extracted. */
+ set_fs_root(current->fs, &orig_root);
+ set_fs_pwd(current->fs, &orig_root);
+ path_put(&orig_root);
+#endif
+
done:
security_initramfs_populated();
@@ -32,6 +32,32 @@ config INITRAMFS_FORCE
and is useful if you cannot or don't want to change the image
your bootloader passes to the kernel.
+config INITRAMFS_EXTERNAL_PATH
+ string "External initramfs extraction path"
+ default "/"
+ depends on INITRAMFS_SOURCE!=""
+ depends on !INITRAMFS_FORCE
+ help
+ This option causes the kernel to extract the initramfs image(s)
+ provided by the bootloader into a subdirectory under the root
+ directory. The subdirectory must exist in the built-in initramfs.
+
+ This enables the built-in initramfs to check the integrity of the
+ external one.
+
+ If this option is used, any special nodes (device/fifo/socket) in the
+ external initramfs are ignored. Symlinks, including ones pointing
+ outside the subdirectory, are allowed.
+
+ If your built-in initramfs is not capable of dealing with this, leave
+ this option set to "/".
+
+config INITRAMFS_EXTERNAL_IS_SUBDIR
+ bool
+ default y
+ depends on INITRAMFS_EXTERNAL_PATH!=""
+ depends on INITRAMFS_EXTERNAL_PATH!="/"
+
config INITRAMFS_ROOT_UID
int "User ID to map to 0 (user root)"
depends on INITRAMFS_SOURCE!=""
In a typical Secure Boot setup the kernel image is signed, but the initramfs provided by the bootloader is not. This reduces the usefulness of Secure Boot because an attacker can overwrite the initramfs without detection. With this change, when a built-in initramfs is used, the kernel can be configured to extract the initramfs provided by the bootloader into a subdirectory, ensuring it cannot overwrite the built-in one. Userspace can implement a verification scheme. One simple approach is to embed all executables in the built-in initramfs and use the external one for the (signed) kernel modules necessary for the system to boot. Signed-off-by: Hristo Venev <hristo@venev.name> --- init/initramfs.c | 38 +++++++++++++++++++++++++++++++++++++- usr/Kconfig | 26 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-)