From patchwork Sun Sep 15 00:56:57 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 2894141 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 14C9A9F1F1 for ; Sun, 15 Sep 2013 00:59:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 073B6202EC for ; Sun, 15 Sep 2013 00:59:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DD16E202C0 for ; Sun, 15 Sep 2013 00:59:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756939Ab3IOA61 (ORCPT ); Sat, 14 Sep 2013 20:58:27 -0400 Received: from mail-bk0-f45.google.com ([209.85.214.45]:40436 "EHLO mail-bk0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756853Ab3IOA6X (ORCPT ); Sat, 14 Sep 2013 20:58:23 -0400 Received: by mail-bk0-f45.google.com with SMTP id mx11so999813bkb.32 for ; Sat, 14 Sep 2013 17:58:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=nyfx9+mWHRXaXovLKUfwMoH+8C5BdFdZ519FqXhV3SQ=; b=ZhG0O0k8ExpECHwfxq78hiZ5EUV5bzdNQvc5ktIUO6d/RPFMxLzsi+NTWQ8BBTclL8 DfRS28YQKpiVSFkzxKX8NfmgjxcTfA2ETiCgzxvrNpUVP62susFonDJRtWbR0RUM7sby GpZA5Ld6mizxPMMvrSy5gJgK+joK674UKnVXP1x9K5NG0jjJler/UF9zvdZOj5T0/rw9 xIfDZ0kZ28Od+h7pn4nUql8sm0LysUhQn3mGcSJy0zTGR9Fa17fV9o99AZ3jL77SdYF2 bhCcyCtQiNhEg+U58tARenTDwxNERVyjEeu4asHdVY+eB/Pf86L1vw9gef4V9xdNiGEI VPRw== X-Received: by 10.205.36.70 with SMTP id sz6mr17669086bkb.12.1379206701645; Sat, 14 Sep 2013 17:58:21 -0700 (PDT) Received: from localhost.localdomain ([124.11.22.254]) by mx.google.com with ESMTPSA id zl3sm4941613bkb.4.1969.12.31.16.00.00 (version=TLSv1 cipher=RC4-SHA bits=128/128); Sat, 14 Sep 2013 17:58:21 -0700 (PDT) From: "Lee, Chun-Yi" To: linux-kernel@vger.kernel.org Cc: linux-security-module@vger.kernel.org, linux-efi@vger.kernel.org, linux-pm@vger.kernel.org, linux-crypto@vger.kernel.org, opensuse-kernel@opensuse.org, David Howells , "Rafael J. Wysocki" , Matthew Garrett , Len Brown , Pavel Machek , Josh Boyer , Vojtech Pavlik , Matt Fleming , James Bottomley , Greg KH , JKosina@suse.com, Rusty Russell , Herbert Xu , "David S. Miller" , "H. Peter Anvin" , Michal Marek , Gary Lin , Vivek Goyal , "Lee, Chun-Yi" Subject: [PATCH V4 11/15] Hibernate: taint kernel when signature check fail Date: Sun, 15 Sep 2013 08:56:57 +0800 Message-Id: <1379206621-18639-12-git-send-email-jlee@suse.com> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: <1379206621-18639-1-git-send-email-jlee@suse.com> References: <1379206621-18639-1-git-send-email-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, KHOP_BIG_TO_CC, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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);