Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 6999
b: refs/heads/master
c: c2ff18f
h: refs/heads/master
i:
  6997: 6f677ab
  6995: a768b5f
  6991: 4b8bab7
v: v3
  • Loading branch information
Andreas Steinmetz authored and Linus Torvalds committed Sep 5, 2005
1 parent 99809f9 commit f37101b
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 583a4e88db1eadc52116e1f97b4519de655b2b80
refs/heads/master: c2ff18f4070f6303a81fd7d9d967d7c9e01b588f
12 changes: 12 additions & 0 deletions trunk/kernel/power/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ config PM_STD_PARTITION
suspended image to. It will simply pick the first available swap
device.

config SWSUSP_ENCRYPT
bool "Encrypt suspend image"
depends on SOFTWARE_SUSPEND && CRYPTO=y && (CRYPTO_AES=y || CRYPTO_AES_586=y || CRYPTO_AES_X86_64=y)
default ""
---help---
To prevent data gathering from swap after resume you can encrypt
the suspend image with a temporary key that is deleted on
resume.

Note that the temporary key is stored unencrypted on disk while the
system is suspended.

config SUSPEND_SMP
bool
depends on HOTPLUG_CPU && X86 && PM
Expand Down
164 changes: 159 additions & 5 deletions trunk/kernel/power/swsusp.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
* Alex Badea <vampire@go.ro>:
* Fixed runaway init
*
* Andreas Steinmetz <ast@domdv.de>:
* Added encrypted suspend option
*
* More state savers are welcome. Especially for the scsi layer...
*
* For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
Expand Down Expand Up @@ -71,8 +74,16 @@
#include <asm/tlbflush.h>
#include <asm/io.h>

#include <linux/random.h>
#include <linux/crypto.h>
#include <asm/scatterlist.h>

#include "power.h"

#define CIPHER "aes"
#define MAXKEY 32
#define MAXIV 32

/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;

Expand Down Expand Up @@ -103,7 +114,8 @@ static suspend_pagedir_t *pagedir_save;
#define SWSUSP_SIG "S1SUSPEND"

static struct swsusp_header {
char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
u8 key_iv[MAXKEY+MAXIV];
swp_entry_t swsusp_info;
char orig_sig[10];
char sig[10];
Expand All @@ -129,6 +141,131 @@ static struct swsusp_info swsusp_info;
static unsigned short swapfile_used[MAX_SWAPFILES];
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)
{
int error;
Expand All @@ -140,6 +277,7 @@ static int mark_swapfiles(swp_entry_t prev)
!memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
swsusp_header.swsusp_info = prev;
error = rw_swap_page_sync(WRITE,
swp_entry(root_swap, 0),
Expand Down Expand Up @@ -286,6 +424,10 @@ static int data_write(void)
int error = 0, i = 0;
unsigned int mod = nr_copy_pages / 100;
struct pbe *p;
void *tfm;

if ((error = crypto_init(1, &tfm)))
return error;

if (!mod)
mod = 1;
Expand All @@ -294,11 +436,14 @@ static int data_write(void)
for_each_pbe (p, pagedir_nosave) {
if (!(i%mod))
printk( "\b\b\b\b%3d%%", i / mod );
if ((error = write_page(p->address, &(p->swap_address))))
if ((error = crypto_write(p, tfm))) {
crypto_exit(tfm);
return error;
}
i++;
}
printk("\b\b\b\bdone\n");
crypto_exit(tfm);
return error;
}

Expand Down Expand Up @@ -400,6 +545,7 @@ static int write_suspend_image(void)
if ((error = close_swap()))
goto FreePagedir;
Done:
memset(key_iv, 0, MAXKEY+MAXIV);
return error;
FreePagedir:
free_pagedir_entries();
Expand Down Expand Up @@ -1212,6 +1358,8 @@ static int check_sig(void)
return error;
if (!memcmp(SWSUSP_SIG, swsusp_header.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.
Expand Down Expand Up @@ -1239,6 +1387,10 @@ static int data_read(struct pbe *pblist)
int error = 0;
int i = 0;
int mod = swsusp_info.image_pages / 100;
void *tfm;

if ((error = crypto_init(0, &tfm)))
return error;

if (!mod)
mod = 1;
Expand All @@ -1250,14 +1402,15 @@ static int data_read(struct pbe *pblist)
if (!(i % mod))
printk("\b\b\b\b%3d%%", i / mod);

error = bio_read_page(swp_offset(p->swap_address),
(void *)p->address);
if (error)
if ((error = crypto_read(p, tfm))) {
crypto_exit(tfm);
return error;
}

i++;
}
printk("\b\b\b\bdone\n");
crypto_exit(tfm);
return error;
}

Expand Down Expand Up @@ -1385,6 +1538,7 @@ int swsusp_read(void)

error = read_suspend_image();
blkdev_put(resume_bdev);
memset(key_iv, 0, MAXKEY+MAXIV);

if (!error)
pr_debug("swsusp: Reading resume file was successful\n");
Expand Down

0 comments on commit f37101b

Please sign in to comment.