|
@@ -30,9 +30,6 @@
|
|
* Alex Badea <vampire@go.ro>:
|
|
* Alex Badea <vampire@go.ro>:
|
|
* Fixed runaway init
|
|
* Fixed runaway init
|
|
*
|
|
*
|
|
- * Andreas Steinmetz <ast@domdv.de>:
|
|
|
|
- * Added encrypted suspend option
|
|
|
|
- *
|
|
|
|
* More state savers are welcome. Especially for the scsi layer...
|
|
* More state savers are welcome. Especially for the scsi layer...
|
|
*
|
|
*
|
|
* For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
|
|
* For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
|
|
@@ -67,10 +64,6 @@
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
|
|
|
|
-#include <linux/random.h>
|
|
|
|
-#include <linux/crypto.h>
|
|
|
|
-#include <asm/scatterlist.h>
|
|
|
|
-
|
|
|
|
#include "power.h"
|
|
#include "power.h"
|
|
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
#ifdef CONFIG_HIGHMEM
|
|
@@ -81,10 +74,6 @@ static int save_highmem(void) { return 0; }
|
|
static int restore_highmem(void) { return 0; }
|
|
static int restore_highmem(void) { return 0; }
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-#define CIPHER "aes"
|
|
|
|
-#define MAXKEY 32
|
|
|
|
-#define MAXIV 32
|
|
|
|
-
|
|
|
|
extern char resume_file[];
|
|
extern char resume_file[];
|
|
|
|
|
|
/* Local variables that should not be affected by save */
|
|
/* Local variables that should not be affected by save */
|
|
@@ -102,8 +91,7 @@ suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
|
|
#define SWSUSP_SIG "S1SUSPEND"
|
|
#define SWSUSP_SIG "S1SUSPEND"
|
|
|
|
|
|
static struct swsusp_header {
|
|
static struct swsusp_header {
|
|
- char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
|
|
|
|
- u8 key_iv[MAXKEY+MAXIV];
|
|
|
|
|
|
+ char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
|
|
swp_entry_t swsusp_info;
|
|
swp_entry_t swsusp_info;
|
|
char orig_sig[10];
|
|
char orig_sig[10];
|
|
char sig[10];
|
|
char sig[10];
|
|
@@ -123,131 +111,6 @@ static struct swsusp_info swsusp_info;
|
|
static unsigned short swapfile_used[MAX_SWAPFILES];
|
|
static unsigned short swapfile_used[MAX_SWAPFILES];
|
|
static unsigned short root_swap;
|
|
static unsigned short root_swap;
|
|
|
|
|
|
-static int write_page(unsigned long addr, swp_entry_t *loc);
|
|
|
|
-static int bio_read_page(pgoff_t page_off, void *page);
|
|
|
|
-
|
|
|
|
-static u8 key_iv[MAXKEY+MAXIV];
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_SWSUSP_ENCRYPT
|
|
|
|
-
|
|
|
|
-static int crypto_init(int mode, void **mem)
|
|
|
|
-{
|
|
|
|
- int error = 0;
|
|
|
|
- int len;
|
|
|
|
- char *modemsg;
|
|
|
|
- struct crypto_tfm *tfm;
|
|
|
|
-
|
|
|
|
- modemsg = mode ? "suspend not possible" : "resume not possible";
|
|
|
|
-
|
|
|
|
- tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
|
|
|
|
- if(!tfm) {
|
|
|
|
- printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg);
|
|
|
|
- error = -EINVAL;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) {
|
|
|
|
- printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg);
|
|
|
|
- error = -ENOKEY;
|
|
|
|
- goto fail;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (mode)
|
|
|
|
- get_random_bytes(key_iv, MAXKEY+MAXIV);
|
|
|
|
-
|
|
|
|
- len = crypto_tfm_alg_max_keysize(tfm);
|
|
|
|
- if (len > MAXKEY)
|
|
|
|
- len = MAXKEY;
|
|
|
|
-
|
|
|
|
- if (crypto_cipher_setkey(tfm, key_iv, len)) {
|
|
|
|
- printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg);
|
|
|
|
- error = -EKEYREJECTED;
|
|
|
|
- goto fail;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- len = crypto_tfm_alg_ivsize(tfm);
|
|
|
|
-
|
|
|
|
- if (MAXIV < len) {
|
|
|
|
- printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg);
|
|
|
|
- error = -EOVERFLOW;
|
|
|
|
- goto fail;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len);
|
|
|
|
-
|
|
|
|
- *mem=(void *)tfm;
|
|
|
|
-
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
-fail: crypto_free_tfm(tfm);
|
|
|
|
-out: return error;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ void crypto_exit(void *mem)
|
|
|
|
-{
|
|
|
|
- crypto_free_tfm((struct crypto_tfm *)mem);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ int crypto_write(struct pbe *p, void *mem)
|
|
|
|
-{
|
|
|
|
- int error = 0;
|
|
|
|
- struct scatterlist src, dst;
|
|
|
|
-
|
|
|
|
- src.page = virt_to_page(p->address);
|
|
|
|
- src.offset = 0;
|
|
|
|
- src.length = PAGE_SIZE;
|
|
|
|
- dst.page = virt_to_page((void *)&swsusp_header);
|
|
|
|
- dst.offset = 0;
|
|
|
|
- dst.length = PAGE_SIZE;
|
|
|
|
-
|
|
|
|
- error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src,
|
|
|
|
- PAGE_SIZE);
|
|
|
|
-
|
|
|
|
- if (!error)
|
|
|
|
- error = write_page((unsigned long)&swsusp_header,
|
|
|
|
- &(p->swap_address));
|
|
|
|
- return error;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ int crypto_read(struct pbe *p, void *mem)
|
|
|
|
-{
|
|
|
|
- int error = 0;
|
|
|
|
- struct scatterlist src, dst;
|
|
|
|
-
|
|
|
|
- error = bio_read_page(swp_offset(p->swap_address), (void *)p->address);
|
|
|
|
- if (!error) {
|
|
|
|
- src.offset = 0;
|
|
|
|
- src.length = PAGE_SIZE;
|
|
|
|
- dst.offset = 0;
|
|
|
|
- dst.length = PAGE_SIZE;
|
|
|
|
- src.page = dst.page = virt_to_page((void *)p->address);
|
|
|
|
-
|
|
|
|
- error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst,
|
|
|
|
- &src, PAGE_SIZE);
|
|
|
|
- }
|
|
|
|
- return error;
|
|
|
|
-}
|
|
|
|
-#else
|
|
|
|
-static __inline__ int crypto_init(int mode, void *mem)
|
|
|
|
-{
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ void crypto_exit(void *mem)
|
|
|
|
-{
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ int crypto_write(struct pbe *p, void *mem)
|
|
|
|
-{
|
|
|
|
- return write_page(p->address, &(p->swap_address));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static __inline__ int crypto_read(struct pbe *p, void *mem)
|
|
|
|
-{
|
|
|
|
- return bio_read_page(swp_offset(p->swap_address), (void *)p->address);
|
|
|
|
-}
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
static int mark_swapfiles(swp_entry_t prev)
|
|
static int mark_swapfiles(swp_entry_t prev)
|
|
{
|
|
{
|
|
int error;
|
|
int error;
|
|
@@ -259,7 +122,6 @@ static int mark_swapfiles(swp_entry_t prev)
|
|
!memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
|
|
!memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
|
|
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
|
|
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
|
|
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
|
|
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
|
|
- memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
|
|
|
|
swsusp_header.swsusp_info = prev;
|
|
swsusp_header.swsusp_info = prev;
|
|
error = rw_swap_page_sync(WRITE,
|
|
error = rw_swap_page_sync(WRITE,
|
|
swp_entry(root_swap, 0),
|
|
swp_entry(root_swap, 0),
|
|
@@ -405,10 +267,6 @@ static int data_write(void)
|
|
int error = 0, i = 0;
|
|
int error = 0, i = 0;
|
|
unsigned int mod = nr_copy_pages / 100;
|
|
unsigned int mod = nr_copy_pages / 100;
|
|
struct pbe *p;
|
|
struct pbe *p;
|
|
- void *tfm;
|
|
|
|
-
|
|
|
|
- if ((error = crypto_init(1, &tfm)))
|
|
|
|
- return error;
|
|
|
|
|
|
|
|
if (!mod)
|
|
if (!mod)
|
|
mod = 1;
|
|
mod = 1;
|
|
@@ -417,14 +275,11 @@ static int data_write(void)
|
|
for_each_pbe (p, pagedir_nosave) {
|
|
for_each_pbe (p, pagedir_nosave) {
|
|
if (!(i%mod))
|
|
if (!(i%mod))
|
|
printk( "\b\b\b\b%3d%%", i / mod );
|
|
printk( "\b\b\b\b%3d%%", i / mod );
|
|
- if ((error = crypto_write(p, tfm))) {
|
|
|
|
- crypto_exit(tfm);
|
|
|
|
|
|
+ if ((error = write_page(p->address, &p->swap_address)))
|
|
return error;
|
|
return error;
|
|
- }
|
|
|
|
i++;
|
|
i++;
|
|
}
|
|
}
|
|
printk("\b\b\b\bdone\n");
|
|
printk("\b\b\b\bdone\n");
|
|
- crypto_exit(tfm);
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -550,7 +405,6 @@ static int write_suspend_image(void)
|
|
if ((error = close_swap()))
|
|
if ((error = close_swap()))
|
|
goto FreePagedir;
|
|
goto FreePagedir;
|
|
Done:
|
|
Done:
|
|
- memset(key_iv, 0, MAXKEY+MAXIV);
|
|
|
|
return error;
|
|
return error;
|
|
FreePagedir:
|
|
FreePagedir:
|
|
free_pagedir_entries();
|
|
free_pagedir_entries();
|
|
@@ -812,8 +666,6 @@ static int check_sig(void)
|
|
return error;
|
|
return error;
|
|
if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
|
|
if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
|
|
memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
|
|
memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
|
|
- memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV);
|
|
|
|
- memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV);
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Reset swap signature now.
|
|
* Reset swap signature now.
|
|
@@ -840,10 +692,6 @@ static int data_read(struct pbe *pblist)
|
|
int error = 0;
|
|
int error = 0;
|
|
int i = 0;
|
|
int i = 0;
|
|
int mod = swsusp_info.image_pages / 100;
|
|
int mod = swsusp_info.image_pages / 100;
|
|
- void *tfm;
|
|
|
|
-
|
|
|
|
- if ((error = crypto_init(0, &tfm)))
|
|
|
|
- return error;
|
|
|
|
|
|
|
|
if (!mod)
|
|
if (!mod)
|
|
mod = 1;
|
|
mod = 1;
|
|
@@ -855,15 +703,13 @@ static int data_read(struct pbe *pblist)
|
|
if (!(i % mod))
|
|
if (!(i % mod))
|
|
printk("\b\b\b\b%3d%%", i / mod);
|
|
printk("\b\b\b\b%3d%%", i / mod);
|
|
|
|
|
|
- if ((error = crypto_read(p, tfm))) {
|
|
|
|
- crypto_exit(tfm);
|
|
|
|
|
|
+ if ((error = bio_read_page(swp_offset(p->swap_address),
|
|
|
|
+ (void *)p->address)))
|
|
return error;
|
|
return error;
|
|
- }
|
|
|
|
|
|
|
|
i++;
|
|
i++;
|
|
}
|
|
}
|
|
printk("\b\b\b\bdone\n");
|
|
printk("\b\b\b\bdone\n");
|
|
- crypto_exit(tfm);
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -986,7 +832,6 @@ int swsusp_read(void)
|
|
|
|
|
|
error = read_suspend_image();
|
|
error = read_suspend_image();
|
|
blkdev_put(resume_bdev);
|
|
blkdev_put(resume_bdev);
|
|
- memset(key_iv, 0, MAXKEY+MAXIV);
|
|
|
|
|
|
|
|
if (!error)
|
|
if (!error)
|
|
pr_debug("swsusp: Reading resume file was successful\n");
|
|
pr_debug("swsusp: Reading resume file was successful\n");
|