mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: linux-efi@vger.kernel.org, linux-pm@vger.kernel.org,
	"Rafael J. Wysocki" <rjw@sisk.pl>,
	Matthew Garrett <matthew.garrett@nebula.com>,
	Len Brown <len.brown@intel.com>, Pavel Machek <pavel@ucw.cz>,
	Josh Boyer <jwboyer@redhat.com>, Vojtech Pavlik <vojtech@suse.cz>,
	Matt Fleming <matt.fleming@intel.com>,
	Jiri Kosina <jkosina@suse.cz>, "H. Peter Anvin" <hpa@zytor.com>,
	"Lee, Chun-Yi" <jlee@suse.com>
Subject: [RFC PATCH 14/16] PM / hibernate: Allow user trigger swsusp key re-generating
Date: Thu, 16 Jul 2015 22:25:28 +0800	[thread overview]
Message-ID: <1437056730-15247-15-git-send-email-jlee@suse.com> (raw)
In-Reply-To: <1437056730-15247-1-git-send-email-jlee@suse.com>

This patch provides a ioctl for triggering swsusp key re-generating
process. It's allow user call ioctl to raise the flag of key re-generating.
Kernel writes a flag to a efi runtime variable, the GUID is
S4SignKeyRegen-fe141863-c070-478e-b8a3-878a5dc9ef21, then EFI stub will
re-generates swsusp key when queried flag.

To aviod the swsusp key changes in hibernating cycle that causes hiberne
restoring failed, this flag is only available when system runs normal
reboot or shutdown. The hibernate code will clean the flag when it raised
in a hiberante cycle.

Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 arch/x86/boot/compressed/eboot.c          | 20 +++++++++++---
 arch/x86/power/hibernate_keys.c           |  2 ++
 drivers/firmware/Makefile                 |  1 +
 drivers/firmware/efi/Kconfig              |  4 +++
 drivers/firmware/efi/Makefile             |  1 +
 drivers/firmware/efi/efi-hibernate_keys.c | 43 +++++++++++++++++++++++++++++++
 include/linux/suspend.h                   | 15 +++++++++++
 include/uapi/linux/suspend_ioctls.h       |  3 ++-
 kernel/power/Kconfig                      |  1 +
 kernel/power/hibernate.c                  |  2 ++
 kernel/power/user.c                       |  7 +++++
 kernel/reboot.c                           |  3 +++
 12 files changed, 97 insertions(+), 5 deletions(-)
 create mode 100644 drivers/firmware/efi/efi-hibernate_keys.c

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 5e1476e..b959f83 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1394,9 +1394,10 @@ static void setup_swsusp_keys(struct boot_params *params)
 {
 	struct setup_data *setup_data, *swsusp_setup_data;
 	struct swsusp_keys *swsusp_keys;
+	bool regen_key = false;
 	int size = 0;
-	unsigned long key_size, attributes;
-	efi_status_t status;
+	unsigned long ignore, key_size, attributes;
+	efi_status_t status, reg_status;
 
 	/* Allocate setup_data to carry keys */
 	size = sizeof(struct setup_data) + sizeof(struct swsusp_keys);
@@ -1425,12 +1426,16 @@ static void setup_swsusp_keys(struct boot_params *params)
 		}
 	}
 
-	if (status != EFI_SUCCESS) {
-		efi_printk(sys_table, "Failed to get existing swsusp key\n");
+	reg_status = efi_call_early(get_variable, SWSUSP_KEY_REGEN_FLAG,
+				&EFI_SWSUSP_GUID, NULL, &ignore, &regen_key);
+	if ((status != EFI_SUCCESS) ||
+	   (reg_status == EFI_SUCCESS && regen_key)) {
+		efi_printk(sys_table, "Regenerating swsusp key\n");
 
 		efi_get_random_key(sys_table, params, swsusp_keys->swsusp_key,
 				   SWSUSP_DIGEST_SIZE);
 
+		/* Set new swsusp key to bootservice non-volatile variable */
 		status = efi_call_early(set_variable, SWSUSP_KEY,
 					&EFI_SWSUSP_GUID,
 					SWSUSP_KEY_ATTRIBUTE,
@@ -1438,6 +1443,13 @@ static void setup_swsusp_keys(struct boot_params *params)
 					swsusp_keys->swsusp_key);
 		if (status != EFI_SUCCESS)
 			efi_printk(sys_table, "Failed to set swsusp key\n");
+
+		efi_call_early(get_variable, SWSUSP_KEY, &EFI_SWSUSP_GUID,
+				NULL, &key_size, swsusp_keys->swsusp_key);
+
+		/* Clean key regenerate flag */
+		efi_call_early(set_variable, SWSUSP_KEY_REGEN_FLAG,
+				&EFI_SWSUSP_GUID, 0, 0, NULL);
 	}
 
 clean_fail:
diff --git a/arch/x86/power/hibernate_keys.c b/arch/x86/power/hibernate_keys.c
index 9a0f3b3..76811d4 100644
--- a/arch/x86/power/hibernate_keys.c
+++ b/arch/x86/power/hibernate_keys.c
@@ -165,6 +165,8 @@ static int __init init_hibernate_keys(void)
 	memblock_free(keys_phys_addr, sizeof(struct swsusp_keys));
 	keys_phys_addr = 0;
 
+	set_swsusp_key_regen_flag = false;
+
 	return ret;
 }
 
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 4a4b897..51b0c38 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -19,3 +19,4 @@ obj-y				+= broadcom/
 obj-$(CONFIG_GOOGLE_FIRMWARE)	+= google/
 obj-$(CONFIG_EFI)		+= efi/
 obj-$(CONFIG_UEFI_CPER)		+= efi/
+obj-$(CONFIG_EFI_SWSUSP_KEYS)	+= efi/
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 54071c1..de3df38 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -69,3 +69,7 @@ endmenu
 
 config UEFI_CPER
 	bool
+
+config EFI_SWSUSP_KEYS
+	bool
+	select EFI_VARS
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index 6fd3da9..98d9fbc 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_EFI)			+= efi.o vars.o reboot.o
 obj-$(CONFIG_EFI_VARS)			+= efivars.o
 obj-$(CONFIG_EFI_ESRT)			+= esrt.o
 obj-$(CONFIG_EFI_VARS_PSTORE)		+= efi-pstore.o
+obj-$(CONFIG_EFI_SWSUSP_KEYS)		+= efi-hibernate_keys.o
 obj-$(CONFIG_UEFI_CPER)			+= cper.o
 obj-$(CONFIG_EFI_RUNTIME_MAP)		+= runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)	+= runtime-wrappers.o
diff --git a/drivers/firmware/efi/efi-hibernate_keys.c b/drivers/firmware/efi/efi-hibernate_keys.c
new file mode 100644
index 0000000..90ae912
--- /dev/null
+++ b/drivers/firmware/efi/efi-hibernate_keys.c
@@ -0,0 +1,43 @@
+/* EFI variable handler of swsusp key regen flag
+ *
+ * Copyright (C) 2015 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Chun-Yi Lee (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+
+/* Set this flag will creating SWSUSPKeyRegen EFI variable */
+bool set_swsusp_key_regen_flag;
+
+void create_swsusp_key_regen_flag(void)
+{
+	struct efivar_entry *entry = NULL;
+	int err = 0;
+
+	if (!set_swsusp_key_regen_flag)
+		return;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return;
+
+	memcpy(entry->var.VariableName,
+		SWSUSP_KEY_REGEN_FLAG, sizeof(SWSUSP_KEY_REGEN_FLAG));
+	memcpy(&(entry->var.VendorGuid),
+		&EFI_SWSUSP_GUID, sizeof(efi_guid_t));
+
+	err = efivar_entry_set(entry, SWSUSP_KEY_SEED_ATTRIBUTE,
+				sizeof(bool), &set_swsusp_key_regen_flag, NULL);
+	if (err)
+		pr_warn("PM: Set flag of regenerating swsusp key failed: %d\n", err);
+
+	kfree(entry);
+}
+EXPORT_SYMBOL_GPL(create_swsusp_key_regen_flag);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index fc3dde0..db8958c 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -330,6 +330,11 @@ struct platform_hibernation_ops {
 
 #define EFI_SWSUSP_GUID \
 	EFI_GUID(0xfe141863, 0xc070, 0x478e, 0xb8, 0xa3, 0x87, 0x8a, 0x5d, 0xc9, 0xef, 0x21)
+#define SWSUSP_KEY_REGEN_FLAG \
+	((efi_char16_t [15]) { 'S', 'W', 'S', 'U', 'S', 'P', 'K', 'e', 'y', 'R', 'e', 'g', 'e', 'n', 0 })
+#define SWSUSP_KEY_SEED_ATTRIBUTE      (EFI_VARIABLE_NON_VOLATILE | \
+					EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+					EFI_VARIABLE_RUNTIME_ACCESS)
 
 /* HMAC Algorithm of Hibernate Signature */
 #define SWSUSP_HMAC		"hmac(sha1)"
@@ -338,6 +343,16 @@ struct platform_hibernation_ops {
 /* kernel/power/hibernate.c */
 extern int sigenforce;
 
+/* drivers/firmware/efi/efi-hibernate_keys.c */
+extern bool set_swsusp_key_regen_flag;
+
+#ifdef CONFIG_HIBERNATE_VERIFICATION
+/* drivers/firmware/efi/efi-hibernate_keys.c */
+extern void create_swsusp_key_regen_flag(void);
+#else
+static inline void create_swsusp_key_regen_flag(void) {}
+#endif
+
 /* kernel/power/snapshot.c */
 extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
 static inline void __init register_nosave_region(unsigned long b, unsigned long e)
diff --git a/include/uapi/linux/suspend_ioctls.h b/include/uapi/linux/suspend_ioctls.h
index 0b30382..0a08450 100644
--- a/include/uapi/linux/suspend_ioctls.h
+++ b/include/uapi/linux/suspend_ioctls.h
@@ -28,6 +28,7 @@ struct resume_swap_area {
 #define SNAPSHOT_PREF_IMAGE_SIZE	_IO(SNAPSHOT_IOC_MAGIC, 18)
 #define SNAPSHOT_AVAIL_SWAP_SIZE	_IOR(SNAPSHOT_IOC_MAGIC, 19, __kernel_loff_t)
 #define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, __kernel_loff_t)
-#define SNAPSHOT_IOC_MAXNR	20
+#define SNAPSHOT_REGENERATE_KEY		_IO(SNAPSHOT_IOC_MAGIC, 21)
+#define SNAPSHOT_IOC_MAXNR	21
 
 #endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index f2a7e21..7a64bda 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -71,6 +71,7 @@ config HIBERNATE_VERIFICATION
 	depends on HIBERNATION
 	depends on EFI_STUB
 	depends on X86
+	select EFI_SWSUSP_KEYS
 	select CRYPTO_HMAC
 	select CRYPTO_SHA1
 	help
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 2c2cc90..314f268 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -653,6 +653,8 @@ int hibernate(void)
 {
 	int error;
 
+	set_swsusp_key_regen_flag = false;
+
 	if (!hibernation_available()) {
 		pr_debug("PM: Hibernation not available.\n");
 		return -EPERM;
diff --git a/kernel/power/user.c b/kernel/power/user.c
index ffd327a..8bcb051 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -338,6 +338,8 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			error = -EPERM;
 			break;
 		}
+		/* clean flag to avoid swsusp key regenerated */
+		set_swsusp_key_regen_flag = false;
 		/*
 		 * Tasks are frozen and the notifiers have been called with
 		 * PM_HIBERNATION_PREPARE
@@ -351,6 +353,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		break;
 
 	case SNAPSHOT_POWER_OFF:
+		set_swsusp_key_regen_flag = false;
 		if (data->platform_support)
 			error = hibernation_platform_enter();
 		break;
@@ -386,6 +389,10 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		}
 		break;
 
+	case SNAPSHOT_REGENERATE_KEY:
+		set_swsusp_key_regen_flag = !!arg;
+		break;
+
 	default:
 		error = -ENOTTY;
 
diff --git a/kernel/reboot.c b/kernel/reboot.c
index d20c85d..88e51e3 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -213,6 +213,7 @@ void migrate_to_reboot_cpu(void)
  */
 void kernel_restart(char *cmd)
 {
+	create_swsusp_key_regen_flag();
 	kernel_restart_prepare(cmd);
 	migrate_to_reboot_cpu();
 	syscore_shutdown();
@@ -240,6 +241,7 @@ static void kernel_shutdown_prepare(enum system_states state)
  */
 void kernel_halt(void)
 {
+	create_swsusp_key_regen_flag();
 	kernel_shutdown_prepare(SYSTEM_HALT);
 	migrate_to_reboot_cpu();
 	syscore_shutdown();
@@ -256,6 +258,7 @@ EXPORT_SYMBOL_GPL(kernel_halt);
  */
 void kernel_power_off(void)
 {
+	create_swsusp_key_regen_flag();
 	kernel_shutdown_prepare(SYSTEM_POWER_OFF);
 	if (pm_power_off_prepare)
 		pm_power_off_prepare();
-- 
1.8.4.5


  parent reply	other threads:[~2015-07-16 14:27 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-16 14:25 [RFC PATCH 00/16] Signature verification of hibernate snapshot Lee, Chun-Yi
2015-07-16 14:25 ` [RFC PATCH 01/16] PM / hibernate: define HMAC algorithm and digest size of swsusp Lee, Chun-Yi
2015-07-28 12:01   ` Pavel Machek
2015-07-31 10:08     ` joeyli
2015-07-31 12:49       ` Pavel Machek
2015-07-31 15:46         ` joeyli
2015-07-16 14:25 ` [RFC PATCH 02/16] x86/efi: Add get and set variable to EFI services pointer table Lee, Chun-Yi
2015-07-30 15:19   ` Matt Fleming
2015-07-31 10:14     ` joeyli
2015-07-16 14:25 ` [RFC PATCH 03/16] x86/boot: Public getting random boot function Lee, Chun-Yi
2015-07-28 12:21   ` Pavel Machek
2015-07-31 10:52     ` joeyli
2015-07-31 12:50       ` Pavel Machek
2015-07-16 14:25 ` [RFC PATCH 04/16] x86/efi: Generating random number in EFI stub Lee, Chun-Yi
2015-07-28 12:01   ` Pavel Machek
2015-07-31  9:06     ` joeyli
2015-07-30 15:37   ` Matt Fleming
2015-07-31  9:12     ` joeyli
2015-07-16 14:25 ` [RFC PATCH 05/16] x86/efi: Get entropy through EFI random number generator protocol Lee, Chun-Yi
2015-07-28 12:28   ` Pavel Machek
2015-07-31  9:58     ` joeyli
2015-07-31 12:01       ` Matt Fleming
2015-07-31 16:05         ` joeyli
2015-07-30 16:11   ` Matt Fleming
2015-07-31 14:59     ` joeyli
2015-07-31 15:01       ` joeyli
2015-07-16 14:25 ` [RFC PATCH 06/16] x86/efi: Generating random HMAC key for siging hibernate image Lee, Chun-Yi
2015-07-28 12:30   ` Pavel Machek
2015-07-31 10:56     ` joeyli
2015-07-30 16:20   ` Matt Fleming
2015-07-31 15:09     ` joeyli
2015-07-16 14:25 ` [RFC PATCH 07/16] efi: Public the function of transferring EFI status to kernel error Lee, Chun-Yi
2015-07-30 16:23   ` Matt Fleming
2015-07-31 15:11     ` joeyli
2015-08-02  0:23     ` Valdis.Kletnieks
2015-07-16 14:25 ` [RFC PATCH 08/16] x86/efi: Carrying swsusp key by setup data Lee, Chun-Yi
2015-07-30 16:30   ` Matt Fleming
2015-07-31 15:31     ` joeyli
2015-07-16 14:25 ` [RFC PATCH 09/16] PM / hibernate: Reserve swsusp key and earse footprints Lee, Chun-Yi
2015-07-28 12:35   ` Pavel Machek
2015-07-31 15:43     ` joeyli
2015-07-16 14:25 ` [RFC PATCH 10/16] PM / hibernate: Generate and verify signature of hibernate snapshot Lee, Chun-Yi
2015-07-16 14:25 ` [RFC PATCH 11/16] PM / hibernate: Avoid including swsusp key to hibernate image Lee, Chun-Yi
2015-07-16 14:25 ` [RFC PATCH 12/16] PM / hibernate: Forward signature verifying result and key to image kernel Lee, Chun-Yi
2015-07-16 14:25 ` [RFC PATCH 13/16] PM / hibernate: Add configuration to enforce signature verification Lee, Chun-Yi
2015-07-16 14:25 ` Lee, Chun-Yi [this message]
2015-07-16 14:25 ` [RFC PATCH 15/16] PM / hibernate: Bypass verification logic on legacy BIOS Lee, Chun-Yi
2015-07-16 14:25 ` [RFC PATCH 16/16] PM / hibernate: Document signature verification of hibernate snapshot Lee, Chun-Yi
2015-07-24 17:08 ` [RFC PATCH 00/16] Signature " Jiri Kosina
2015-07-24 20:08   ` Rafael J. Wysocki
2015-07-28 12:09     ` Matt Fleming
2015-07-25 14:32   ` joeyli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1437056730-15247-15-git-send-email-jlee@suse.com \
    --to=joeyli.kernel@gmail.com \
    --cc=hpa@zytor.com \
    --cc=jkosina@suse.cz \
    --cc=jlee@suse.com \
    --cc=jwboyer@redhat.com \
    --cc=len.brown@intel.com \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=matt.fleming@intel.com \
    --cc=matthew.garrett@nebula.com \
    --cc=pavel@ucw.cz \
    --cc=rjw@sisk.pl \
    --cc=vojtech@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®