|
@@ -1,6 +1,7 @@
|
|
/*
|
|
/*
|
|
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
|
|
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
|
|
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
|
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
|
|
|
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
|
*
|
|
*
|
|
* This file is released under the GPL.
|
|
* This file is released under the GPL.
|
|
*/
|
|
*/
|
|
@@ -22,6 +23,7 @@
|
|
#include "dm.h"
|
|
#include "dm.h"
|
|
|
|
|
|
#define DM_MSG_PREFIX "crypt"
|
|
#define DM_MSG_PREFIX "crypt"
|
|
|
|
+#define MESG_STR(x) x, sizeof(x)
|
|
|
|
|
|
/*
|
|
/*
|
|
* per bio private data
|
|
* per bio private data
|
|
@@ -63,6 +65,7 @@ struct crypt_iv_operations {
|
|
* Crypt: maps a linear range of a block device
|
|
* Crypt: maps a linear range of a block device
|
|
* and encrypts / decrypts at the same time.
|
|
* and encrypts / decrypts at the same time.
|
|
*/
|
|
*/
|
|
|
|
+enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
|
|
struct crypt_config {
|
|
struct crypt_config {
|
|
struct dm_dev *dev;
|
|
struct dm_dev *dev;
|
|
sector_t start;
|
|
sector_t start;
|
|
@@ -86,6 +89,7 @@ struct crypt_config {
|
|
char cipher[CRYPTO_MAX_ALG_NAME];
|
|
char cipher[CRYPTO_MAX_ALG_NAME];
|
|
char chainmode[CRYPTO_MAX_ALG_NAME];
|
|
char chainmode[CRYPTO_MAX_ALG_NAME];
|
|
struct crypto_blkcipher *tfm;
|
|
struct crypto_blkcipher *tfm;
|
|
|
|
+ unsigned long flags;
|
|
unsigned int key_size;
|
|
unsigned int key_size;
|
|
u8 key[0];
|
|
u8 key[0];
|
|
};
|
|
};
|
|
@@ -507,6 +511,31 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int crypt_set_key(struct crypt_config *cc, char *key)
|
|
|
|
+{
|
|
|
|
+ unsigned key_size = strlen(key) >> 1;
|
|
|
|
+
|
|
|
|
+ if (cc->key_size && cc->key_size != key_size)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ cc->key_size = key_size; /* initial settings */
|
|
|
|
+
|
|
|
|
+ if ((!key_size && strcmp(key, "-")) ||
|
|
|
|
+ (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int crypt_wipe_key(struct crypt_config *cc)
|
|
|
|
+{
|
|
|
|
+ clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
|
|
|
|
+ memset(&cc->key, 0, cc->key_size * sizeof(u8));
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Construct an encryption mapping:
|
|
* Construct an encryption mapping:
|
|
* <cipher> <key> <iv_offset> <dev_path> <start>
|
|
* <cipher> <key> <iv_offset> <dev_path> <start>
|
|
@@ -539,16 +568,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|
|
|
|
|
key_size = strlen(argv[1]) >> 1;
|
|
key_size = strlen(argv[1]) >> 1;
|
|
|
|
|
|
- cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
|
|
|
|
|
|
+ cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
|
|
if (cc == NULL) {
|
|
if (cc == NULL) {
|
|
ti->error =
|
|
ti->error =
|
|
"Cannot allocate transparent encryption context";
|
|
"Cannot allocate transparent encryption context";
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- cc->key_size = key_size;
|
|
|
|
- if ((!key_size && strcmp(argv[1], "-") != 0) ||
|
|
|
|
- (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
|
|
|
|
|
|
+ if (crypt_set_key(cc, argv[1])) {
|
|
ti->error = "Error decoding key";
|
|
ti->error = "Error decoding key";
|
|
goto bad1;
|
|
goto bad1;
|
|
}
|
|
}
|
|
@@ -780,13 +807,14 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
|
|
union map_info *map_context)
|
|
union map_info *map_context)
|
|
{
|
|
{
|
|
struct crypt_config *cc = (struct crypt_config *) ti->private;
|
|
struct crypt_config *cc = (struct crypt_config *) ti->private;
|
|
- struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
|
|
|
|
|
|
+ struct crypt_io *io;
|
|
struct convert_context ctx;
|
|
struct convert_context ctx;
|
|
struct bio *clone;
|
|
struct bio *clone;
|
|
unsigned int remaining = bio->bi_size;
|
|
unsigned int remaining = bio->bi_size;
|
|
sector_t sector = bio->bi_sector - ti->begin;
|
|
sector_t sector = bio->bi_sector - ti->begin;
|
|
unsigned int bvec_idx = 0;
|
|
unsigned int bvec_idx = 0;
|
|
|
|
|
|
|
|
+ io = mempool_alloc(cc->io_pool, GFP_NOIO);
|
|
io->target = ti;
|
|
io->target = ti;
|
|
io->bio = bio;
|
|
io->bio = bio;
|
|
io->first_clone = NULL;
|
|
io->first_clone = NULL;
|
|
@@ -883,14 +911,71 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void crypt_postsuspend(struct dm_target *ti)
|
|
|
|
+{
|
|
|
|
+ struct crypt_config *cc = ti->private;
|
|
|
|
+
|
|
|
|
+ set_bit(DM_CRYPT_SUSPENDED, &cc->flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int crypt_preresume(struct dm_target *ti)
|
|
|
|
+{
|
|
|
|
+ struct crypt_config *cc = ti->private;
|
|
|
|
+
|
|
|
|
+ if (!test_bit(DM_CRYPT_KEY_VALID, &cc->flags)) {
|
|
|
|
+ DMERR("aborting resume - crypt key is not set.");
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void crypt_resume(struct dm_target *ti)
|
|
|
|
+{
|
|
|
|
+ struct crypt_config *cc = ti->private;
|
|
|
|
+
|
|
|
|
+ clear_bit(DM_CRYPT_SUSPENDED, &cc->flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Message interface
|
|
|
|
+ * key set <key>
|
|
|
|
+ * key wipe
|
|
|
|
+ */
|
|
|
|
+static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
|
+{
|
|
|
|
+ struct crypt_config *cc = ti->private;
|
|
|
|
+
|
|
|
|
+ if (argc < 2)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ if (!strnicmp(argv[0], MESG_STR("key"))) {
|
|
|
|
+ if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) {
|
|
|
|
+ DMWARN("not suspended during key manipulation.");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ if (argc == 3 && !strnicmp(argv[1], MESG_STR("set")))
|
|
|
|
+ return crypt_set_key(cc, argv[2]);
|
|
|
|
+ if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe")))
|
|
|
|
+ return crypt_wipe_key(cc);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+error:
|
|
|
|
+ DMWARN("unrecognised message received.");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+}
|
|
|
|
+
|
|
static struct target_type crypt_target = {
|
|
static struct target_type crypt_target = {
|
|
.name = "crypt",
|
|
.name = "crypt",
|
|
- .version= {1, 1, 0},
|
|
|
|
|
|
+ .version= {1, 2, 0},
|
|
.module = THIS_MODULE,
|
|
.module = THIS_MODULE,
|
|
.ctr = crypt_ctr,
|
|
.ctr = crypt_ctr,
|
|
.dtr = crypt_dtr,
|
|
.dtr = crypt_dtr,
|
|
.map = crypt_map,
|
|
.map = crypt_map,
|
|
.status = crypt_status,
|
|
.status = crypt_status,
|
|
|
|
+ .postsuspend = crypt_postsuspend,
|
|
|
|
+ .preresume = crypt_preresume,
|
|
|
|
+ .resume = crypt_resume,
|
|
|
|
+ .message = crypt_message,
|
|
};
|
|
};
|
|
|
|
|
|
static int __init dm_crypt_init(void)
|
|
static int __init dm_crypt_init(void)
|