aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/swsusp.c163
1 files changed, 4 insertions, 159 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index c05f46e7348f..bd3097c583bf 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -30,9 +30,6 @@
30 * Alex Badea <vampire@go.ro>: 30 * Alex Badea <vampire@go.ro>:
31 * Fixed runaway init 31 * Fixed runaway init
32 * 32 *
33 * Andreas Steinmetz <ast@domdv.de>:
34 * Added encrypted suspend option
35 *
36 * More state savers are welcome. Especially for the scsi layer... 33 * More state savers are welcome. Especially for the scsi layer...
37 * 34 *
38 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt 35 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
@@ -67,10 +64,6 @@
67#include <asm/tlbflush.h> 64#include <asm/tlbflush.h>
68#include <asm/io.h> 65#include <asm/io.h>
69 66
70#include <linux/random.h>
71#include <linux/crypto.h>
72#include <asm/scatterlist.h>
73
74#include "power.h" 67#include "power.h"
75 68
76#ifdef CONFIG_HIGHMEM 69#ifdef CONFIG_HIGHMEM
@@ -81,10 +74,6 @@ static int save_highmem(void) { return 0; }
81static int restore_highmem(void) { return 0; } 74static int restore_highmem(void) { return 0; }
82#endif 75#endif
83 76
84#define CIPHER "aes"
85#define MAXKEY 32
86#define MAXIV 32
87
88extern char resume_file[]; 77extern char resume_file[];
89 78
90/* Local variables that should not be affected by save */ 79/* Local variables that should not be affected by save */
@@ -102,8 +91,7 @@ suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
102#define SWSUSP_SIG "S1SUSPEND" 91#define SWSUSP_SIG "S1SUSPEND"
103 92
104static struct swsusp_header { 93static struct swsusp_header {
105 char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)]; 94 char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
106 u8 key_iv[MAXKEY+MAXIV];
107 swp_entry_t swsusp_info; 95 swp_entry_t swsusp_info;
108 char orig_sig[10]; 96 char orig_sig[10];
109 char sig[10]; 97 char sig[10];
@@ -123,131 +111,6 @@ static struct swsusp_info swsusp_info;
123static unsigned short swapfile_used[MAX_SWAPFILES]; 111static unsigned short swapfile_used[MAX_SWAPFILES];
124static unsigned short root_swap; 112static unsigned short root_swap;
125 113
126static int write_page(unsigned long addr, swp_entry_t *loc);
127static int bio_read_page(pgoff_t page_off, void *page);
128
129static u8 key_iv[MAXKEY+MAXIV];
130
131#ifdef CONFIG_SWSUSP_ENCRYPT
132
133static int crypto_init(int mode, void **mem)
134{
135 int error = 0;
136 int len;
137 char *modemsg;
138 struct crypto_tfm *tfm;
139
140 modemsg = mode ? "suspend not possible" : "resume not possible";
141
142 tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
143 if(!tfm) {
144 printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg);
145 error = -EINVAL;
146 goto out;
147 }
148
149 if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) {
150 printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg);
151 error = -ENOKEY;
152 goto fail;
153 }
154
155 if (mode)
156 get_random_bytes(key_iv, MAXKEY+MAXIV);
157
158 len = crypto_tfm_alg_max_keysize(tfm);
159 if (len > MAXKEY)
160 len = MAXKEY;
161
162 if (crypto_cipher_setkey(tfm, key_iv, len)) {
163 printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg);
164 error = -EKEYREJECTED;
165 goto fail;
166 }
167
168 len = crypto_tfm_alg_ivsize(tfm);
169
170 if (MAXIV < len) {
171 printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg);
172 error = -EOVERFLOW;
173 goto fail;
174 }
175
176 crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len);
177
178 *mem=(void *)tfm;
179
180 goto out;
181
182fail: crypto_free_tfm(tfm);
183out: return error;
184}
185
186static __inline__ void crypto_exit(void *mem)
187{
188 crypto_free_tfm((struct crypto_tfm *)mem);
189}
190
191static __inline__ int crypto_write(struct pbe *p, void *mem)
192{
193 int error = 0;
194 struct scatterlist src, dst;
195
196 src.page = virt_to_page(p->address);
197 src.offset = 0;
198 src.length = PAGE_SIZE;
199 dst.page = virt_to_page((void *)&swsusp_header);
200 dst.offset = 0;
201 dst.length = PAGE_SIZE;
202
203 error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src,
204 PAGE_SIZE);
205
206 if (!error)
207 error = write_page((unsigned long)&swsusp_header,
208 &(p->swap_address));
209 return error;
210}
211
212static __inline__ int crypto_read(struct pbe *p, void *mem)
213{
214 int error = 0;
215 struct scatterlist src, dst;
216
217 error = bio_read_page(swp_offset(p->swap_address), (void *)p->address);
218 if (!error) {
219 src.offset = 0;
220 src.length = PAGE_SIZE;
221 dst.offset = 0;
222 dst.length = PAGE_SIZE;
223 src.page = dst.page = virt_to_page((void *)p->address);
224
225 error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst,
226 &src, PAGE_SIZE);
227 }
228 return error;
229}
230#else
231static __inline__ int crypto_init(int mode, void *mem)
232{
233 return 0;
234}
235
236static __inline__ void crypto_exit(void *mem)
237{
238}
239
240static __inline__ int crypto_write(struct pbe *p, void *mem)
241{
242 return write_page(p->address, &(p->swap_address));
243}
244
245static __inline__ int crypto_read(struct pbe *p, void *mem)
246{
247 return bio_read_page(swp_offset(p->swap_address), (void *)p->address);
248}
249#endif
250
251static int mark_swapfiles(swp_entry_t prev) 114static int mark_swapfiles(swp_entry_t prev)
252{ 115{
253 int error; 116 int error;
@@ -259,7 +122,6 @@ static int mark_swapfiles(swp_entry_t prev)
259 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { 122 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
260 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); 123 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
261 memcpy(swsusp_header.sig,SWSUSP_SIG, 10); 124 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
262 memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
263 swsusp_header.swsusp_info = prev; 125 swsusp_header.swsusp_info = prev;
264 error = rw_swap_page_sync(WRITE, 126 error = rw_swap_page_sync(WRITE,
265 swp_entry(root_swap, 0), 127 swp_entry(root_swap, 0),
@@ -405,10 +267,6 @@ static int data_write(void)
405 int error = 0, i = 0; 267 int error = 0, i = 0;
406 unsigned int mod = nr_copy_pages / 100; 268 unsigned int mod = nr_copy_pages / 100;
407 struct pbe *p; 269 struct pbe *p;
408 void *tfm;
409
410 if ((error = crypto_init(1, &tfm)))
411 return error;
412 270
413 if (!mod) 271 if (!mod)
414 mod = 1; 272 mod = 1;
@@ -417,14 +275,11 @@ static int data_write(void)
417 for_each_pbe (p, pagedir_nosave) { 275 for_each_pbe (p, pagedir_nosave) {
418 if (!(i%mod)) 276 if (!(i%mod))
419 printk( "\b\b\b\b%3d%%", i / mod ); 277 printk( "\b\b\b\b%3d%%", i / mod );
420 if ((error = crypto_write(p, tfm))) { 278 if ((error = write_page(p->address, &p->swap_address)))
421 crypto_exit(tfm);
422 return error; 279 return error;
423 }
424 i++; 280 i++;
425 } 281 }
426 printk("\b\b\b\bdone\n"); 282 printk("\b\b\b\bdone\n");
427 crypto_exit(tfm);
428 return error; 283 return error;
429} 284}
430 285
@@ -550,7 +405,6 @@ static int write_suspend_image(void)
550 if ((error = close_swap())) 405 if ((error = close_swap()))
551 goto FreePagedir; 406 goto FreePagedir;
552 Done: 407 Done:
553 memset(key_iv, 0, MAXKEY+MAXIV);
554 return error; 408 return error;
555 FreePagedir: 409 FreePagedir:
556 free_pagedir_entries(); 410 free_pagedir_entries();
@@ -812,8 +666,6 @@ static int check_sig(void)
812 return error; 666 return error;
813 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { 667 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
814 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); 668 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
815 memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV);
816 memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV);
817 669
818 /* 670 /*
819 * Reset swap signature now. 671 * Reset swap signature now.
@@ -840,10 +692,6 @@ static int data_read(struct pbe *pblist)
840 int error = 0; 692 int error = 0;
841 int i = 0; 693 int i = 0;
842 int mod = swsusp_info.image_pages / 100; 694 int mod = swsusp_info.image_pages / 100;
843 void *tfm;
844
845 if ((error = crypto_init(0, &tfm)))
846 return error;
847 695
848 if (!mod) 696 if (!mod)
849 mod = 1; 697 mod = 1;
@@ -855,15 +703,13 @@ static int data_read(struct pbe *pblist)
855 if (!(i % mod)) 703 if (!(i % mod))
856 printk("\b\b\b\b%3d%%", i / mod); 704 printk("\b\b\b\b%3d%%", i / mod);
857 705
858 if ((error = crypto_read(p, tfm))) { 706 if ((error = bio_read_page(swp_offset(p->swap_address),
859 crypto_exit(tfm); 707 (void *)p->address)))
860 return error; 708 return error;
861 }
862 709
863 i++; 710 i++;
864 } 711 }
865 printk("\b\b\b\bdone\n"); 712 printk("\b\b\b\bdone\n");
866 crypto_exit(tfm);
867 return error; 713 return error;
868} 714}
869 715
@@ -986,7 +832,6 @@ int swsusp_read(void)
986 832
987 error = read_suspend_image(); 833 error = read_suspend_image();
988 blkdev_put(resume_bdev); 834 blkdev_put(resume_bdev);
989 memset(key_iv, 0, MAXKEY+MAXIV);
990 835
991 if (!error) 836 if (!error)
992 pr_debug("swsusp: Reading resume file was successful\n"); 837 pr_debug("swsusp: Reading resume file was successful\n");