Lee, Chun-Yi 5b696a
From 9f5eff10f723d39ddac3ed9300cb3246e9298156 Mon Sep 17 00:00:00 2001
Lee, Chun-Yi 5b696a
From: "Lee, Chun-Yi" <jlee@suse.com>
Lee, Chun-Yi 5b696a
Date: Tue, 12 Dec 2017 14:55:01 +0800
Lee, Chun-Yi 5b696a
Subject: [PATCH 07/11] PM / hibernate: encrypt hidden area
Lee, Chun-Yi 5b696a
Patch-mainline: No, will be submitted to upstream
Lee, Chun-Yi 5b696a
References: fate#316350
Lee, Chun-Yi 5b696a
Lee, Chun-Yi 5b696a
The hidden area keeps sensitive data (symmetric key, password...) that
Lee, Chun-Yi 5b696a
it can not be leaked to user space. So the hidden area page is ignored
Lee, Chun-Yi 5b696a
by snapshot process. But it causes that the hidden area is empty after
Lee, Chun-Yi 5b696a
system resumed, then all sensitive data are lost.
Lee, Chun-Yi 5b696a
Lee, Chun-Yi 5b696a
The idea against this situation is that using EFI secret key to
Lee, Chun-Yi 5b696a
encrypt/backup the hidden area when producing snapshot image, then
Lee, Chun-Yi 5b696a
decrypt/restore hidden area after system resumed. In resuming process,
Lee, Chun-Yi 5b696a
the boot kernel must transfers secret key to target kernel, otherwise
Lee, Chun-Yi 5b696a
target kernel doesn't have secret key to decrypt hidden area because
Lee, Chun-Yi 5b696a
hidden area (including secret key) was ignored by snapshot.
Lee, Chun-Yi 5b696a
Lee, Chun-Yi 5b696a
For transferring secret key to targer kernel, hibernation creates a
Lee, Chun-Yi 5b696a
trampoline page in snapshot image. The trampoline page can be used
Lee, Chun-Yi 5b696a
by boot kernel to fill in secret key before whole system be restored
Lee, Chun-Yi 5b696a
from snapshot image. After system is restored, kernel uses the secret
Lee, Chun-Yi 5b696a
key in trampoline page to decrypt/restore hidden area. Then all
Lee, Chun-Yi 5b696a
sensitive data are back.
Lee, Chun-Yi 5b696a
Lee, Chun-Yi 5b696a
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
Lee, Chun-Yi 5b696a
---
Lee, Chun-Yi 5b696a
 kernel/power/hibernate.c |   19 ++++++
Lee, Chun-Yi 5b696a
 kernel/power/power.h     |    5 +
Lee, Chun-Yi 5b696a
 kernel/power/snapshot.c  |  133 +++++++++++++++++++++++++++++++++++++++++++++--
Lee, Chun-Yi 5b696a
 kernel/power/swap.c      |    2 
Lee, Chun-Yi 5b696a
 kernel/power/user.c      |    5 +
Lee, Chun-Yi 5b696a
 5 files changed, 161 insertions(+), 3 deletions(-)
Lee, Chun-Yi 5b696a
Lee, Chun-Yi 5b696a
--- a/kernel/power/hibernate.c
Lee, Chun-Yi 5b696a
+++ b/kernel/power/hibernate.c
Lee, Chun-Yi 5b696a
@@ -32,6 +32,8 @@
Lee, Chun-Yi 5b696a
 #include <linux/ctype.h>
Lee, Chun-Yi 5b696a
 #include <linux/genhd.h>
Lee, Chun-Yi 5b696a
 #include <linux/ktime.h>
Lee, Chun-Yi 5b696a
+#include <linux/efi.h>
Lee, Chun-Yi 5b696a
+#include <linux/security.h>
Lee, Chun-Yi 5b696a
 #include <trace/events/power.h>
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 #include "power.h"
Lee, Chun-Yi 5b696a
@@ -679,12 +681,28 @@ int hibernate(void)
Lee, Chun-Yi 5b696a
 {
Lee, Chun-Yi 5b696a
 	int error, nr_calls = 0;
Lee, Chun-Yi 5b696a
 	bool snapshot_test = false;
Lee, Chun-Yi 5b696a
+	void *secret_key;
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 	if (!hibernation_available()) {
Lee, Chun-Yi 5b696a
 		pr_debug("Hibernation not available.\n");
Lee, Chun-Yi 5b696a
 		return -EPERM;
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
+	error = snapshot_create_trampoline();
Lee, Chun-Yi 5b696a
+	if (error)
Lee, Chun-Yi 5b696a
+		return error;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	/* using EFI secret key to encrypt hidden area */
Lee, Chun-Yi 5b696a
+	secret_key = get_efi_secret_key();
Lee, Chun-Yi 5b696a
+	if (secret_key) {
Lee, Chun-Yi 5b696a
+		error = encrypt_backup_hidden_area(secret_key, SECRET_KEY_SIZE);
Lee, Chun-Yi 5b696a
+		if (error) {
Lee, Chun-Yi 5b696a
+			pr_err("Encrypt hidden area failed: %d\n", error);
Lee, Chun-Yi 5b696a
+			snapshot_free_trampoline();
Lee, Chun-Yi 5b696a
+			return error;
Lee, Chun-Yi 5b696a
+		}
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
 	lock_system_sleep();
Lee, Chun-Yi 5b696a
 	/* The snapshot device should not be opened while we're running */
Lee, Chun-Yi 5b696a
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
Lee, Chun-Yi 5b696a
@@ -740,6 +758,7 @@ int hibernate(void)
Lee, Chun-Yi 5b696a
 		pm_restore_gfp_mask();
Lee, Chun-Yi 5b696a
 	} else {
Lee, Chun-Yi 5b696a
 		pr_debug("Image restored successfully.\n");
Lee, Chun-Yi 5b696a
+		snapshot_restore_trampoline();
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
  Free_bitmaps:
Lee, Chun-Yi 5b696a
--- a/kernel/power/power.h
Lee, Chun-Yi 5b696a
+++ b/kernel/power/power.h
Lee, Chun-Yi 5b696a
@@ -12,6 +12,7 @@ struct swsusp_info {
Lee, Chun-Yi 5b696a
 	unsigned long		image_pages;
Lee, Chun-Yi 5b696a
 	unsigned long		pages;
Lee, Chun-Yi 5b696a
 	unsigned long		size;
Lee, Chun-Yi 5b696a
+	unsigned long           trampoline_pfn;
Lee, Chun-Yi 5b696a
 } __aligned(PAGE_SIZE);
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 #ifdef CONFIG_HIBERNATION
Lee, Chun-Yi 5b696a
@@ -157,6 +158,10 @@ extern int snapshot_read_next(struct sna
Lee, Chun-Yi 5b696a
 extern int snapshot_write_next(struct snapshot_handle *handle);
Lee, Chun-Yi 5b696a
 extern void snapshot_write_finalize(struct snapshot_handle *handle);
Lee, Chun-Yi 5b696a
 extern int snapshot_image_loaded(struct snapshot_handle *handle);
Lee, Chun-Yi 5b696a
+extern int snapshot_create_trampoline(void);
Lee, Chun-Yi 5b696a
+extern void snapshot_init_trampoline(void);
Lee, Chun-Yi 5b696a
+extern void snapshot_restore_trampoline(void);
Lee, Chun-Yi 5b696a
+extern void snapshot_free_trampoline(void);
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 /* If unset, the snapshot device cannot be open. */
Lee, Chun-Yi 5b696a
 extern atomic_t snapshot_device_available;
Lee, Chun-Yi 5b696a
--- a/kernel/power/snapshot.c
Lee, Chun-Yi 5b696a
+++ b/kernel/power/snapshot.c
Lee, Chun-Yi 5b696a
@@ -31,6 +31,7 @@
Lee, Chun-Yi 5b696a
 #include <linux/compiler.h>
Lee, Chun-Yi 5b696a
 #include <linux/ktime.h>
Lee, Chun-Yi 5b696a
 #include <linux/security.h>
Lee, Chun-Yi 5b696a
+#include <linux/efi.h>
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 #include <linux/uaccess.h>
Lee, Chun-Yi 5b696a
 #include <asm/mmu_context.h>
Lee, Chun-Yi 5b696a
@@ -80,6 +81,24 @@ static inline void hibernate_restore_pro
Lee, Chun-Yi 5b696a
 static inline void hibernate_restore_unprotect_page(void *page_address) {}
Takashi Iwai 68d869
 #endif /* CONFIG_STRICT_KERNEL_RWX  && CONFIG_ARCH_HAS_SET_MEMORY */
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
+/*
Lee, Chun-Yi 5b696a
+ * The trampoline is used to forward information from boot kernel
Lee, Chun-Yi 5b696a
+ * to image kernel.
Lee, Chun-Yi 5b696a
+ */
Lee, Chun-Yi 5b696a
+struct trampoline {
Lee, Chun-Yi 5b696a
+	bool secret_key_valid;
Lee, Chun-Yi 5b696a
+	u8 secret_key[SECRET_KEY_SIZE];
Lee, Chun-Yi 5b696a
+};
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/* the trampoline is used by image kernel */
Lee, Chun-Yi 5b696a
+static void *trampoline_virt;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/* trampoline pfn from swsusp_info in snapshot for snapshot_write_next() */
Lee, Chun-Yi 5b696a
+static unsigned long trampoline_pfn;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/* Keep the buffer for foward page in snapshot_write_next() */
Lee, Chun-Yi 5b696a
+static void *trampoline_buff;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
 static int swsusp_page_is_free(struct page *);
Lee, Chun-Yi 5b696a
 static void swsusp_set_page_forbidden(struct page *);
Lee, Chun-Yi 5b696a
 static void swsusp_unset_page_forbidden(struct page *);
Lee, Chun-Yi 5b696a
@@ -2048,10 +2067,109 @@ static int init_header(struct swsusp_inf
Lee, Chun-Yi 5b696a
 	info->pages = snapshot_get_image_size();
Lee, Chun-Yi 5b696a
 	info->size = info->pages;
Lee, Chun-Yi 5b696a
 	info->size <<= PAGE_SHIFT;
Lee, Chun-Yi 5b696a
+	info->trampoline_pfn = page_to_pfn(virt_to_page(trampoline_virt));
Lee, Chun-Yi 5b696a
 	return init_header_complete(info);
Lee, Chun-Yi 5b696a
 }
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 /**
Lee, Chun-Yi 5b696a
+ * create trampoline - Create a trampoline page before snapshot be created
Lee, Chun-Yi 5b696a
+ * In hibernation process, this routine will be called by kernel before
Lee, Chun-Yi 5b696a
+ * the snapshot image be created. It can be used in resuming process.
Lee, Chun-Yi 5b696a
+ */
Lee, Chun-Yi 5b696a
+int snapshot_create_trampoline(void)
Lee, Chun-Yi 5b696a
+{
Lee, Chun-Yi 5b696a
+	if (trampoline_virt) {
Lee, Chun-Yi 5b696a
+		pr_warn("PM: Tried to create trampoline again\n");
Lee, Chun-Yi 5b696a
+		return 0;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	trampoline_virt = (void *)get_zeroed_page(GFP_KERNEL);
Lee, Chun-Yi 5b696a
+	if (!trampoline_virt) {
Lee, Chun-Yi 5b696a
+		pr_err("PM: Allocate trampoline page failed\n");
Lee, Chun-Yi 5b696a
+		return -ENOMEM;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+	trampoline_pfn = 0;
Lee, Chun-Yi 5b696a
+	trampoline_buff = NULL;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	return 0;
Lee, Chun-Yi 5b696a
+}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/**
Lee, Chun-Yi 5b696a
+ * initial trampoline - Put data to trampoline buffer for target kernel
Lee, Chun-Yi 5b696a
+ *
Lee, Chun-Yi 5b696a
+ * In resuming process, this routine will be called by boot kernel before
Lee, Chun-Yi 5b696a
+ * the target kernel be restored. The boot kernel uses trampoline buffer
Lee, Chun-Yi 5b696a
+ * to transfer information to target kernel.
Lee, Chun-Yi 5b696a
+ */
Lee, Chun-Yi 5b696a
+void snapshot_init_trampoline(void)
Lee, Chun-Yi 5b696a
+{
Lee, Chun-Yi 5b696a
+	struct trampoline *t;
Lee, Chun-Yi 5b696a
+	void *efi_secret_key;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	if (!trampoline_pfn || !trampoline_buff) {
Lee, Chun-Yi 5b696a
+		pr_err("PM: Did not find trampoline buffer, pfn: %ld\n",
Lee, Chun-Yi 5b696a
+			trampoline_pfn);
Lee, Chun-Yi 5b696a
+		return;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	hibernate_restore_unprotect_page(trampoline_buff);
Lee, Chun-Yi 5b696a
+	memset(trampoline_buff, 0, PAGE_SIZE);
Lee, Chun-Yi 5b696a
+	t = (struct trampoline *)trampoline_buff;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	efi_secret_key = get_efi_secret_key();
Lee, Chun-Yi 5b696a
+	if (efi_secret_key) {
Lee, Chun-Yi 5b696a
+		memset(t->secret_key, 0, SECRET_KEY_SIZE);
Lee, Chun-Yi 5b696a
+		memcpy(t->secret_key, efi_secret_key, SECRET_KEY_SIZE);
Lee, Chun-Yi 5b696a
+		t->secret_key_valid = true;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+	pr_info("PM: Hibernation trampoline page prepared\n");
Lee, Chun-Yi 5b696a
+}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/**
Lee, Chun-Yi 5b696a
+ * restore trampoline - Handle the data from boot kernel and free.
Lee, Chun-Yi 5b696a
+ *
Lee, Chun-Yi 5b696a
+ * In resuming process, this routine will be called by target kernel
Lee, Chun-Yi 5b696a
+ * after target kernel is restored. The target kernel handles
Lee, Chun-Yi 5b696a
+ * the data in trampoline that it is transferred from boot kernel.
Lee, Chun-Yi 5b696a
+ */
Lee, Chun-Yi 5b696a
+void snapshot_restore_trampoline(void)
Lee, Chun-Yi 5b696a
+{
Lee, Chun-Yi 5b696a
+	struct trampoline *t;
Lee, Chun-Yi 5b696a
+	int ret;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	if (!trampoline_virt) {
Lee, Chun-Yi 5b696a
+		pr_err("PM: Doesn't have trampoline page\n");
Lee, Chun-Yi 5b696a
+		return;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	t = (struct trampoline *)trampoline_virt;
Lee, Chun-Yi 5b696a
+	if (t->secret_key_valid) {
Lee, Chun-Yi 5b696a
+		ret = decrypt_restore_hidden_area(t->secret_key, SECRET_KEY_SIZE);
Lee, Chun-Yi 5b696a
+		if (ret)
Lee, Chun-Yi 5b696a
+			pr_err("PM: Decrypted hidden area failed: %d\n", ret);
Lee, Chun-Yi 5b696a
+		else
Lee, Chun-Yi 5b696a
+			pr_info("PM: Hidden area decrypted\n");
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	snapshot_free_trampoline();
Lee, Chun-Yi 5b696a
+}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+void snapshot_free_trampoline(void)
Lee, Chun-Yi 5b696a
+{
Lee, Chun-Yi 5b696a
+	if (!trampoline_virt) {
Lee, Chun-Yi 5b696a
+		pr_err("PM: No trampoline page can be freed\n");
Lee, Chun-Yi 5b696a
+		return;
Lee, Chun-Yi 5b696a
+	}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+	trampoline_pfn = 0;
Lee, Chun-Yi 5b696a
+	trampoline_buff = NULL;
Lee, Chun-Yi 5b696a
+	memset(trampoline_virt, 0, PAGE_SIZE);
Lee, Chun-Yi 5b696a
+	free_page((unsigned long)trampoline_virt);
Lee, Chun-Yi 5b696a
+	trampoline_virt = NULL;
Lee, Chun-Yi 5b696a
+	pr_info("PM: Trampoline freed\n");
Lee, Chun-Yi 5b696a
+}
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
+/**
Lee, Chun-Yi 5b696a
  * pack_pfns - Prepare PFNs for saving.
Lee, Chun-Yi 5b696a
  * @bm: Memory bitmap.
Lee, Chun-Yi 5b696a
  * @buf: Memory buffer to store the PFNs in.
Lee, Chun-Yi 5b696a
@@ -2198,6 +2316,7 @@ static int load_header(struct swsusp_inf
Lee, Chun-Yi 5b696a
 	if (!error) {
Lee, Chun-Yi 5b696a
 		nr_copy_pages = info->image_pages;
Lee, Chun-Yi 5b696a
 		nr_meta_pages = info->pages - info->image_pages - 1;
Lee, Chun-Yi 5b696a
+		trampoline_pfn = info->trampoline_pfn;
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
 	return error;
Lee, Chun-Yi 5b696a
 }
Lee, Chun-Yi 5b696a
@@ -2531,7 +2650,8 @@ static int prepare_image(struct memory_b
Lee, Chun-Yi 5b696a
  * Get the address that snapshot_write_next() should return to its caller to
Lee, Chun-Yi 5b696a
  * write to.
Lee, Chun-Yi 5b696a
  */
Lee, Chun-Yi 5b696a
-static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
Lee, Chun-Yi 5b696a
+static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca,
Lee, Chun-Yi 5b696a
+			unsigned long *pfn_out)
Lee, Chun-Yi 5b696a
 {
Lee, Chun-Yi 5b696a
 	struct pbe *pbe;
Lee, Chun-Yi 5b696a
 	struct page *page;
Lee, Chun-Yi 5b696a
@@ -2540,6 +2660,9 @@ static void *get_buffer(struct memory_bi
Lee, Chun-Yi 5b696a
 	if (pfn == BM_END_OF_MAP)
Lee, Chun-Yi 5b696a
 		return ERR_PTR(-EFAULT);
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
+	if (pfn_out)
Lee, Chun-Yi 5b696a
+		*pfn_out = pfn;
Lee, Chun-Yi 5b696a
+
Lee, Chun-Yi 5b696a
 	page = pfn_to_page(pfn);
Lee, Chun-Yi 5b696a
 	if (PageHighMem(page))
Lee, Chun-Yi 5b696a
 		return get_highmem_page_buffer(page, ca);
Lee, Chun-Yi 5b696a
@@ -2587,6 +2710,7 @@ static void *get_buffer(struct memory_bi
Lee, Chun-Yi 5b696a
 int snapshot_write_next(struct snapshot_handle *handle)
Lee, Chun-Yi 5b696a
 {
Lee, Chun-Yi 5b696a
 	static struct chain_allocator ca;
Lee, Chun-Yi 5b696a
+	unsigned long pfn;
Lee, Chun-Yi 5b696a
 	int error = 0;
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
 	/* Check if we have already loaded the entire image */
Lee, Chun-Yi 5b696a
@@ -2634,7 +2758,7 @@ int snapshot_write_next(struct snapshot_
Lee, Chun-Yi 5b696a
 			chain_init(&ca, GFP_ATOMIC, PG_SAFE);
Lee, Chun-Yi 5b696a
 			memory_bm_position_reset(&orig_bm);
Lee, Chun-Yi 5b696a
 			restore_pblist = NULL;
Lee, Chun-Yi 5b696a
-			handle->buffer = get_buffer(&orig_bm, &ca);
Lee, Chun-Yi 5b696a
+			handle->buffer = get_buffer(&orig_bm, &ca, &pfn;;
Lee, Chun-Yi 5b696a
 			handle->sync_read = 0;
Lee, Chun-Yi 5b696a
 			if (IS_ERR(handle->buffer))
Lee, Chun-Yi 5b696a
 				return PTR_ERR(handle->buffer);
Lee, Chun-Yi 5b696a
@@ -2644,11 +2768,14 @@ int snapshot_write_next(struct snapshot_
Lee, Chun-Yi 5b696a
 		/* Restore page key for data page (s390 only). */
Lee, Chun-Yi 5b696a
 		page_key_write(handle->buffer);
Lee, Chun-Yi 5b696a
 		hibernate_restore_protect_page(handle->buffer);
Lee, Chun-Yi 5b696a
-		handle->buffer = get_buffer(&orig_bm, &ca);
Lee, Chun-Yi 5b696a
+		handle->buffer = get_buffer(&orig_bm, &ca, &pfn;;
Lee, Chun-Yi 5b696a
 		if (IS_ERR(handle->buffer))
Lee, Chun-Yi 5b696a
 			return PTR_ERR(handle->buffer);
Lee, Chun-Yi 5b696a
 		if (handle->buffer != buffer)
Lee, Chun-Yi 5b696a
 			handle->sync_read = 0;
Lee, Chun-Yi 5b696a
+		/* Capture the trampoline for transfer data */
Lee, Chun-Yi 5b696a
+		if (pfn == trampoline_pfn && trampoline_pfn)
Lee, Chun-Yi 5b696a
+			trampoline_buff = handle->buffer;
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
 	handle->cur++;
Lee, Chun-Yi 5b696a
 	return PAGE_SIZE;
Lee, Chun-Yi 5b696a
--- a/kernel/power/swap.c
Lee, Chun-Yi 5b696a
+++ b/kernel/power/swap.c
Lee, Chun-Yi 5b696a
@@ -1102,6 +1102,7 @@ static int load_image(struct swap_map_ha
Lee, Chun-Yi 5b696a
 		if (!snapshot_image_loaded(snapshot))
Lee, Chun-Yi 5b696a
 			ret = -ENODATA;
Lee, Chun-Yi 5b696a
 
Lee, Chun-Yi 5b696a
+		snapshot_init_trampoline();
Lee, Chun-Yi 5b696a
 		/* clean the hidden area in boot kernel */
Lee, Chun-Yi 5b696a
 		clean_hidden_area();
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
@@ -1465,6 +1466,7 @@ out_finish:
Lee, Chun-Yi 5b696a
 				}
Lee, Chun-Yi 5b696a
 			}
Lee, Chun-Yi 5b696a
 		}
Lee, Chun-Yi 5b696a
+		snapshot_init_trampoline();
Lee, Chun-Yi 5b696a
 		/* clean the hidden area in boot kernel */
Lee, Chun-Yi 5b696a
 		clean_hidden_area();
Lee, Chun-Yi 5b696a
 	}
Lee, Chun-Yi 5b696a
--- a/kernel/power/user.c
Lee, Chun-Yi 5b696a
+++ b/kernel/power/user.c
Takashi Iwai 68d869
@@ -249,6 +249,7 @@ static long snapshot_ioctl(struct file *
Lee, Chun-Yi 5b696a
 		if (!data->frozen || data->ready)
Lee, Chun-Yi 5b696a
 			break;
Lee, Chun-Yi 5b696a
 		pm_restore_gfp_mask();
Lee, Chun-Yi 5b696a
+		snapshot_restore_trampoline();
Lee, Chun-Yi 5b696a
 		free_basic_memory_bitmaps();
Lee, Chun-Yi 5b696a
 		data->free_bitmaps = false;
Lee, Chun-Yi 5b696a
 		thaw_processes();
Takashi Iwai 68d869
@@ -260,6 +261,9 @@ static long snapshot_ioctl(struct file *
Lee, Chun-Yi 5b696a
 			error = -EPERM;
Lee, Chun-Yi 5b696a
 			break;
Lee, Chun-Yi 5b696a
 		}
Lee, Chun-Yi 5b696a
+		error = snapshot_create_trampoline();
Lee, Chun-Yi 5b696a
+		if (error)
Lee, Chun-Yi 5b696a
+			return error;
Lee, Chun-Yi 5b696a
 		pm_restore_gfp_mask();
Lee, Chun-Yi 5b696a
 		error = hibernation_snapshot(data->platform_support);
Lee, Chun-Yi 5b696a
 		if (!error) {
Takashi Iwai 68d869
@@ -276,6 +280,7 @@ static long snapshot_ioctl(struct file *
Lee, Chun-Yi 5b696a
 			error = -EPERM;
Lee, Chun-Yi 5b696a
 			break;
Lee, Chun-Yi 5b696a
 		}
Lee, Chun-Yi 5b696a
+		snapshot_init_trampoline();
Lee, Chun-Yi 5b696a
 		/* clean the hidden area in boot kernel */
Lee, Chun-Yi 5b696a
 		clean_hidden_area();
Lee, Chun-Yi 5b696a
 		error = hibernation_restore(data->platform_support);