Skip to content
dm-crypt.c 50.4 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
/*
 * Copyright (C) 2003 Jana Saout <jana@saout.de>
Linus Torvalds's avatar
Linus Torvalds committed
 * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
 * Copyright (C) 2006-2015 Red Hat, Inc. All rights reserved.
 * Copyright (C) 2013 Milan Broz <gmazyland@gmail.com>
Linus Torvalds's avatar
Linus Torvalds committed
 *
 * This file is released under the GPL.
 */

#include <linux/completion.h>
#include <linux/err.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/mempool.h>
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/atomic.h>
#include <linux/scatterlist.h>
Mikulas Patocka's avatar
Mikulas Patocka committed
#include <linux/rbtree.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <asm/page.h>
#include <crypto/hash.h>
#include <crypto/md5.h>
#include <crypto/algapi.h>
Linus Torvalds's avatar
Linus Torvalds committed

#include <linux/device-mapper.h>
Linus Torvalds's avatar
Linus Torvalds committed

#define DM_MSG_PREFIX "crypt"
Linus Torvalds's avatar
Linus Torvalds committed

/*
 * context holding the current state of a multi-part conversion
 */
struct convert_context {
	struct completion restart;
Linus Torvalds's avatar
Linus Torvalds committed
	struct bio *bio_in;
	struct bio *bio_out;
	struct bvec_iter iter_in;
	struct bvec_iter iter_out;
	atomic_t cc_pending;
	struct ablkcipher_request *req;
Linus Torvalds's avatar
Linus Torvalds committed
};

/*
 * per bio private data
 */
struct dm_crypt_io {
	struct bio *base_bio;
	struct work_struct work;

	struct convert_context ctx;

	atomic_t io_pending;
	sector_t sector;
Mikulas Patocka's avatar
Mikulas Patocka committed
	struct rb_node rb_node;
} CRYPTO_MINALIGN_ATTR;
struct dm_crypt_request {
	struct convert_context *ctx;
	struct scatterlist sg_in;
	struct scatterlist sg_out;
	sector_t iv_sector;
Linus Torvalds's avatar
Linus Torvalds committed
struct crypt_config;

struct crypt_iv_operations {
	int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
Milan Broz's avatar
Milan Broz committed
		   const char *opts);
Linus Torvalds's avatar
Linus Torvalds committed
	void (*dtr)(struct crypt_config *cc);
	int (*init)(struct crypt_config *cc);
	int (*wipe)(struct crypt_config *cc);
	int (*generator)(struct crypt_config *cc, u8 *iv,
			 struct dm_crypt_request *dmreq);
	int (*post)(struct crypt_config *cc, u8 *iv,
		    struct dm_crypt_request *dmreq);
Linus Torvalds's avatar
Linus Torvalds committed
};

struct iv_essiv_private {
	struct crypto_hash *hash_tfm;
	u8 *salt;
};

struct iv_benbi_private {
	int shift;
};

#define LMK_SEED_SIZE 64 /* hash + 0 */
struct iv_lmk_private {
	struct crypto_shash *hash_tfm;
	u8 *seed;
};

#define TCW_WHITENING_SIZE 16
struct iv_tcw_private {
	struct crypto_shash *crc32_tfm;
	u8 *iv_seed;
	u8 *whitening;
};

Linus Torvalds's avatar
Linus Torvalds committed
/*
 * Crypt: maps a linear range of a block device
 * and encrypts / decrypts at the same time.
 */
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
	     DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
	     DM_CRYPT_EXIT_THREAD};
 * The fields in here must be read only after initialization.
Linus Torvalds's avatar
Linus Torvalds committed
struct crypt_config {
	struct dm_dev *dev;
	sector_t start;

	/*
	 * pool for per bio private data, crypto requests and
	 * encryption requeusts/buffer pages
Linus Torvalds's avatar
Linus Torvalds committed
	 */
	mempool_t *req_pool;
Linus Torvalds's avatar
Linus Torvalds committed
	mempool_t *page_pool;
	struct bio_set *bs;
	struct mutex bio_alloc_lock;
Linus Torvalds's avatar
Linus Torvalds committed

	struct workqueue_struct *io_queue;
	struct workqueue_struct *crypt_queue;
	struct task_struct *write_thread;
	wait_queue_head_t write_thread_wait;
Mikulas Patocka's avatar
Mikulas Patocka committed
	struct rb_root write_tree;
Milan Broz's avatar
Milan Broz committed
	char *cipher;
	char *cipher_string;
Linus Torvalds's avatar
Linus Torvalds committed
	struct crypt_iv_operations *iv_gen_ops;
		struct iv_essiv_private essiv;
		struct iv_benbi_private benbi;
		struct iv_lmk_private lmk;
		struct iv_tcw_private tcw;
	} iv_gen_private;
Linus Torvalds's avatar
Linus Torvalds committed
	sector_t iv_offset;
	unsigned int iv_size;

	/* ESSIV: struct crypto_cipher *essiv_tfm */
	void *iv_private;
	struct crypto_ablkcipher **tfms;
	unsigned tfms_count;
	/*
	 * Layout of each crypto request:
	 *
	 *   struct ablkcipher_request
	 *      context
	 *      padding
	 *   struct dm_crypt_request
	 *      padding
	 *   IV
	 *
	 * The padding is added so that dm_crypt_request and the IV are
	 * correctly aligned.
	 */
	unsigned int dmreq_start;

	unsigned int per_bio_data_size;

	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
	unsigned int key_size;
	unsigned int key_parts;      /* independent parts in key buffer */
	unsigned int key_extra_size; /* additional keys length */
Linus Torvalds's avatar
Linus Torvalds committed
	u8 key[0];
};

#define MIN_IOS        16
Linus Torvalds's avatar
Linus Torvalds committed

static void clone_init(struct dm_crypt_io *, struct bio *);
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
static u8 *iv_of_dmreq(struct crypt_config *cc, struct dm_crypt_request *dmreq);
/*
 * Use this to access cipher attributes that are the same for each CPU.
 */
static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
{
Linus Torvalds's avatar
Linus Torvalds committed
/*
 * Different IV generation algorithms:
 *
 * plain: the initial vector is the 32-bit little-endian version of the sector
Loading
Loading full blame...