#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <asm/atomic.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm/page.h>
#include "dm.h"
-#define PFX "crypt: "
+#define DM_MSG_PREFIX "crypt"
/*
* per bio private data
static kmem_cache_t *_crypt_io_pool;
-/*
- * Mempool alloc and free functions for the page
- */
-static void *mempool_alloc_page(unsigned int __nocast gfp_mask, void *data)
-{
- return alloc_page(gfp_mask);
-}
-
-static void mempool_free_page(void *page, void *data)
-{
- __free_page(page);
-}
-
-
/*
* Different IV generation algorithms:
*
u8 *salt;
if (opts == NULL) {
- ti->error = PFX "Digest algorithm missing for ESSIV mode";
+ ti->error = "Digest algorithm missing for ESSIV mode";
return -EINVAL;
}
/* Hash the cipher key with the given hash algorithm */
- hash_tfm = crypto_alloc_tfm(opts, 0);
+ hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
if (hash_tfm == NULL) {
- ti->error = PFX "Error initializing ESSIV hash";
+ ti->error = "Error initializing ESSIV hash";
return -EINVAL;
}
if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
- ti->error = PFX "Expected digest algorithm for ESSIV hash";
+ ti->error = "Expected digest algorithm for ESSIV hash";
crypto_free_tfm(hash_tfm);
return -EINVAL;
}
saltsize = crypto_tfm_alg_digestsize(hash_tfm);
salt = kmalloc(saltsize, GFP_KERNEL);
if (salt == NULL) {
- ti->error = PFX "Error kmallocing salt storage in ESSIV";
+ ti->error = "Error kmallocing salt storage in ESSIV";
crypto_free_tfm(hash_tfm);
return -ENOMEM;
}
- sg.page = virt_to_page(cc->key);
- sg.offset = offset_in_page(cc->key);
- sg.length = cc->key_size;
+ sg_set_buf(&sg, cc->key, cc->key_size);
crypto_digest_digest(hash_tfm, &sg, 1, salt);
crypto_free_tfm(hash_tfm);
/* Setup the essiv_tfm with the given salt */
essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
- CRYPTO_TFM_MODE_ECB);
+ CRYPTO_TFM_MODE_ECB |
+ CRYPTO_TFM_REQ_MAY_SLEEP);
if (essiv_tfm == NULL) {
- ti->error = PFX "Error allocating crypto tfm for ESSIV";
+ ti->error = "Error allocating crypto tfm for ESSIV";
kfree(salt);
return -EINVAL;
}
if (crypto_tfm_alg_blocksize(essiv_tfm)
!= crypto_tfm_alg_ivsize(cc->tfm)) {
- ti->error = PFX "Block size of ESSIV cipher does "
+ ti->error = "Block size of ESSIV cipher does "
"not match IV size of block cipher";
crypto_free_tfm(essiv_tfm);
kfree(salt);
return -EINVAL;
}
if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) {
- ti->error = PFX "Failed to set key for ESSIV cipher";
+ ti->error = "Failed to set key for ESSIV cipher";
crypto_free_tfm(essiv_tfm);
kfree(salt);
return -EINVAL;
static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
{
- struct scatterlist sg = { NULL, };
+ struct scatterlist sg;
memset(iv, 0, cc->iv_size);
*(u64 *)iv = cpu_to_le64(sector);
- sg.page = virt_to_page(iv);
- sg.offset = offset_in_page(iv);
- sg.length = cc->iv_size;
+ sg_set_buf(&sg, iv, cc->iv_size);
crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private,
&sg, &sg, cc->iv_size);
};
-static inline int
+static int
crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
struct scatterlist *in, unsigned int length,
int write, sector_t sector)
{
struct bio *bio;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+ gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
unsigned int i;
/*
char *ivopts;
unsigned int crypto_flags;
unsigned int key_size;
+ unsigned long long tmpll;
if (argc != 5) {
- ti->error = PFX "Not enough arguments";
+ ti->error = "Not enough arguments";
return -EINVAL;
}
ivmode = strsep(&ivopts, ":");
if (tmp)
- DMWARN(PFX "Unexpected additional cipher options");
+ DMWARN("Unexpected additional cipher options");
key_size = strlen(argv[1]) >> 1;
cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (cc == NULL) {
ti->error =
- PFX "Cannot allocate transparent encryption context";
+ "Cannot allocate transparent encryption context";
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)) {
- ti->error = PFX "Error decoding key";
+ ti->error = "Error decoding key";
goto bad1;
}
else if (strcmp(chainmode, "ecb") == 0)
crypto_flags = CRYPTO_TFM_MODE_ECB;
else {
- ti->error = PFX "Unknown chaining mode";
+ ti->error = "Unknown chaining mode";
goto bad1;
}
if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) {
- ti->error = PFX "This chaining mode requires an IV mechanism";
+ ti->error = "This chaining mode requires an IV mechanism";
goto bad1;
}
- tfm = crypto_alloc_tfm(cipher, crypto_flags);
+ tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
if (!tfm) {
- ti->error = PFX "Error allocating crypto tfm";
+ ti->error = "Error allocating crypto tfm";
goto bad1;
}
if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) {
- ti->error = PFX "Expected cipher algorithm";
+ ti->error = "Expected cipher algorithm";
goto bad2;
}
else if (strcmp(ivmode, "essiv") == 0)
cc->iv_gen_ops = &crypt_iv_essiv_ops;
else {
- ti->error = PFX "Invalid IV mode";
+ ti->error = "Invalid IV mode";
goto bad2;
}
else {
cc->iv_size = 0;
if (cc->iv_gen_ops) {
- DMWARN(PFX "Selected cipher does not support IVs");
+ DMWARN("Selected cipher does not support IVs");
if (cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
cc->iv_gen_ops = NULL;
}
}
- cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
- mempool_free_slab, _crypt_io_pool);
+ cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
if (!cc->io_pool) {
- ti->error = PFX "Cannot allocate crypt io mempool";
+ ti->error = "Cannot allocate crypt io mempool";
goto bad3;
}
- cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
- mempool_free_page, NULL);
+ cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!cc->page_pool) {
- ti->error = PFX "Cannot allocate page mempool";
+ ti->error = "Cannot allocate page mempool";
goto bad4;
}
if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
- ti->error = PFX "Error setting key";
+ ti->error = "Error setting key";
goto bad5;
}
- if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
- ti->error = PFX "Invalid iv_offset sector";
+ if (sscanf(argv[2], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid iv_offset sector";
goto bad5;
}
+ cc->iv_offset = tmpll;
- if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
- ti->error = PFX "Invalid device sector";
+ if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid device sector";
goto bad5;
}
+ cc->start = tmpll;
if (dm_get_device(ti, argv[3], cc->start, ti->len,
dm_table_get_mode(ti->table), &cc->dev)) {
- ti->error = PFX "Device lookup failed";
+ ti->error = "Device lookup failed";
goto bad5;
}
*(ivopts - 1) = ':';
cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
if (!cc->iv_mode) {
- ti->error = PFX "Error kmallocing iv_mode string";
+ ti->error = "Error kmallocing iv_mode string";
goto bad5;
}
strcpy(cc->iv_mode, ivmode);
bad2:
crypto_free_tfm(tfm);
bad1:
+ /* Must zero key material before freeing */
+ memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
kfree(cc);
return -EINVAL;
}
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);
- if (cc->iv_mode)
- kfree(cc->iv_mode);
+ kfree(cc->iv_mode);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
crypto_free_tfm(cc->tfm);
dm_put_device(ti, cc->dev);
+
+ /* Must zero key material before freeing */
+ memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
kfree(cc);
}
if (bio->bi_size)
return 1;
+ if (!bio_flagged(bio, BIO_UPTODATE) && !error)
+ error = -EIO;
+
bio_put(bio);
/*
* successful reads are decrypted by the worker thread
*/
- if ((bio_data_dir(bio) == READ)
- && bio_flagged(bio, BIO_UPTODATE)) {
+ if (bio_data_dir(io->bio) == READ && !error) {
kcryptd_queue_io(io);
return 0;
}
result[sz++] = '-';
}
- DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
- cc->iv_offset, cc->dev->name, cc->start);
+ DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
+ cc->dev->name, (unsigned long long)cc->start);
break;
}
return 0;
_kcryptd_workqueue = create_workqueue("kcryptd");
if (!_kcryptd_workqueue) {
r = -ENOMEM;
- DMERR(PFX "couldn't create kcryptd");
+ DMERR("couldn't create kcryptd");
goto bad1;
}
r = dm_register_target(&crypt_target);
if (r < 0) {
- DMERR(PFX "register failed %d", r);
+ DMERR("register failed %d", r);
goto bad2;
}
int r = dm_unregister_target(&crypt_target);
if (r < 0)
- DMERR(PFX "unregister failed %d", r);
+ DMERR("unregister failed %d", r);
destroy_workqueue(_kcryptd_workqueue);
kmem_cache_destroy(_crypt_io_pool);