[PATCH] zero disk pages used by swsusp on resume

From: Andreas Steinmetz
Date: Sun Apr 10 2005 - 08:15:37 EST


It may not be desireable to leave swsusp saved pages on disk after
resume as they may contain sensitive data that was never intended to be
stored on disk in an way (e.g. in-kernel dm-crypt keys, mlocked pages).

The attached simple patch against 2.6.11.2 should fix this by zeroing
the swap pages after reading them.

The patch is by no means perfect. Especially it isn't invoked on error
conditions. However it seems to work during regular operation.

Note that it is not possible to do this from userspace in a performant
way, one has to zero the whole swap partition used for swsusp to achive
a similar effect which quite often means clearing 2GB instead of about a
few 100MB. The difference in speed and power consumption is important
especially for laptops when resuming on battery. The userspace method
also allows for a window in which at least some of the data may still be
read.
--
Andreas Steinmetz SPAMmers use robotrap@xxxxxxxx
--- linux-2.6.11.2/kernel/power/swsusp.c.ast 2005-04-10 14:08:55.000000000 +0200
+++ linux-2.6.11.2/kernel/power/swsusp.c 2005-04-10 14:24:10.000000000 +0200
@@ -112,6 +112,10 @@

static struct swsusp_info swsusp_info;

+static struct swsusp_clear {
+ char zero[PAGE_SIZE];
+} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_clear __initdata;
+
/*
* XXX: We try to keep some more pages free so that I/O operations succeed
* without paging. Might this be more?
@@ -1169,6 +1173,29 @@

}

+static int __init data_clear(void)
+{
+ struct pbe * p;
+ int error = 0;
+ int i;
+ int mod = nr_copy_pages / 100;
+
+ if (!mod)
+ mod = 1;
+
+ memset(&swsusp_clear, 0, sizeof(swsusp_clear));
+
+ printk( "Clearing disk data (%d pages): ", nr_copy_pages );
+ for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
+ if (!(i%mod))
+ printk( "\b\b\b\b%3d%%", i / mod );
+ error = bio_write_page(swp_offset(p->swap_address),
+ (void *)&swsusp_clear);
+ }
+ printk(" %d done.\n",i);
+ return error;
+}
+
extern dev_t __init name_to_dev_t(const char *line);

static int __init read_pagedir(void)
@@ -1208,6 +1235,8 @@
return error;
if ((error = data_read()))
free_pages((unsigned long)pagedir_nosave, pagedir_order);
+ else
+ data_clear();
return error;
}