From patchwork Sat Nov 12 21:32:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Fleming X-Patchwork-Id: 81935 Delivered-To: patch@linaro.org Received: by 10.182.1.168 with SMTP id 8csp456153obn; Sat, 12 Nov 2016 13:33:07 -0800 (PST) X-Received: by 10.99.64.132 with SMTP id n126mr56274050pga.87.1478986386979; Sat, 12 Nov 2016 13:33:06 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id cr5si13725226pad.48.2016.11.12.13.33.06; Sat, 12 Nov 2016 13:33:06 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@codeblueprint-co-uk.20150623.gappssmtp.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754087AbcKLVct (ORCPT + 27 others); Sat, 12 Nov 2016 16:32:49 -0500 Received: from mail-wm0-f52.google.com ([74.125.82.52]:36919 "EHLO mail-wm0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752870AbcKLVco (ORCPT ); Sat, 12 Nov 2016 16:32:44 -0500 Received: by mail-wm0-f52.google.com with SMTP id t79so36506244wmt.0 for ; Sat, 12 Nov 2016 13:32:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=codeblueprint-co-uk.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mU2Jdn8OHbq+nnv8eEWyKR15bITNLXWgmtifBxFbk+A=; b=wVPj7xt1Mm/XfkpvcOKejxnB6yDRnyRRblfw/WAjXp2zMuLKnFKN7vroDv40Pc5hq0 8JY/H1pd6Bl3dA17KgnuHInUwAEFnMQzlS4tYJvoo7F3EYAXgCBD7Qv3ojA6c/0UKb9M sUp3s+UjUogYol1neipVrVA25PWsNBp9K+6R8RADklCvHjSYf9Sl7wxOnz5/zQdagzFS P5/iOxWubyR/Xt+Un5vfWQTzI+wookhvQ0r8vjr7ZVoqBu6mqtDN5HKmLIdZjewTQL6m tY37FNvnnfkcua5pCj+PgAeRAtdygXJNGbvrbbnC4hH7eum7d2qTn10A407E5Wdra0rp 31Rw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mU2Jdn8OHbq+nnv8eEWyKR15bITNLXWgmtifBxFbk+A=; b=PF+N/g5N3fxNyrqM/CY9T4gbvkaiXuXa2AGUDaf6jrjV9e56zYMxtr28N+cB9CPf0C i0IHvY/VmtcJ1/hOsiwl8ZOWdBY2VCMp6RCCmYhWEQkLIEAP2zrnWJiMtmBBsccNh5/A zs4ehfBb3DT2ueMdPKkxN/1+XUR8dw6xLKPoQ7UVm3hHMLEUem5KimlVQNF9DVAeY4L1 WcXyUa6zc1w3M3c++5ECtG6asW1ryFMyA2CwEIqh8JcEJ5NNoNMg+7SrxsfAxJIhaQeb DMTIG/DmTqUpggBr05oZoITIeNddaFNLf8l7CKXL/6V7rwFF3L2rsbx/YIv6uuM+IJh7 iRrw== X-Gm-Message-State: ABUngveNESsBw2drbhniMOooDnDbEo1mdhTMVZLVEUdNlenc9DhczhuJus4fjmKnWOabIw== X-Received: by 10.28.234.201 with SMTP id g70mr3592525wmi.104.1478986362645; Sat, 12 Nov 2016 13:32:42 -0800 (PST) Received: from localhost ([2a02:c7f:9225:4100:de53:60ff:fe39:5599]) by smtp.gmail.com with ESMTPSA id i15sm19028267wjs.16.2016.11.12.13.32.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 12 Nov 2016 13:32:42 -0800 (PST) From: Matt Fleming To: Ingo Molnar , Thomas Gleixner , "H . Peter Anvin" Cc: Ard Biesheuvel , linux-kernel@vger.kernel.org, linux-efi@vger.kernel.org, Matt Fleming , Kees Cook Subject: [PATCH 3/9] efi: Add support for seeding the RNG from a UEFI config table Date: Sat, 12 Nov 2016 21:32:31 +0000 Message-Id: <20161112213237.8804-4-matt@codeblueprint.co.uk> X-Mailer: git-send-email 2.10.0 In-Reply-To: <20161112213237.8804-1-matt@codeblueprint.co.uk> References: <20161112213237.8804-1-matt@codeblueprint.co.uk> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Ard Biesheuvel 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) Cc: Matt Fleming Reviewed-by: Kees Cook Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/efi.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/efi.h | 8 ++++++ 2 files changed, 80 insertions(+) -- 2.10.0 diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a4944e22f294..92914801e388 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.esrt}, {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table}, {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, + {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.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, &efi.flags); + 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 = { + .notifier_call = update_efi_random_seed, +}; + +static int register_update_efi_random_seed(void) +{ + if (efi.rng_seed == EFI_INVALID_TABLE_ADDR) + return 0; + return register_reboot_notifier(&efi_random_seed_nb); +} +late_initcall(register_update_efi_random_seed); +#endif diff --git a/include/linux/efi.h b/include/linux/efi.h index 2d089487d2da..85e28b138cdd 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -599,6 +599,7 @@ void efi_native_runtime_setup(void); */ #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) +#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) typedef struct { efi_guid_t guid; @@ -872,6 +873,7 @@ extern struct efi { unsigned long esrt; /* ESRT table */ unsigned long properties_table; /* properties table */ unsigned long mem_attr_table; /* memory attributes table */ + unsigned long rng_seed; /* UEFI firmware random seed */ efi_get_time_t *get_time; efi_set_time_t *set_time; efi_get_wakeup_time_t *get_wakeup_time; @@ -1493,4 +1495,10 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table, struct efi_boot_memmap *map, void *priv, efi_exit_boot_map_processing priv_func); + +struct linux_efi_random_seed { + u32 size; + u8 bits[]; +}; + #endif /* _LINUX_EFI_H */