block: Keyslot Manager for Inline Encryption
Inline Encryption hardware allows software to specify an encryption context
(an encryption key, crypto algorithm, data unit num, data unit size) along
with a data transfer request to a storage device, and the inline encryption
hardware will use that context to en/decrypt the data. The inline
encryption hardware is part of the storage device, and it conceptually sits
on the data path between system memory and the storage device.
Inline Encryption hardware implementations often function around the
concept of "keyslots". These implementations often have a limited number
of "keyslots", each of which can hold a key (we say that a key can be
"programmed" into a keyslot). Requests made to the storage device may have
a keyslot and a data unit number associated with them, and the inline
encryption hardware will en/decrypt the data in the requests using the key
programmed into that associated keyslot and the data unit number specified
with the request.
As keyslots are limited, and programming keys may be expensive in many
implementations, and multiple requests may use exactly the same encryption
contexts, we introduce a Keyslot Manager to efficiently manage keyslots.
We also introduce a blk_crypto_key, which will represent the key that's
programmed into keyslots managed by keyslot managers. The keyslot manager
also functions as the interface that upper layers will use to program keys
into inline encryption hardware. For more information on the Keyslot
Manager, refer to documentation found in block/keyslot-manager.c and
linux/keyslot-manager.h.
Co-developed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2020-05-14 03:37:17 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LINUX_BLK_CRYPTO_H
|
|
|
|
#define __LINUX_BLK_CRYPTO_H
|
|
|
|
|
block: Inline encryption support for blk-mq
We must have some way of letting a storage device driver know what
encryption context it should use for en/decrypting a request. However,
it's the upper layers (like the filesystem/fscrypt) that know about and
manages encryption contexts. As such, when the upper layer submits a bio
to the block layer, and this bio eventually reaches a device driver with
support for inline encryption, the device driver will need to have been
told the encryption context for that bio.
We want to communicate the encryption context from the upper layer to the
storage device along with the bio, when the bio is submitted to the block
layer. To do this, we add a struct bio_crypt_ctx to struct bio, which can
represent an encryption context (note that we can't use the bi_private
field in struct bio to do this because that field does not function to pass
information across layers in the storage stack). We also introduce various
functions to manipulate the bio_crypt_ctx and make the bio/request merging
logic aware of the bio_crypt_ctx.
We also make changes to blk-mq to make it handle bios with encryption
contexts. blk-mq can merge many bios into the same request. These bios need
to have contiguous data unit numbers (the necessary changes to blk-merge
are also made to ensure this) - as such, it suffices to keep the data unit
number of just the first bio, since that's all a storage driver needs to
infer the data unit number to use for each data block in each bio in a
request. blk-mq keeps track of the encryption context to be used for all
the bios in a request with the request's rq_crypt_ctx. When the first bio
is added to an empty request, blk-mq will program the encryption context
of that bio into the request_queue's keyslot manager, and store the
returned keyslot in the request's rq_crypt_ctx. All the functions to
operate on encryption contexts are in blk-crypto.c.
Upper layers only need to call bio_crypt_set_ctx with the encryption key,
algorithm and data_unit_num; they don't have to worry about getting a
keyslot for each encryption context, as blk-mq/blk-crypto handles that.
Blk-crypto also makes it possible for request-based layered devices like
dm-rq to make use of inline encryption hardware by cloning the
rq_crypt_ctx and programming a keyslot in the new request_queue when
necessary.
Note that any user of the block layer can submit bios with an
encryption context, such as filesystems, device-mapper targets, etc.
Signed-off-by: Satya Tangirala <satyat@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2020-05-14 03:37:18 +03:00
|
|
|
#include <linux/types.h>
|
|
|
|
|
block: Keyslot Manager for Inline Encryption
Inline Encryption hardware allows software to specify an encryption context
(an encryption key, crypto algorithm, data unit num, data unit size) along
with a data transfer request to a storage device, and the inline encryption
hardware will use that context to en/decrypt the data. The inline
encryption hardware is part of the storage device, and it conceptually sits
on the data path between system memory and the storage device.
Inline Encryption hardware implementations often function around the
concept of "keyslots". These implementations often have a limited number
of "keyslots", each of which can hold a key (we say that a key can be
"programmed" into a keyslot). Requests made to the storage device may have
a keyslot and a data unit number associated with them, and the inline
encryption hardware will en/decrypt the data in the requests using the key
programmed into that associated keyslot and the data unit number specified
with the request.
As keyslots are limited, and programming keys may be expensive in many
implementations, and multiple requests may use exactly the same encryption
contexts, we introduce a Keyslot Manager to efficiently manage keyslots.
We also introduce a blk_crypto_key, which will represent the key that's
programmed into keyslots managed by keyslot managers. The keyslot manager
also functions as the interface that upper layers will use to program keys
into inline encryption hardware. For more information on the Keyslot
Manager, refer to documentation found in block/keyslot-manager.c and
linux/keyslot-manager.h.
Co-developed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2020-05-14 03:37:17 +03:00
|
|
|
enum blk_crypto_mode_num {
|
|
|
|
BLK_ENCRYPTION_MODE_INVALID,
|
|
|
|
BLK_ENCRYPTION_MODE_AES_256_XTS,
|
|
|
|
BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV,
|
|
|
|
BLK_ENCRYPTION_MODE_ADIANTUM,
|
|
|
|
BLK_ENCRYPTION_MODE_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define BLK_CRYPTO_MAX_KEY_SIZE 64
|
|
|
|
/**
|
|
|
|
* struct blk_crypto_config - an inline encryption key's crypto configuration
|
|
|
|
* @crypto_mode: encryption algorithm this key is for
|
|
|
|
* @data_unit_size: the data unit size for all encryption/decryptions with this
|
|
|
|
* key. This is the size in bytes of each individual plaintext and
|
|
|
|
* ciphertext. This is always a power of 2. It might be e.g. the
|
|
|
|
* filesystem block size or the disk sector size.
|
|
|
|
* @dun_bytes: the maximum number of bytes of DUN used when using this key
|
|
|
|
*/
|
|
|
|
struct blk_crypto_config {
|
|
|
|
enum blk_crypto_mode_num crypto_mode;
|
|
|
|
unsigned int data_unit_size;
|
|
|
|
unsigned int dun_bytes;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct blk_crypto_key - an inline encryption key
|
|
|
|
* @crypto_cfg: the crypto configuration (like crypto_mode, key size) for this
|
|
|
|
* key
|
|
|
|
* @data_unit_size_bits: log2 of data_unit_size
|
|
|
|
* @size: size of this key in bytes (determined by @crypto_cfg.crypto_mode)
|
|
|
|
* @raw: the raw bytes of this key. Only the first @size bytes are used.
|
|
|
|
*
|
|
|
|
* A blk_crypto_key is immutable once created, and many bios can reference it at
|
|
|
|
* the same time. It must not be freed until all bios using it have completed
|
|
|
|
* and it has been evicted from all devices on which it may have been used.
|
|
|
|
*/
|
|
|
|
struct blk_crypto_key {
|
|
|
|
struct blk_crypto_config crypto_cfg;
|
|
|
|
unsigned int data_unit_size_bits;
|
|
|
|
unsigned int size;
|
|
|
|
u8 raw[BLK_CRYPTO_MAX_KEY_SIZE];
|
|
|
|
};
|
|
|
|
|
block: Inline encryption support for blk-mq
We must have some way of letting a storage device driver know what
encryption context it should use for en/decrypting a request. However,
it's the upper layers (like the filesystem/fscrypt) that know about and
manages encryption contexts. As such, when the upper layer submits a bio
to the block layer, and this bio eventually reaches a device driver with
support for inline encryption, the device driver will need to have been
told the encryption context for that bio.
We want to communicate the encryption context from the upper layer to the
storage device along with the bio, when the bio is submitted to the block
layer. To do this, we add a struct bio_crypt_ctx to struct bio, which can
represent an encryption context (note that we can't use the bi_private
field in struct bio to do this because that field does not function to pass
information across layers in the storage stack). We also introduce various
functions to manipulate the bio_crypt_ctx and make the bio/request merging
logic aware of the bio_crypt_ctx.
We also make changes to blk-mq to make it handle bios with encryption
contexts. blk-mq can merge many bios into the same request. These bios need
to have contiguous data unit numbers (the necessary changes to blk-merge
are also made to ensure this) - as such, it suffices to keep the data unit
number of just the first bio, since that's all a storage driver needs to
infer the data unit number to use for each data block in each bio in a
request. blk-mq keeps track of the encryption context to be used for all
the bios in a request with the request's rq_crypt_ctx. When the first bio
is added to an empty request, blk-mq will program the encryption context
of that bio into the request_queue's keyslot manager, and store the
returned keyslot in the request's rq_crypt_ctx. All the functions to
operate on encryption contexts are in blk-crypto.c.
Upper layers only need to call bio_crypt_set_ctx with the encryption key,
algorithm and data_unit_num; they don't have to worry about getting a
keyslot for each encryption context, as blk-mq/blk-crypto handles that.
Blk-crypto also makes it possible for request-based layered devices like
dm-rq to make use of inline encryption hardware by cloning the
rq_crypt_ctx and programming a keyslot in the new request_queue when
necessary.
Note that any user of the block layer can submit bios with an
encryption context, such as filesystems, device-mapper targets, etc.
Signed-off-by: Satya Tangirala <satyat@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2020-05-14 03:37:18 +03:00
|
|
|
#define BLK_CRYPTO_MAX_IV_SIZE 32
|
|
|
|
#define BLK_CRYPTO_DUN_ARRAY_SIZE (BLK_CRYPTO_MAX_IV_SIZE / sizeof(u64))
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct bio_crypt_ctx - an inline encryption context
|
|
|
|
* @bc_key: the key, algorithm, and data unit size to use
|
|
|
|
* @bc_dun: the data unit number (starting IV) to use
|
|
|
|
*
|
|
|
|
* A bio_crypt_ctx specifies that the contents of the bio will be encrypted (for
|
|
|
|
* write requests) or decrypted (for read requests) inline by the storage device
|
|
|
|
* or controller.
|
|
|
|
*/
|
|
|
|
struct bio_crypt_ctx {
|
|
|
|
const struct blk_crypto_key *bc_key;
|
|
|
|
u64 bc_dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
#include <linux/blk_types.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
|
|
|
|
struct request;
|
|
|
|
struct request_queue;
|
|
|
|
|
|
|
|
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
|
|
|
|
|
|
|
|
static inline bool bio_has_crypt_ctx(struct bio *bio)
|
|
|
|
{
|
|
|
|
return bio->bi_crypt_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bio_crypt_set_ctx(struct bio *bio, const struct blk_crypto_key *key,
|
|
|
|
const u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
|
|
|
|
gfp_t gfp_mask);
|
|
|
|
|
|
|
|
bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
|
|
|
|
unsigned int bytes,
|
|
|
|
const u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]);
|
|
|
|
|
|
|
|
int blk_crypto_init_key(struct blk_crypto_key *blk_key, const u8 *raw_key,
|
|
|
|
enum blk_crypto_mode_num crypto_mode,
|
|
|
|
unsigned int dun_bytes,
|
|
|
|
unsigned int data_unit_size);
|
|
|
|
|
|
|
|
int blk_crypto_start_using_key(const struct blk_crypto_key *key,
|
|
|
|
struct request_queue *q);
|
|
|
|
|
|
|
|
int blk_crypto_evict_key(struct request_queue *q,
|
|
|
|
const struct blk_crypto_key *key);
|
|
|
|
|
|
|
|
bool blk_crypto_config_supported(struct request_queue *q,
|
|
|
|
const struct blk_crypto_config *cfg);
|
|
|
|
|
|
|
|
#else /* CONFIG_BLK_INLINE_ENCRYPTION */
|
|
|
|
|
|
|
|
static inline bool bio_has_crypt_ctx(struct bio *bio)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_BLK_INLINE_ENCRYPTION */
|
|
|
|
|
|
|
|
void __bio_crypt_clone(struct bio *dst, struct bio *src, gfp_t gfp_mask);
|
|
|
|
static inline void bio_crypt_clone(struct bio *dst, struct bio *src,
|
|
|
|
gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
if (bio_has_crypt_ctx(src))
|
|
|
|
__bio_crypt_clone(dst, src, gfp_mask);
|
|
|
|
}
|
|
|
|
|
block: Keyslot Manager for Inline Encryption
Inline Encryption hardware allows software to specify an encryption context
(an encryption key, crypto algorithm, data unit num, data unit size) along
with a data transfer request to a storage device, and the inline encryption
hardware will use that context to en/decrypt the data. The inline
encryption hardware is part of the storage device, and it conceptually sits
on the data path between system memory and the storage device.
Inline Encryption hardware implementations often function around the
concept of "keyslots". These implementations often have a limited number
of "keyslots", each of which can hold a key (we say that a key can be
"programmed" into a keyslot). Requests made to the storage device may have
a keyslot and a data unit number associated with them, and the inline
encryption hardware will en/decrypt the data in the requests using the key
programmed into that associated keyslot and the data unit number specified
with the request.
As keyslots are limited, and programming keys may be expensive in many
implementations, and multiple requests may use exactly the same encryption
contexts, we introduce a Keyslot Manager to efficiently manage keyslots.
We also introduce a blk_crypto_key, which will represent the key that's
programmed into keyslots managed by keyslot managers. The keyslot manager
also functions as the interface that upper layers will use to program keys
into inline encryption hardware. For more information on the Keyslot
Manager, refer to documentation found in block/keyslot-manager.c and
linux/keyslot-manager.h.
Co-developed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2020-05-14 03:37:17 +03:00
|
|
|
#endif /* __LINUX_BLK_CRYPTO_H */
|