[tip:efi/core] efi: Add support for seeding the RNG from a UEFI config table

2016-11-13 Thread tip-bot for Ard Biesheuvel
Commit-ID:  636259880a7e7d3446a707dddebc799da94bdd0b
Gitweb: http://git.kernel.org/tip/636259880a7e7d3446a707dddebc799da94bdd0b
Author: Ard Biesheuvel 
AuthorDate: Sat, 12 Nov 2016 21:32:31 +
Committer:  Ingo Molnar 
CommitDate: Sun, 13 Nov 2016 08:23:14 +0100

efi: Add support for seeding the RNG from a UEFI config table

Specify a Linux specific UEFI configuration table that carries some
random bits, and use the contents during early boot to seed the kernel's
random number generator. This allows much strong random numbers to be
generated early on.

The entropy is fed to the kernel using add_device_randomness(), which is
documented as being appropriate for being called very early.

Since UEFI configuration tables may also be consumed by kexec'd kernels,
register a reboot notifier that updates the seed in the table.

Note that the config table could be generated by the EFI stub or by any
other UEFI driver or application (e.g., GRUB), but the random seed table
GUID and the associated functionality should be considered an internal
kernel interface (unless it is promoted to ABI later on)

Signed-off-by: Ard Biesheuvel 
Signed-off-by: Matt Fleming 
Reviewed-by: Kees Cook 
Cc: Linus Torvalds 
Cc: Peter Zijlstra 
Cc: Thomas Gleixner 
Cc: linux-...@vger.kernel.org
Link: http://lkml.kernel.org/r/20161112213237.8804-4-m...@codeblueprint.co.uk
Signed-off-by: Ingo Molnar 
---
 drivers/firmware/efi/efi.c | 72 ++
 include/linux/efi.h|  8 ++
 2 files changed, 80 insertions(+)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index a4944e2..9291480 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -23,7 +23,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -48,6 +51,7 @@ struct efi __read_mostly efi = {
.esrt   = EFI_INVALID_TABLE_ADDR,
.properties_table   = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
+   .rng_seed   = EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
 
@@ -440,6 +444,7 @@ static __initdata efi_config_table_type_t common_tables[] = 
{
{EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", },
{EFI_PROPERTIES_TABLE_GUID, "PROP", _table},
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", _attr_table},
+   {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", _seed},
{NULL_GUID, NULL, NULL},
 };
 
@@ -501,6 +506,29 @@ int __init efi_config_parse_tables(void *config_tables, 
int count, int sz,
pr_cont("\n");
set_bit(EFI_CONFIG_TABLES, );
 
+   if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
+   struct linux_efi_random_seed *seed;
+   u32 size = 0;
+
+   seed = early_memremap(efi.rng_seed, sizeof(*seed));
+   if (seed != NULL) {
+   size = seed->size;
+   early_memunmap(seed, sizeof(*seed));
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   if (size > 0) {
+   seed = early_memremap(efi.rng_seed,
+ sizeof(*seed) + size);
+   if (seed != NULL) {
+   add_device_randomness(seed->bits, seed->size);
+   early_memunmap(seed, sizeof(*seed) + size);
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   }
+   }
+
/* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
efi_properties_table_t *tbl;
@@ -824,3 +852,47 @@ int efi_status_to_err(efi_status_t status)
 
return err;
 }
+
+#ifdef CONFIG_KEXEC
+static int update_efi_random_seed(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+   struct linux_efi_random_seed *seed;
+   u32 size = 0;
+
+   if (!kexec_in_progress)
+   return NOTIFY_DONE;
+
+   seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
+   if (seed != NULL) {
+   size = min(seed->size, 32U);
+   memunmap(seed);
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   if (size > 0) {
+   seed = memremap(efi.rng_seed, sizeof(*seed) + size,
+   MEMREMAP_WB);
+   if (seed != NULL) {
+   seed->size = size;
+   get_random_bytes(seed->bits, seed->size);
+   

[tip:efi/core] efi: Add support for seeding the RNG from a UEFI config table

2016-11-13 Thread tip-bot for Ard Biesheuvel
Commit-ID:  636259880a7e7d3446a707dddebc799da94bdd0b
Gitweb: http://git.kernel.org/tip/636259880a7e7d3446a707dddebc799da94bdd0b
Author: Ard Biesheuvel 
AuthorDate: Sat, 12 Nov 2016 21:32:31 +
Committer:  Ingo Molnar 
CommitDate: Sun, 13 Nov 2016 08:23:14 +0100

efi: Add support for seeding the RNG from a UEFI config table

Specify a Linux specific UEFI configuration table that carries some
random bits, and use the contents during early boot to seed the kernel's
random number generator. This allows much strong random numbers to be
generated early on.

The entropy is fed to the kernel using add_device_randomness(), which is
documented as being appropriate for being called very early.

Since UEFI configuration tables may also be consumed by kexec'd kernels,
register a reboot notifier that updates the seed in the table.

Note that the config table could be generated by the EFI stub or by any
other UEFI driver or application (e.g., GRUB), but the random seed table
GUID and the associated functionality should be considered an internal
kernel interface (unless it is promoted to ABI later on)

Signed-off-by: Ard Biesheuvel 
Signed-off-by: Matt Fleming 
Reviewed-by: Kees Cook 
Cc: Linus Torvalds 
Cc: Peter Zijlstra 
Cc: Thomas Gleixner 
Cc: linux-...@vger.kernel.org
Link: http://lkml.kernel.org/r/20161112213237.8804-4-m...@codeblueprint.co.uk
Signed-off-by: Ingo Molnar 
---
 drivers/firmware/efi/efi.c | 72 ++
 include/linux/efi.h|  8 ++
 2 files changed, 80 insertions(+)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index a4944e2..9291480 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -23,7 +23,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -48,6 +51,7 @@ struct efi __read_mostly efi = {
.esrt   = EFI_INVALID_TABLE_ADDR,
.properties_table   = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
+   .rng_seed   = EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
 
@@ -440,6 +444,7 @@ static __initdata efi_config_table_type_t common_tables[] = 
{
{EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", },
{EFI_PROPERTIES_TABLE_GUID, "PROP", _table},
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", _attr_table},
+   {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", _seed},
{NULL_GUID, NULL, NULL},
 };
 
@@ -501,6 +506,29 @@ int __init efi_config_parse_tables(void *config_tables, 
int count, int sz,
pr_cont("\n");
set_bit(EFI_CONFIG_TABLES, );
 
+   if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
+   struct linux_efi_random_seed *seed;
+   u32 size = 0;
+
+   seed = early_memremap(efi.rng_seed, sizeof(*seed));
+   if (seed != NULL) {
+   size = seed->size;
+   early_memunmap(seed, sizeof(*seed));
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   if (size > 0) {
+   seed = early_memremap(efi.rng_seed,
+ sizeof(*seed) + size);
+   if (seed != NULL) {
+   add_device_randomness(seed->bits, seed->size);
+   early_memunmap(seed, sizeof(*seed) + size);
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   }
+   }
+
/* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
efi_properties_table_t *tbl;
@@ -824,3 +852,47 @@ int efi_status_to_err(efi_status_t status)
 
return err;
 }
+
+#ifdef CONFIG_KEXEC
+static int update_efi_random_seed(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+   struct linux_efi_random_seed *seed;
+   u32 size = 0;
+
+   if (!kexec_in_progress)
+   return NOTIFY_DONE;
+
+   seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
+   if (seed != NULL) {
+   size = min(seed->size, 32U);
+   memunmap(seed);
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   if (size > 0) {
+   seed = memremap(efi.rng_seed, sizeof(*seed) + size,
+   MEMREMAP_WB);
+   if (seed != NULL) {
+   seed->size = size;
+   get_random_bytes(seed->bits, seed->size);
+   memunmap(seed);
+   } else {
+   pr_err("Could not map UEFI random seed!\n");
+   }
+   }
+   return NOTIFY_DONE;
+}
+
+static struct notifier_block efi_random_seed_nb = {
+