diff options
-rw-r--r-- | drivers/md/dm-crypt.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index bdbd34993a80..e1e8040f451a 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003 Christophe Saout <christophe@saout.de> | 2 | * Copyright (C) 2003 Christophe Saout <christophe@saout.de> |
3 | * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org> | 3 | * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org> |
4 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | ||
4 | * | 5 | * |
5 | * This file is released under the GPL. | 6 | * This file is released under the GPL. |
6 | */ | 7 | */ |
@@ -22,6 +23,7 @@ | |||
22 | #include "dm.h" | 23 | #include "dm.h" |
23 | 24 | ||
24 | #define DM_MSG_PREFIX "crypt" | 25 | #define DM_MSG_PREFIX "crypt" |
26 | #define MESG_STR(x) x, sizeof(x) | ||
25 | 27 | ||
26 | /* | 28 | /* |
27 | * per bio private data | 29 | * per bio private data |
@@ -63,6 +65,7 @@ struct crypt_iv_operations { | |||
63 | * Crypt: maps a linear range of a block device | 65 | * Crypt: maps a linear range of a block device |
64 | * and encrypts / decrypts at the same time. | 66 | * and encrypts / decrypts at the same time. |
65 | */ | 67 | */ |
68 | enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID }; | ||
66 | struct crypt_config { | 69 | struct crypt_config { |
67 | struct dm_dev *dev; | 70 | struct dm_dev *dev; |
68 | sector_t start; | 71 | sector_t start; |
@@ -86,6 +89,7 @@ struct crypt_config { | |||
86 | char cipher[CRYPTO_MAX_ALG_NAME]; | 89 | char cipher[CRYPTO_MAX_ALG_NAME]; |
87 | char chainmode[CRYPTO_MAX_ALG_NAME]; | 90 | char chainmode[CRYPTO_MAX_ALG_NAME]; |
88 | struct crypto_blkcipher *tfm; | 91 | struct crypto_blkcipher *tfm; |
92 | unsigned long flags; | ||
89 | unsigned int key_size; | 93 | unsigned int key_size; |
90 | u8 key[0]; | 94 | u8 key[0]; |
91 | }; | 95 | }; |
@@ -507,6 +511,31 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) | |||
507 | } | 511 | } |
508 | } | 512 | } |
509 | 513 | ||
514 | static int crypt_set_key(struct crypt_config *cc, char *key) | ||
515 | { | ||
516 | unsigned key_size = strlen(key) >> 1; | ||
517 | |||
518 | if (cc->key_size && cc->key_size != key_size) | ||
519 | return -EINVAL; | ||
520 | |||
521 | cc->key_size = key_size; /* initial settings */ | ||
522 | |||
523 | if ((!key_size && strcmp(key, "-")) || | ||
524 | (key_size && crypt_decode_key(cc->key, key, key_size) < 0)) | ||
525 | return -EINVAL; | ||
526 | |||
527 | set_bit(DM_CRYPT_KEY_VALID, &cc->flags); | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int crypt_wipe_key(struct crypt_config *cc) | ||
533 | { | ||
534 | clear_bit(DM_CRYPT_KEY_VALID, &cc->flags); | ||
535 | memset(&cc->key, 0, cc->key_size * sizeof(u8)); | ||
536 | return 0; | ||
537 | } | ||
538 | |||
510 | /* | 539 | /* |
511 | * Construct an encryption mapping: | 540 | * Construct an encryption mapping: |
512 | * <cipher> <key> <iv_offset> <dev_path> <start> | 541 | * <cipher> <key> <iv_offset> <dev_path> <start> |
@@ -539,16 +568,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
539 | 568 | ||
540 | key_size = strlen(argv[1]) >> 1; | 569 | key_size = strlen(argv[1]) >> 1; |
541 | 570 | ||
542 | cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | 571 | cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); |
543 | if (cc == NULL) { | 572 | if (cc == NULL) { |
544 | ti->error = | 573 | ti->error = |
545 | "Cannot allocate transparent encryption context"; | 574 | "Cannot allocate transparent encryption context"; |
546 | return -ENOMEM; | 575 | return -ENOMEM; |
547 | } | 576 | } |
548 | 577 | ||
549 | cc->key_size = key_size; | 578 | if (crypt_set_key(cc, argv[1])) { |
550 | if ((!key_size && strcmp(argv[1], "-") != 0) || | ||
551 | (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) { | ||
552 | ti->error = "Error decoding key"; | 579 | ti->error = "Error decoding key"; |
553 | goto bad1; | 580 | goto bad1; |
554 | } | 581 | } |
@@ -780,13 +807,14 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, | |||
780 | union map_info *map_context) | 807 | union map_info *map_context) |
781 | { | 808 | { |
782 | struct crypt_config *cc = (struct crypt_config *) ti->private; | 809 | struct crypt_config *cc = (struct crypt_config *) ti->private; |
783 | struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO); | 810 | struct crypt_io *io; |
784 | struct convert_context ctx; | 811 | struct convert_context ctx; |
785 | struct bio *clone; | 812 | struct bio *clone; |
786 | unsigned int remaining = bio->bi_size; | 813 | unsigned int remaining = bio->bi_size; |
787 | sector_t sector = bio->bi_sector - ti->begin; | 814 | sector_t sector = bio->bi_sector - ti->begin; |
788 | unsigned int bvec_idx = 0; | 815 | unsigned int bvec_idx = 0; |
789 | 816 | ||
817 | io = mempool_alloc(cc->io_pool, GFP_NOIO); | ||
790 | io->target = ti; | 818 | io->target = ti; |
791 | io->bio = bio; | 819 | io->bio = bio; |
792 | io->first_clone = NULL; | 820 | io->first_clone = NULL; |
@@ -883,14 +911,71 @@ static int crypt_status(struct dm_target *ti, status_type_t type, | |||
883 | return 0; | 911 | return 0; |
884 | } | 912 | } |
885 | 913 | ||
914 | static void crypt_postsuspend(struct dm_target *ti) | ||
915 | { | ||
916 | struct crypt_config *cc = ti->private; | ||
917 | |||
918 | set_bit(DM_CRYPT_SUSPENDED, &cc->flags); | ||
919 | } | ||
920 | |||
921 | static int crypt_preresume(struct dm_target *ti) | ||
922 | { | ||
923 | struct crypt_config *cc = ti->private; | ||
924 | |||
925 | if (!test_bit(DM_CRYPT_KEY_VALID, &cc->flags)) { | ||
926 | DMERR("aborting resume - crypt key is not set."); | ||
927 | return -EAGAIN; | ||
928 | } | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | static void crypt_resume(struct dm_target *ti) | ||
934 | { | ||
935 | struct crypt_config *cc = ti->private; | ||
936 | |||
937 | clear_bit(DM_CRYPT_SUSPENDED, &cc->flags); | ||
938 | } | ||
939 | |||
940 | /* Message interface | ||
941 | * key set <key> | ||
942 | * key wipe | ||
943 | */ | ||
944 | static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) | ||
945 | { | ||
946 | struct crypt_config *cc = ti->private; | ||
947 | |||
948 | if (argc < 2) | ||
949 | goto error; | ||
950 | |||
951 | if (!strnicmp(argv[0], MESG_STR("key"))) { | ||
952 | if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) { | ||
953 | DMWARN("not suspended during key manipulation."); | ||
954 | return -EINVAL; | ||
955 | } | ||
956 | if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) | ||
957 | return crypt_set_key(cc, argv[2]); | ||
958 | if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) | ||
959 | return crypt_wipe_key(cc); | ||
960 | } | ||
961 | |||
962 | error: | ||
963 | DMWARN("unrecognised message received."); | ||
964 | return -EINVAL; | ||
965 | } | ||
966 | |||
886 | static struct target_type crypt_target = { | 967 | static struct target_type crypt_target = { |
887 | .name = "crypt", | 968 | .name = "crypt", |
888 | .version= {1, 1, 0}, | 969 | .version= {1, 2, 0}, |
889 | .module = THIS_MODULE, | 970 | .module = THIS_MODULE, |
890 | .ctr = crypt_ctr, | 971 | .ctr = crypt_ctr, |
891 | .dtr = crypt_dtr, | 972 | .dtr = crypt_dtr, |
892 | .map = crypt_map, | 973 | .map = crypt_map, |
893 | .status = crypt_status, | 974 | .status = crypt_status, |
975 | .postsuspend = crypt_postsuspend, | ||
976 | .preresume = crypt_preresume, | ||
977 | .resume = crypt_resume, | ||
978 | .message = crypt_message, | ||
894 | }; | 979 | }; |
895 | 980 | ||
896 | static int __init dm_crypt_init(void) | 981 | static int __init dm_crypt_init(void) |