We will not direct fail the hibernate snapshot restore when the signature check fail, instead kernel will complain by warning message and taint kernel. This patch also introduced a sig_enforce flag to indicate if we want direct fail the snapshot restore when signature check fail. User can enable it through snapshot_sig_enforce parameter or EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE. Signed-off-by: Lee, Chun-Yi <jlee@xxxxxxxx> --- Documentation/kernel-parameters.txt | 7 +++++++ arch/x86/Kconfig | 11 +++++++++++ include/linux/kernel.h | 1 + include/linux/suspend.h | 7 +++++++ kernel/panic.c | 2 ++ kernel/power/hibernate_keys.c | 35 +++++++++++++++++++++++++++++++++++ kernel/power/power.h | 1 + kernel/power/snapshot.c | 6 +++++- 8 files changed, 69 insertions(+), 1 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7f9d4f5..4c686c0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2730,6 +2730,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Useful for devices that are detected asynchronously (e.g. USB and MMC devices). + snapshot_sig_enforce + [HIBERNATE] When CONFIG_SNAPSHOT_VERIFICATION is set, + this means the snapshot image without (valid) signatures + will fail to recover. This parameter provides user to + force launch the snapshot signature check even the UEFI + secure boot didn't enable. + hibernate= [HIBERNATION] noresume Don't check if there's a hibernation image present during boot. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ea73d2f..b43217a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1591,6 +1591,17 @@ config EFI_SECURE_BOOT_SIG_ENFORCE Say Y here to automatically enable module signature enforcement when a system boots with UEFI Secure Boot enabled. +config EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE + def_bool n + prompt "Force snapshot signing when UEFI Secure Boot is enabled" + ---help--- + UEFI Secure Boot provides a mechanism for ensuring that the + firmware will only load signed bootloaders and kernels. Certain + use cases may also require that the snapshot image of hibernate + also be signed. + Say Y here to automatically enable snapshot iage signature + enforcement when a system boots with UEFI Secure Boot enabled. + config SECCOMP def_bool y prompt "Enable seccomp to safely compute untrusted bytecode" diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 482ad2d..95df772 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -427,6 +427,7 @@ extern enum system_states { #define TAINT_CRAP 10 #define TAINT_FIRMWARE_WORKAROUND 11 #define TAINT_OOT_MODULE 12 +#define TAINT_UNSAFE_HIBERNATE 13 extern const char hex_asc[]; #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f73cabf..6b46726 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -320,6 +320,13 @@ extern unsigned long get_safe_page(gfp_t gfp_mask); extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); + +#ifdef CONFIG_SNAPSHOT_VERIFICATION +extern void enforce_signed_snapshot(void); +#else +static inline void enforce_signed_snapshot(void) {}; +#endif + #else /* CONFIG_HIBERNATION */ static inline void register_nosave_region(unsigned long b, unsigned long e) {} static inline void register_nosave_region_late(unsigned long b, unsigned long e) {} diff --git a/kernel/panic.c b/kernel/panic.c index 8018646..c59b1f6 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -206,6 +206,7 @@ static const struct tnt tnts[] = { { TAINT_CRAP, 'C', ' ' }, { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, { TAINT_OOT_MODULE, 'O', ' ' }, + { TAINT_UNSAFE_HIBERNATE, 'H', ' ' }, }; /** @@ -224,6 +225,7 @@ static const struct tnt tnts[] = { * 'C' - modules from drivers/staging are loaded. * 'I' - Working around severe firmware bug. * 'O' - Out-of-tree module has been loaded. + * 'H' - System restored from unsafe hibernate snapshot image. * * The string is overwritten by the next call to print_tainted(). */ diff --git a/kernel/power/hibernate_keys.c b/kernel/power/hibernate_keys.c index 0bce9ab..daf08e0 100644 --- a/kernel/power/hibernate_keys.c +++ b/kernel/power/hibernate_keys.c @@ -17,6 +17,7 @@ struct forward_info { static void *skey_data; static void *forward_info_buf; static unsigned long skey_dsize; +static bool sig_enforce = false; bool swsusp_page_is_sign_key(struct page *page) { @@ -52,6 +53,7 @@ void fill_sig_forward_info(void *page, int sig_check_ret_in) memset(page, 0, PAGE_SIZE); info = (struct forward_info *)page; + info->head.sig_enforce = sig_enforce; info->head.sig_check_ret = sig_check_ret_in; if (skey_data && !IS_ERR(skey_data) && skey_dsize <= SKEY_DBUF_MAX_SIZE) { @@ -74,6 +76,11 @@ void restore_sig_forward_info(void) } info = (struct forward_info *)forward_info_buf; + /* eanble sig_enforce either boot kernel or resume target kernel set it */ + sig_enforce = sig_enforce || info->head.sig_enforce; + if (sig_enforce) + pr_info("PM: Enforce S4 snapshot signature check\n"); + sig_check_ret = info->head.sig_check_ret; if (sig_check_ret) pr_info("PM: Signature check fail: %d\n", sig_check_ret); @@ -89,6 +96,14 @@ void restore_sig_forward_info(void) /* reset skey page buffer */ memset(forward_info_buf, 0, PAGE_SIZE); + + /* taint kernel */ + if (!sig_enforce && sig_check_ret) { + pr_warning("PM: Hibernate signature check fail, system " + "restored from unsafe snapshot: tainting kernel\n"); + add_taint(TAINT_UNSAFE_HIBERNATE, LOCKDEP_STILL_OK); + pr_info("%s\n", print_tainted()); + } } bool skey_data_available(void) @@ -275,6 +290,17 @@ size_t get_key_length(const struct key *key) return len; } +void enforce_signed_snapshot(void) +{ + sig_enforce = true; + pr_info("PM: Enforce signature verification of hibernate snapshot\n"); +} + +bool sig_enforced(void) +{ + return sig_enforce; +} + static int __init init_sign_key_data(void) { skey_data = (void *)get_zeroed_page(GFP_KERNEL); @@ -290,3 +316,12 @@ static int __init init_sign_key_data(void) } late_initcall(init_sign_key_data); + +static int __init sig_enforce_setup(char *str) +{ + sig_enforce = true; + pr_info("PM: Enforce signature verification of hibernate snapshot\n"); + return 1; +} + +__setup("snapshot_sig_enforce", sig_enforce_setup); diff --git a/kernel/power/power.h b/kernel/power/power.h index d2da75b..4f411ac 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -187,6 +187,7 @@ extern void restore_sig_forward_info(void); extern bool swsusp_page_is_sign_key(struct page *page); extern unsigned long get_sig_forward_info_pfn(void); extern void fill_sig_forward_info(void *page_addr, int sig_check_ret); +extern bool sig_enforced(void); #else static inline bool skey_data_available(void) { diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index d3e14aa..8a166e1 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -2581,7 +2581,11 @@ int snapshot_image_verify(void) pr_info("PM: snapshot signature check SUCCESS!\n"); forward_ret: - snapshot_fill_sig_forward_info(ret); + /* forward check result when pass or not enforce verify success */ + if (!ret || !sig_enforced()) { + snapshot_fill_sig_forward_info(ret); + ret = 0; + } error_shash: kfree(handle_buffers); kfree(digest); -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html