* Re: [PATCH 1/1] block: Add support for setting inline encryption key per block device
[not found] ` <1658316391-13472-2-git-send-email-israelr@nvidia.com>
@ 2022-07-21 6:49 ` Eric Biggers
2022-07-21 12:54 ` Christoph Hellwig
2022-07-26 2:40 ` Daniil Lunev
0 siblings, 2 replies; 4+ messages in thread
From: Eric Biggers @ 2022-07-21 6:49 UTC (permalink / raw)
To: Israel Rukshin
Cc: Linux-block, Jens Axboe, Christoph Hellwig, Nitzan Carmi,
Max Gurtovoy, dm-devel, linux-fscrypt
Hi Israel,
On Wed, Jul 20, 2022 at 02:26:31PM +0300, Israel Rukshin wrote:
> Until now, using inline encryption key has been possible only at
> filesystem level via fs-crypt. The patch allows to set a default
> inline encryption key per block device. Once the key is set, all the
> read commands will be decrypted, and all the write commands will
> be encrypted. The key can be overridden by another key from a higher
> level (FS/DM).
>
> To add/remove a key, the patch introduces a block device ioctl:
> - BLKCRYPTOSETKEY: set a key with the following attributes:
> - crypto_mode: identifier for the encryption algorithm to use
> - raw_key_ptr: pointer to a buffer of the raw key
> - raw_key_size: size in bytes of the raw key
> - data_unit_size: the data unit size to use for en/decryption
> (must be <= device logical block size)
> To remove the key, use the same ioctl with raw_key_size = 0.
> It is not possible to remove the key when it is in use by any
> in-flight IO or when the block device is open.
>
> Signed-off-by: Israel Rukshin <israelr@nvidia.com>
Thanks for sending this out. I've added dm-devel@redhat.com to Cc, as I think
the device-mapper developers need to be aware of this. I also added
linux-fscrypt@vger.kernel.org, as this is relevant there too.
I'm glad to see a proposal in this area -- this is something that is greatly
needed. Chrome OS is looking for something like "dm-crypt with inline crypto
support", which this should work for. Android is also looking for something
similar with the additional property that filesystems can override the key used.
Some high-level comments about this approach (I'll send some more routine code
review nits in a separate email):
> @@ -134,7 +150,8 @@ static inline void bio_crypt_do_front_merge(struct request *rq,
> bool __blk_crypto_bio_prep(struct bio **bio_ptr);
> static inline bool blk_crypto_bio_prep(struct bio **bio_ptr)
> {
> - if (bio_has_crypt_ctx(*bio_ptr))
> + if (bio_has_crypt_ctx(*bio_ptr) ||
> + blk_crypto_bio_set_default_ctx(*bio_ptr))
> return __blk_crypto_bio_prep(bio_ptr);
> return true;
This allows upper layers to override the block device key, which as I've
mentioned is very useful -- it allows block device encryption and file
encryption to be used together without the performance cost of double
encryption. Android already needs and uses this type of encryption.
Still, it's important to understand the limitations of this particular way to
achieve this type of encryption, since I want to make sure everyone is on board.
First, this implementation currently doesn't provide a way to skip the default
key without setting an encryption context. There are actually two cases where
the default key must be skipped when there is no encryption context. The first
is when the filesystem is doing I/O to an encrypted file, but the filesystem
wasn't mounted with the "inlinecrypt" mount option. This could be worked around
by requiring "inlinecrypt" if a default key is set; that loses some flexibility,
but it could be done. The second case, which can't be worked around at the
filesystem level, is that the f2fs garbage collector sometimes has to move the
data of encrypted files on-disk without having access to their encryption key.
So we'll actually need a separate indicator for "skip the default key". The
simplest solution would be a new flag in the bio. However, to avoid using space
in struct bio, it could instead be a special value of the encryption context.
Second, both this solution and dm-based solutions have the property that they
allow the default key to be *arbitrarily* overridden by upper layers. That
means that there is no *general* guarantee that all data on the device is
protected at least as well as the default key. Consider e.g. the default key
being overridden by an all-zeros key. Concerns about this sort of architecture
were raised on a dm-crypt patchset several years ago; see
https://lore.kernel.org/r/0b268ff7-5fc8-c85f-a530-82e9844f0400@gmail.com and
https://lore.kernel.org/r/20170616125511.GA11824@yeono.kjorling.se.
The alternative architecture for this that I've had in mind, and which has been
prototyped for f2fs
(https://lore.kernel.org/linux-f2fs-devel/20201005073606.1949772-1-satyat@google.com/T/#u),
is for the filesystem to manage *all* the encryption, and to mix the default key
into all file keys. Then, all data on the block device would always be
protected by the default key or better, regardless of userspace.
On the other hand, I'd personally be fine with saying that this isn't actually
needed, i.e. that allowing arbitrary overriding of the default key is fine,
since userspace should just set up the keys properly. For example, Android
doesn't need this at all, as it sets up all its keys properly. But I want to
make sure that everyone is generally okay with this now, as I personally don't
see a fundamental difference between this and what the dm-crypt developers had
rejected *very* forcefully before. Perhaps it's acceptable now simply because
it wouldn't be part of dm-crypt; it's a new thing, so it can have new semantics.
> +static int blk_crypto_ioctl_create_key(struct request_queue *q,
> + void __user *argp)
> +{
> + struct blk_crypto_set_key_arg arg;
> + u8 raw_key[BLK_CRYPTO_MAX_KEY_SIZE];
> + struct blk_crypto_key *blk_key;
> + int ret;
> +
> + if (copy_from_user(&arg, argp, sizeof(arg)))
> + return -EFAULT;
> +
> + if (memchr_inv(arg.reserved, 0, sizeof(arg.reserved)))
> + return -EINVAL;
> +
> + if (!arg.raw_key_size)
> + return blk_crypto_destroy_default_key(q);
> +
> + if (q->blk_key) {
> + pr_err("Crypto key is already configured\n");
> + return -EBUSY;
> + }
> +
> + if (arg.raw_key_size > sizeof(raw_key))
> + return -EINVAL;
> +
> + if (arg.data_unit_size > queue_logical_block_size(q)) {
> + pr_err("Data unit size is bigger than logical block size\n");
> + return -EINVAL;
> + }
This is forbidding data_unit_size greater than logical_block_size. I see why
you did this: the block layer doesn't know what is above it, and it could
receive I/O requests targeting individual logical blocks. However, this can
result in a big efficiency loss; a common example is when a filesystem with a
4096-byte block size is used on a block device with a logical block size of 512
bytes. Since such a filesystem only submits I/O in 4096-byte blocks, it's safe
for the data_unit_size to be 4096 bytes as well. This is much more efficient
than 512 bytes, since there is overhead for every data unit. Note that some of
this overhead is intrinsic in the crypto algorithms themselves and cannot be
optimized out by better hardware.
The device-mapper based solution wouldn't have this problem, as the
device-mapper target (dm-inlinecrypt or whatever) would just advertise the
crypto data unit size as the logical block size, like dm-crypt does.
I'm wondering if anyone any thoughts about how to allow data_unit_size >
logical_block_size with this patch's approach. I suppose that the ioctl could
just allow setting it, and the block layer could fail any I/O that isn't
properly aligned to the data_unit_size.
- Eric
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/1] block: Add support for setting inline encryption key per block device
2022-07-21 6:49 ` [PATCH 1/1] block: Add support for setting inline encryption key per block device Eric Biggers
@ 2022-07-21 12:54 ` Christoph Hellwig
2022-07-22 8:20 ` [dm-devel] " Milan Broz
2022-07-26 2:40 ` Daniil Lunev
1 sibling, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2022-07-21 12:54 UTC (permalink / raw)
To: Eric Biggers
Cc: Israel Rukshin, Linux-block, Jens Axboe, Christoph Hellwig,
Nitzan Carmi, Max Gurtovoy, dm-devel, linux-fscrypt
On Wed, Jul 20, 2022 at 11:49:07PM -0700, Eric Biggers wrote:
> On the other hand, I'd personally be fine with saying that this isn't actually
> needed, i.e. that allowing arbitrary overriding of the default key is fine,
> since userspace should just set up the keys properly. For example, Android
> doesn't need this at all, as it sets up all its keys properly. But I want to
> make sure that everyone is generally okay with this now, as I personally don't
> see a fundamental difference between this and what the dm-crypt developers had
> rejected *very* forcefully before. Perhaps it's acceptable now simply because
> it wouldn't be part of dm-crypt; it's a new thing, so it can have new semantics.
I agree with both the dm-crypt maintainer and you on this. dm-crypt is
a full disk encryption solution and has to provide guarantees, so it
can't let upper layers degrade the cypher. The block layer support on
the other hand is just a building block an can as long as it is carefully
documented.
> I'm wondering if anyone any thoughts about how to allow data_unit_size >
> logical_block_size with this patch's approach. I suppose that the ioctl could
> just allow setting it, and the block layer could fail any I/O that isn't
> properly aligned to the data_unit_size.
We could do that, but we'd need to comunicate the limit to the upper
layers both in the kernel an user space. Effectively this changes the
logical block size for all practical purposes.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [dm-devel] [PATCH 1/1] block: Add support for setting inline encryption key per block device
2022-07-21 12:54 ` Christoph Hellwig
@ 2022-07-22 8:20 ` Milan Broz
0 siblings, 0 replies; 4+ messages in thread
From: Milan Broz @ 2022-07-22 8:20 UTC (permalink / raw)
To: Christoph Hellwig, Eric Biggers
Cc: Jens Axboe, Max Gurtovoy, Israel Rukshin, linux-fscrypt,
Linux-block, dm-devel, Nitzan Carmi
On 21/07/2022 14:54, Christoph Hellwig wrote:
> On Wed, Jul 20, 2022 at 11:49:07PM -0700, Eric Biggers wrote:
>> On the other hand, I'd personally be fine with saying that this isn't actually
>> needed, i.e. that allowing arbitrary overriding of the default key is fine,
>> since userspace should just set up the keys properly. For example, Android
>> doesn't need this at all, as it sets up all its keys properly. But I want to
>> make sure that everyone is generally okay with this now, as I personally don't
>> see a fundamental difference between this and what the dm-crypt developers had
>> rejected *very* forcefully before. Perhaps it's acceptable now simply because
>> it wouldn't be part of dm-crypt; it's a new thing, so it can have new semantics.
>
> I agree with both the dm-crypt maintainer and you on this. dm-crypt is
> a full disk encryption solution and has to provide guarantees, so it
> can't let upper layers degrade the cypher. The block layer support on
> the other hand is just a building block an can as long as it is carefully
> documented.
Yes, that is what I meant when complaining about the last dm-crypt patch.
I think inline encryption for block devices is a good idea; my complaint was
integration with dm-crypt - as it can dilute expectations and create a new
threat model here.
But I also think that implementing this directly in the block layer makes sense.
Perhaps it should be generic enough.
(I can imagine dynamic inline encryption integrated into LVM ... :-)
>> I'm wondering if anyone any thoughts about how to allow data_unit_size >
>> logical_block_size with this patch's approach. I suppose that the ioctl could
>> just allow setting it, and the block layer could fail any I/O that isn't
>> properly aligned to the data_unit_size.
>
> We could do that, but we'd need to comunicate the limit to the upper
> layers both in the kernel an user space. Effectively this changes the
> logical block size for all practical purposes.
I think you should support setting logical encryption size from the beginning,
at least prepare API for that. It has a big impact on performance.
The dm-crypt also requires aligned IO here. We propagate new logical size
to upper layers (and also to loop device below, if used).
(Also this revealed hacks in USB enclosures mapping unaligned devices...)
Milan
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/1] block: Add support for setting inline encryption key per block device
2022-07-21 6:49 ` [PATCH 1/1] block: Add support for setting inline encryption key per block device Eric Biggers
2022-07-21 12:54 ` Christoph Hellwig
@ 2022-07-26 2:40 ` Daniil Lunev
1 sibling, 0 replies; 4+ messages in thread
From: Daniil Lunev @ 2022-07-26 2:40 UTC (permalink / raw)
To: Israel Rukshin, Eric Biggers
Cc: Linux-block, Jens Axboe, Christoph Hellwig, Nitzan Carmi,
Max Gurtovoy, dm-devel, linux-fscrypt
On Wed, Jul 20, 2022 at 11:49:07PM -0700, Eric Biggers wrote:
> I'm glad to see a proposal in this area -- this is something that is greatly
> needed. Chrome OS is looking for something like "dm-crypt with inline crypto
> support", which this should work for. Android is also looking for something
> similar with the additional property that filesystems can override the key used.
Yes, this is exciting to see proposals in this area. In ChromeOS we were
contemplating ways to upstream Eric's work for Android. This solution should
work generally for our use-case, however I would like to add a few extra pieces
we were considering.
One thing we were looking for is having an option to pass inline encryption keys
via keyrings, similarly to how dm-crypt allows suuplying keys both ways: raw and
keyring attached. I would assume that is something that should still be possible
with the IOCTL-based approach, though proposed API can make it a bit obscure. I
was wondering whether there should be a separate field to allow this kind of
differentiation?
The other aspect is the key lifetime. Current implementation doesn't allow to
unset the key once set. This is something that would still work with dm setups,
presumably, since the key lifetime is tied to the lifetime of the device itself,
but may render problematic if this is applied to a raw device or partition of a
raw device, I would assume - allowing no ways to rotate the key without reboot.
I am not sure if this is a particularly important issue, but something that I
wanted to raise for the discussion. This also becomes relevant in the context of
the keyring usages, i.e. whether to revoke the key from the block device when
the key is removed from the keyring, or assume it is bound at the time of device
setup. The dm-crypt follows the latter model, AFAIU, and it is fine to keep it
consistent, but then the question comes back to inability to remove the key in
the current API in general.
And speaking about dm, the other thing we were looking into is compatibility of
inline encryption key setup with dm stacks. Current kernel implementaiton
propagates the crypto context through linear and flakey target, we also had
initial tests enabling it on thin pools by adding DM_TARGET_PASSES_CRYPTO, which
didn't show any problems at first glance (but more testing is required). We
believe that an ability to setup multiple different dm targets with different
keys over the same physical device is an important use case - and as far as I
can tell proposed approach supports it, but wanted to highlight that as well.
--Daniil
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2022-07-26 2:40 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1658316391-13472-1-git-send-email-israelr@nvidia.com>
[not found] ` <1658316391-13472-2-git-send-email-israelr@nvidia.com>
2022-07-21 6:49 ` [PATCH 1/1] block: Add support for setting inline encryption key per block device Eric Biggers
2022-07-21 12:54 ` Christoph Hellwig
2022-07-22 8:20 ` [dm-devel] " Milan Broz
2022-07-26 2:40 ` Daniil Lunev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox