diff options
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r-- | kernel/power/swsusp.c | 163 |
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; } | |||
81 | static int restore_highmem(void) { return 0; } | 74 | static 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 | |||
88 | extern char resume_file[]; | 77 | extern 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 | ||
104 | static struct swsusp_header { | 93 | static 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; | |||
123 | static unsigned short swapfile_used[MAX_SWAPFILES]; | 111 | static unsigned short swapfile_used[MAX_SWAPFILES]; |
124 | static unsigned short root_swap; | 112 | static unsigned short root_swap; |
125 | 113 | ||
126 | static int write_page(unsigned long addr, swp_entry_t *loc); | ||
127 | static int bio_read_page(pgoff_t page_off, void *page); | ||
128 | |||
129 | static u8 key_iv[MAXKEY+MAXIV]; | ||
130 | |||
131 | #ifdef CONFIG_SWSUSP_ENCRYPT | ||
132 | |||
133 | static 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 | |||
182 | fail: crypto_free_tfm(tfm); | ||
183 | out: return error; | ||
184 | } | ||
185 | |||
186 | static __inline__ void crypto_exit(void *mem) | ||
187 | { | ||
188 | crypto_free_tfm((struct crypto_tfm *)mem); | ||
189 | } | ||
190 | |||
191 | static __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 | |||
212 | static __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 | ||
231 | static __inline__ int crypto_init(int mode, void *mem) | ||
232 | { | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static __inline__ void crypto_exit(void *mem) | ||
237 | { | ||
238 | } | ||
239 | |||
240 | static __inline__ int crypto_write(struct pbe *p, void *mem) | ||
241 | { | ||
242 | return write_page(p->address, &(p->swap_address)); | ||
243 | } | ||
244 | |||
245 | static __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 | |||
251 | static int mark_swapfiles(swp_entry_t prev) | 114 | static 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"); |