If device is not rotational, do not use Gutmann wipe method.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@615 36d66b0a-2a48-0410-832c-cd162a569da5
This commit is contained in:
Milan Broz
2011-10-08 16:17:08 +00:00
parent 61bec51be0
commit d2fbc963ca
8 changed files with 221 additions and 103 deletions

View File

@@ -1,5 +1,6 @@
2011-10-05 Milan Broz <mbroz@redhat.com>
* Support Nettle 2.4 crypto backend (for ripemd160).
* If device is not rotational, do not use Gutmann wipe method.
2011-09-22 Milan Broz <mbroz@redhat.com>
* Support key-slot option for luksOpen (use only explicit keyslot).

View File

@@ -53,6 +53,7 @@ libcryptsetup_la_SOURCES = \
utils_loop.c \
utils_loop.h \
utils_devpath.c \
utils_wipe.c \
libdevmapper.c \
utils_dm.h \
volumekey.c \

View File

@@ -51,6 +51,7 @@ const char *get_error(void);
char *crypt_lookup_dev(const char *dev_id);
int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_t size);
int crypt_sysfs_get_rotational(int major, int minor, int *rotational);
int sector_size_for_device(const char *device);
int device_read_ahead(const char *dev, uint32_t *read_ahead);
@@ -104,4 +105,23 @@ int PLAIN_activate(struct crypt_device *cd,
uint64_t size,
uint32_t flags);
/**
* Different methods used to erase sensitive data concerning
* either encrypted payload area or master key inside keyslot
* area
*/
typedef enum {
CRYPT_WIPE_ZERO, /**< overwrite area using zero blocks */
CRYPT_WIPE_DISK, /**< erase disk (using Gutmann method if it is rotational disk)*/
CRYPT_WIPE_SSD, /**< erase solid state disk (random write) */
CRYPT_WIPE_RANDOM /**< overwrite area using some up to now unspecified
* random algorithm */
} crypt_wipe_type;
int crypt_wipe(const char *device,
uint64_t offset,
uint64_t sectors,
crypt_wipe_type type,
int flags);
#endif /* INTERNAL_H */

View File

@@ -825,72 +825,6 @@ int LUKS_open_key_with_hdr(const char *device,
return -EPERM;
}
/*
* Wipe patterns according to Gutmann's Paper
*/
static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
{
unsigned int i;
unsigned char write_modes[][3] = {
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"},
{"\x49\x24\x92"}, {"\x24\x92\x49"}, {"\x00\x00\x00"},
{"\x11\x11\x11"}, {"\x22\x22\x22"}, {"\x33\x33\x33"},
{"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"},
{"\xaa\xaa\xaa"}, {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"},
{"\xdd\xdd\xdd"}, {"\xee\xee\xee"}, {"\xff\xff\xff"},
{"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
};
for(i = 0; i < buffer_size / 3; ++i) {
memcpy(buffer, write_modes[turn], 3);
buffer += 3;
}
}
static int wipe(const char *device, unsigned int from, unsigned int to)
{
int devfd, r = 0;
char *buffer;
unsigned int i, bufLen;
ssize_t written;
devfd = open(device, O_RDWR | O_DIRECT | O_SYNC);
if(devfd == -1)
return -EINVAL;
bufLen = (to - from) * SECTOR_SIZE;
buffer = malloc(bufLen);
if(!buffer) {
close(devfd);
return -ENOMEM;
}
for(i = 0; i < 39; ++i) {
if (i < 5) crypt_random_get(NULL, buffer, bufLen,
CRYPT_RND_NORMAL);
else if(i >= 5 && i < 32) wipeSpecial(buffer, bufLen, i - 5);
else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, bufLen,
CRYPT_RND_NORMAL);
else if(i >= 38 && i < 39) memset(buffer, 0xFF, bufLen);
written = write_lseek_blockwise(devfd, buffer, bufLen,
from * SECTOR_SIZE);
if (written < 0 || written != bufLen) {
r = -EIO;
break;
}
}
free(buffer);
close(devfd);
return r;
}
int LUKS_del_key(const char *device,
unsigned int keyIndex,
struct luks_phdr *hdr,
@@ -915,7 +849,9 @@ int LUKS_del_key(const char *device,
stripesLen = hdr->keyBytes * hdr->keyblock[keyIndex].stripes;
endOffset = startOffset + div_round_up(stripesLen, SECTOR_SIZE);
r = wipe(device, startOffset, endOffset);
r = crypt_wipe(device, startOffset * SECTOR_SIZE,
(endOffset - startOffset) * SECTOR_SIZE,
CRYPT_WIPE_DISK, 0);
if (r) {
log_err(ctx, _("Cannot wipe device %s.\n"), device);
return r;

View File

@@ -788,7 +788,7 @@ static int _crypt_format_luks1(struct crypt_device *cd,
return r;
/* Wipe first 8 sectors - fs magic numbers etc. */
r = wipe_device_header(mdata_device(cd), 8);
r = crypt_wipe(mdata_device(cd), 0, 8 * SECTOR_SIZE, CRYPT_WIPE_ZERO, 1);
if(r < 0) {
if (r == -EBUSY)
log_err(cd, _("Cannot format device %s which is still in use.\n"),

View File

@@ -475,41 +475,6 @@ int device_check_and_adjust(struct crypt_device *cd,
return 0;
}
int wipe_device_header(const char *device, int sectors)
{
struct stat st;
char *buffer;
int size = sectors * SECTOR_SIZE;
int r = -1;
int devfd;
int flags = O_RDWR | O_DIRECT | O_SYNC;
if (stat(device, &st) < 0)
return -EINVAL;
/* never wipe header on mounted device */
if (S_ISBLK(st.st_mode))
flags |= O_EXCL;
devfd = open(device, flags);
if(devfd == -1)
return errno == EBUSY ? -EBUSY : -EINVAL;
buffer = malloc(size);
if (!buffer) {
close(devfd);
return -ENOMEM;
}
memset(buffer, 0, size);
r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
free(buffer);
close(devfd);
return r;
}
/* MEMLOCK */
#define DEFAULT_PROCESS_PRIORITY -18

View File

@@ -242,3 +242,26 @@ int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_
return r;
}
int crypt_sysfs_get_rotational(int major, int minor, int *rotational)
{
char path[PATH_MAX], tmp[64] = {0};
int fd, r;
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/queue/rotational",
major, minor) < 0)
return 0;
if ((fd = open(path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
if (r <= 0)
return 0;
if (sscanf(tmp, "%d", rotational) != 1)
return 0;
return 1;
}

172
lib/utils_wipe.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* utils_wipe - wipe a device
*
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2011, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "libcryptsetup.h"
#include "internal.h"
#define MAXIMUM_WIPE_BYTES 1024 * 1024 * 32 /* 32 MiB */
static ssize_t _crypt_wipe_zero(int fd, char *buffer, uint64_t offset, uint64_t size)
{
memset(buffer, 0, size);
return write_lseek_blockwise(fd, buffer, size, offset);
}
/*
* Wipe using Peter Gutmann method described in
* http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html
*/
static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
{
unsigned int i;
unsigned char write_modes[][3] = {
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"},
{"\x49\x24\x92"}, {"\x24\x92\x49"}, {"\x00\x00\x00"},
{"\x11\x11\x11"}, {"\x22\x22\x22"}, {"\x33\x33\x33"},
{"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"},
{"\xaa\xaa\xaa"}, {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"},
{"\xdd\xdd\xdd"}, {"\xee\xee\xee"}, {"\xff\xff\xff"},
{"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
};
for(i = 0; i < buffer_size / 3; ++i) {
memcpy(buffer, write_modes[turn], 3);
buffer += 3;
}
}
static ssize_t _crypt_wipe_disk(int fd, char *buffer, uint64_t offset, uint64_t size)
{
unsigned int i;
ssize_t written;
for(i = 0; i < 39; ++i) {
if (i < 5) crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
else if(i >= 5 && i < 32) wipeSpecial(buffer, size, i - 5);
else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
else if(i >= 38 && i < 39) memset(buffer, 0xFF, size);
written = write_lseek_blockwise(fd, buffer, size, offset);
if (written < 0 || written != size)
return written;
}
return written;
}
static ssize_t _crypt_wipe_random(int fd, char *buffer, uint64_t offset, uint64_t size)
{
crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
return write_lseek_blockwise(fd, buffer, size, offset);
}
static ssize_t _crypt_wipe_ssd(int fd, char *buffer, uint64_t offset, uint64_t size)
{
// FIXME: for now just rewrite it by random
return _crypt_wipe_random(fd, buffer, offset, size);
}
int crypt_wipe(const char *device,
uint64_t offset,
uint64_t size,
crypt_wipe_type type,
int exclusive)
{
struct stat st;
char *buffer;
int devfd, flags, rotational;
ssize_t written;
if (!size || size % SECTOR_SIZE || (size > MAXIMUM_WIPE_BYTES)) {
log_dbg("Unsuported wipe size for device %s: %ld.",
device, (unsigned long)size);
return -EINVAL;
}
if (stat(device, &st) < 0) {
log_dbg("Device %s not found.", device);
return -EINVAL;
}
if (type == CRYPT_WIPE_DISK) {
if (!crypt_sysfs_get_rotational(major(st.st_rdev),
minor(st.st_rdev),
&rotational))
rotational = 1;
log_dbg("Rotational flag is %d.", rotational);
if (!rotational)
type = CRYPT_WIPE_SSD;
}
buffer = malloc(size);
if (!buffer)
return -ENOMEM;
flags = O_WRONLY | O_DIRECT | O_SYNC;
/* use O_EXCL only for block devices */
if (exclusive && S_ISBLK(st.st_mode))
flags |= O_EXCL;
devfd = open(device, flags);
if (devfd == -1) {
free(buffer);
return errno == EBUSY ? -EBUSY : -EINVAL;
}
// FIXME: use fixed block size and loop here
switch (type) {
case CRYPT_WIPE_ZERO:
written = _crypt_wipe_zero(devfd, buffer, offset, size);
break;
case CRYPT_WIPE_DISK:
written = _crypt_wipe_disk(devfd, buffer, offset, size);
case CRYPT_WIPE_SSD:
written = _crypt_wipe_ssd(devfd, buffer, offset, size);
break;
case CRYPT_WIPE_RANDOM:
written = _crypt_wipe_random(devfd, buffer, offset, size);
default:
log_dbg("Unsuported wipe type requested: (%d)", type);
written = -1;
}
close(devfd);
free(buffer);
if (written != size || written < 0)
return -EIO;
return 0;
}