2019-05-19 20:08:20 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2015-05-16 07:26:10 +08:00
|
|
|
/*
|
|
|
|
* This contains encryption functions for per-file encryption.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015, Google, Inc.
|
|
|
|
* Copyright (C) 2015, Motorola Mobility
|
|
|
|
*
|
|
|
|
* Written by Michael Halcrow, 2014.
|
|
|
|
*
|
|
|
|
* Filename encryption additions
|
|
|
|
* Uday Savagaonkar, 2014
|
|
|
|
* Encryption policy handling additions
|
|
|
|
* Ildar Muslukhov, 2014
|
|
|
|
* Add fscrypt_pullback_bio_page()
|
|
|
|
* Jaegeuk Kim, 2015.
|
|
|
|
*
|
|
|
|
* This has not yet undergone a rigorous security audit.
|
|
|
|
*
|
|
|
|
* The usage of AES-XTS should conform to recommendations in NIST
|
|
|
|
* Special Publication 800-38E and IEEE P1619/D16.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/mempool.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/scatterlist.h>
|
|
|
|
#include <linux/ratelimit.h>
|
2018-01-06 02:45:00 +08:00
|
|
|
#include <crypto/skcipher.h>
|
2016-11-27 11:05:18 +08:00
|
|
|
#include "fscrypt_private.h"
|
2015-05-16 07:26:10 +08:00
|
|
|
|
|
|
|
static unsigned int num_prealloc_crypto_pages = 32;
|
|
|
|
|
|
|
|
module_param(num_prealloc_crypto_pages, uint, 0444);
|
|
|
|
MODULE_PARM_DESC(num_prealloc_crypto_pages,
|
|
|
|
"Number of crypto pages to preallocate");
|
|
|
|
|
|
|
|
static mempool_t *fscrypt_bounce_page_pool = NULL;
|
|
|
|
|
2018-04-19 02:09:47 +08:00
|
|
|
static struct workqueue_struct *fscrypt_read_workqueue;
|
2015-05-16 07:26:10 +08:00
|
|
|
static DEFINE_MUTEX(fscrypt_init_mutex);
|
|
|
|
|
|
|
|
struct kmem_cache *fscrypt_info_cachep;
|
|
|
|
|
2018-04-19 02:09:47 +08:00
|
|
|
void fscrypt_enqueue_decrypt_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
queue_work(fscrypt_read_workqueue, work);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
|
|
|
|
|
2019-05-21 00:29:39 +08:00
|
|
|
struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
|
|
|
|
{
|
|
|
|
return mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fscrypt_free_bounce_page() - free a ciphertext bounce page
|
2020-05-12 03:13:56 +08:00
|
|
|
* @bounce_page: the bounce page to free, or NULL
|
2019-05-21 00:29:39 +08:00
|
|
|
*
|
2019-05-21 00:29:44 +08:00
|
|
|
* Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(),
|
|
|
|
* or by fscrypt_alloc_bounce_page() directly.
|
2019-05-21 00:29:39 +08:00
|
|
|
*/
|
|
|
|
void fscrypt_free_bounce_page(struct page *bounce_page)
|
|
|
|
{
|
|
|
|
if (!bounce_page)
|
|
|
|
return;
|
|
|
|
set_page_private(bounce_page, (unsigned long)NULL);
|
|
|
|
ClearPagePrivate(bounce_page);
|
|
|
|
mempool_free(bounce_page, fscrypt_bounce_page_pool);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(fscrypt_free_bounce_page);
|
|
|
|
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
|
|
|
|
const struct fscrypt_info *ci)
|
|
|
|
{
|
fscrypt: add support for IV_INO_LBLK_64 policies
Inline encryption hardware compliant with the UFS v2.1 standard or with
the upcoming version of the eMMC standard has the following properties:
(1) Per I/O request, the encryption key is specified by a previously
loaded keyslot. There might be only a small number of keyslots.
(2) Per I/O request, the starting IV is specified by a 64-bit "data unit
number" (DUN). IV bits 64-127 are assumed to be 0. The hardware
automatically increments the DUN for each "data unit" of
configurable size in the request, e.g. for each filesystem block.
Property (1) makes it inefficient to use the traditional fscrypt
per-file keys. Property (2) precludes the use of the existing
DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
encryption to modified as follows:
- The encryption keys are derived from the master key, encryption mode
number, and filesystem UUID.
- The IVs are chosen as (inode_number << 32) | file_logical_block_num.
For filenames encryption, file_logical_block_num is 0.
Since the file nonces aren't used in the key derivation, many files may
share the same encryption key. This is much more efficient on the
target hardware. Including the inode number in the IVs and mixing the
filesystem UUID into the keys ensures that data in different files is
nevertheless still encrypted differently.
Additionally, limiting the inode and block numbers to 32 bits and
placing the block number in the low bits maintains compatibility with
the 64-bit DUN convention (property (2) above).
Since this scheme assumes that inode numbers are stable (which may
preclude filesystem shrinking) and that inode and file logical block
numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
filesystems that meet these constraints. These are acceptable
limitations for the cases where this format would actually be used.
Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
This patch just adds support for it using the existing filesystem layer
encryption. A later patch will add support for inline encryption.
Reviewed-by: Paul Crowley <paulcrowley@google.com>
Co-developed-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-10-25 05:54:36 +08:00
|
|
|
u8 flags = fscrypt_policy_flags(&ci->ci_policy);
|
|
|
|
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
memset(iv, 0, ci->ci_mode->ivsize);
|
|
|
|
|
fscrypt: add support for IV_INO_LBLK_64 policies
Inline encryption hardware compliant with the UFS v2.1 standard or with
the upcoming version of the eMMC standard has the following properties:
(1) Per I/O request, the encryption key is specified by a previously
loaded keyslot. There might be only a small number of keyslots.
(2) Per I/O request, the starting IV is specified by a 64-bit "data unit
number" (DUN). IV bits 64-127 are assumed to be 0. The hardware
automatically increments the DUN for each "data unit" of
configurable size in the request, e.g. for each filesystem block.
Property (1) makes it inefficient to use the traditional fscrypt
per-file keys. Property (2) precludes the use of the existing
DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
encryption to modified as follows:
- The encryption keys are derived from the master key, encryption mode
number, and filesystem UUID.
- The IVs are chosen as (inode_number << 32) | file_logical_block_num.
For filenames encryption, file_logical_block_num is 0.
Since the file nonces aren't used in the key derivation, many files may
share the same encryption key. This is much more efficient on the
target hardware. Including the inode number in the IVs and mixing the
filesystem UUID into the keys ensures that data in different files is
nevertheless still encrypted differently.
Additionally, limiting the inode and block numbers to 32 bits and
placing the block number in the low bits maintains compatibility with
the 64-bit DUN convention (property (2) above).
Since this scheme assumes that inode numbers are stable (which may
preclude filesystem shrinking) and that inode and file logical block
numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
filesystems that meet these constraints. These are acceptable
limitations for the cases where this format would actually be used.
Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
This patch just adds support for it using the existing filesystem layer
encryption. A later patch will add support for inline encryption.
Reviewed-by: Paul Crowley <paulcrowley@google.com>
Co-developed-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-10-25 05:54:36 +08:00
|
|
|
if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
|
2020-05-16 04:41:41 +08:00
|
|
|
WARN_ON_ONCE(lblk_num > U32_MAX);
|
|
|
|
WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX);
|
fscrypt: add support for IV_INO_LBLK_64 policies
Inline encryption hardware compliant with the UFS v2.1 standard or with
the upcoming version of the eMMC standard has the following properties:
(1) Per I/O request, the encryption key is specified by a previously
loaded keyslot. There might be only a small number of keyslots.
(2) Per I/O request, the starting IV is specified by a 64-bit "data unit
number" (DUN). IV bits 64-127 are assumed to be 0. The hardware
automatically increments the DUN for each "data unit" of
configurable size in the request, e.g. for each filesystem block.
Property (1) makes it inefficient to use the traditional fscrypt
per-file keys. Property (2) precludes the use of the existing
DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
encryption to modified as follows:
- The encryption keys are derived from the master key, encryption mode
number, and filesystem UUID.
- The IVs are chosen as (inode_number << 32) | file_logical_block_num.
For filenames encryption, file_logical_block_num is 0.
Since the file nonces aren't used in the key derivation, many files may
share the same encryption key. This is much more efficient on the
target hardware. Including the inode number in the IVs and mixing the
filesystem UUID into the keys ensures that data in different files is
nevertheless still encrypted differently.
Additionally, limiting the inode and block numbers to 32 bits and
placing the block number in the low bits maintains compatibility with
the 64-bit DUN convention (property (2) above).
Since this scheme assumes that inode numbers are stable (which may
preclude filesystem shrinking) and that inode and file logical block
numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
filesystems that meet these constraints. These are acceptable
limitations for the cases where this format would actually be used.
Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
This patch just adds support for it using the existing filesystem layer
encryption. A later patch will add support for inline encryption.
Reviewed-by: Paul Crowley <paulcrowley@google.com>
Co-developed-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-10-25 05:54:36 +08:00
|
|
|
lblk_num |= (u64)ci->ci_inode->i_ino << 32;
|
2020-05-16 04:41:41 +08:00
|
|
|
} else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
|
|
|
|
WARN_ON_ONCE(lblk_num > U32_MAX);
|
|
|
|
lblk_num = (u32)(ci->ci_hashed_ino + lblk_num);
|
fscrypt: add support for IV_INO_LBLK_64 policies
Inline encryption hardware compliant with the UFS v2.1 standard or with
the upcoming version of the eMMC standard has the following properties:
(1) Per I/O request, the encryption key is specified by a previously
loaded keyslot. There might be only a small number of keyslots.
(2) Per I/O request, the starting IV is specified by a 64-bit "data unit
number" (DUN). IV bits 64-127 are assumed to be 0. The hardware
automatically increments the DUN for each "data unit" of
configurable size in the request, e.g. for each filesystem block.
Property (1) makes it inefficient to use the traditional fscrypt
per-file keys. Property (2) precludes the use of the existing
DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
encryption to modified as follows:
- The encryption keys are derived from the master key, encryption mode
number, and filesystem UUID.
- The IVs are chosen as (inode_number << 32) | file_logical_block_num.
For filenames encryption, file_logical_block_num is 0.
Since the file nonces aren't used in the key derivation, many files may
share the same encryption key. This is much more efficient on the
target hardware. Including the inode number in the IVs and mixing the
filesystem UUID into the keys ensures that data in different files is
nevertheless still encrypted differently.
Additionally, limiting the inode and block numbers to 32 bits and
placing the block number in the low bits maintains compatibility with
the 64-bit DUN convention (property (2) above).
Since this scheme assumes that inode numbers are stable (which may
preclude filesystem shrinking) and that inode and file logical block
numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
filesystems that meet these constraints. These are acceptable
limitations for the cases where this format would actually be used.
Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
This patch just adds support for it using the existing filesystem layer
encryption. A later patch will add support for inline encryption.
Reviewed-by: Paul Crowley <paulcrowley@google.com>
Co-developed-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-10-25 05:54:36 +08:00
|
|
|
} else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
|
fscrypt: add support for IV_INO_LBLK_64 policies
Inline encryption hardware compliant with the UFS v2.1 standard or with
the upcoming version of the eMMC standard has the following properties:
(1) Per I/O request, the encryption key is specified by a previously
loaded keyslot. There might be only a small number of keyslots.
(2) Per I/O request, the starting IV is specified by a 64-bit "data unit
number" (DUN). IV bits 64-127 are assumed to be 0. The hardware
automatically increments the DUN for each "data unit" of
configurable size in the request, e.g. for each filesystem block.
Property (1) makes it inefficient to use the traditional fscrypt
per-file keys. Property (2) precludes the use of the existing
DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits.
Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the
encryption to modified as follows:
- The encryption keys are derived from the master key, encryption mode
number, and filesystem UUID.
- The IVs are chosen as (inode_number << 32) | file_logical_block_num.
For filenames encryption, file_logical_block_num is 0.
Since the file nonces aren't used in the key derivation, many files may
share the same encryption key. This is much more efficient on the
target hardware. Including the inode number in the IVs and mixing the
filesystem UUID into the keys ensures that data in different files is
nevertheless still encrypted differently.
Additionally, limiting the inode and block numbers to 32 bits and
placing the block number in the low bits maintains compatibility with
the 64-bit DUN convention (property (2) above).
Since this scheme assumes that inode numbers are stable (which may
preclude filesystem shrinking) and that inode and file logical block
numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on
filesystems that meet these constraints. These are acceptable
limitations for the cases where this format would actually be used.
Note that IV_INO_LBLK_64 is an on-disk format, not an implementation.
This patch just adds support for it using the existing filesystem layer
encryption. A later patch will add support for inline encryption.
Reviewed-by: Paul Crowley <paulcrowley@google.com>
Co-developed-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Satya Tangirala <satyat@google.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-10-25 05:54:36 +08:00
|
|
|
}
|
|
|
|
iv->lblk_num = cpu_to_le64(lblk_num);
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
}
|
|
|
|
|
2019-05-21 00:29:41 +08:00
|
|
|
/* Encrypt or decrypt a single filesystem block of file contents */
|
|
|
|
int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
|
|
|
|
u64 lblk_num, struct page *src_page,
|
|
|
|
struct page *dest_page, unsigned int len,
|
|
|
|
unsigned int offs, gfp_t gfp_flags)
|
2015-05-16 07:26:10 +08:00
|
|
|
{
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
union fscrypt_iv iv;
|
2016-03-22 02:03:02 +08:00
|
|
|
struct skcipher_request *req = NULL;
|
2017-10-18 15:00:44 +08:00
|
|
|
DECLARE_CRYPTO_WAIT(wait);
|
2015-05-16 07:26:10 +08:00
|
|
|
struct scatterlist dst, src;
|
|
|
|
struct fscrypt_info *ci = inode->i_crypt_info;
|
2016-03-22 02:03:02 +08:00
|
|
|
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
2015-05-16 07:26:10 +08:00
|
|
|
int res = 0;
|
|
|
|
|
2019-05-21 00:29:42 +08:00
|
|
|
if (WARN_ON_ONCE(len <= 0))
|
|
|
|
return -EINVAL;
|
|
|
|
if (WARN_ON_ONCE(len % FS_CRYPTO_BLOCK_SIZE != 0))
|
|
|
|
return -EINVAL;
|
2016-12-07 06:53:55 +08:00
|
|
|
|
fscrypt: add Adiantum support
Add support for the Adiantum encryption mode to fscrypt. Adiantum is a
tweakable, length-preserving encryption mode with security provably
reducible to that of XChaCha12 and AES-256, subject to a security bound.
It's also a true wide-block mode, unlike XTS. See the paper
"Adiantum: length-preserving encryption for entry-level processors"
(https://eprint.iacr.org/2018/720.pdf) for more details. Also see
commit 059c2a4d8e16 ("crypto: adiantum - add Adiantum support").
On sufficiently long messages, Adiantum's bottlenecks are XChaCha12 and
the NH hash function. These algorithms are fast even on processors
without dedicated crypto instructions. Adiantum makes it feasible to
enable storage encryption on low-end mobile devices that lack AES
instructions; currently such devices are unencrypted. On ARM Cortex-A7,
on 4096-byte messages Adiantum encryption is about 4 times faster than
AES-256-XTS encryption; decryption is about 5 times faster.
In fscrypt, Adiantum is suitable for encrypting both file contents and
names. With filenames, it fixes a known weakness: when two filenames in
a directory share a common prefix of >= 16 bytes, with CTS-CBC their
encrypted filenames share a common prefix too, leaking information.
Adiantum does not have this problem.
Since Adiantum also accepts long tweaks (IVs), it's also safe to use the
master key directly for Adiantum encryption rather than deriving
per-file keys, provided that the per-file nonce is included in the IVs
and the master key isn't used for any other encryption mode. This
configuration saves memory and improves performance. A new fscrypt
policy flag is added to allow users to opt-in to this configuration.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2019-01-06 21:36:21 +08:00
|
|
|
fscrypt_generate_iv(&iv, lblk_num, ci);
|
2017-06-19 15:27:58 +08:00
|
|
|
|
2016-04-12 06:51:57 +08:00
|
|
|
req = skcipher_request_alloc(tfm, gfp_flags);
|
2018-05-01 06:51:38 +08:00
|
|
|
if (!req)
|
2015-05-16 07:26:10 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-03-22 02:03:02 +08:00
|
|
|
skcipher_request_set_callback(
|
2015-05-16 07:26:10 +08:00
|
|
|
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
2017-10-18 15:00:44 +08:00
|
|
|
crypto_req_done, &wait);
|
2015-05-16 07:26:10 +08:00
|
|
|
|
|
|
|
sg_init_table(&dst, 1);
|
2016-12-07 06:53:55 +08:00
|
|
|
sg_set_page(&dst, dest_page, len, offs);
|
2015-05-16 07:26:10 +08:00
|
|
|
sg_init_table(&src, 1);
|
2016-12-07 06:53:55 +08:00
|
|
|
sg_set_page(&src, src_page, len, offs);
|
2017-06-19 15:27:58 +08:00
|
|
|
skcipher_request_set_crypt(req, &src, &dst, len, &iv);
|
2015-05-16 07:26:10 +08:00
|
|
|
if (rw == FS_DECRYPT)
|
2017-10-18 15:00:44 +08:00
|
|
|
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
2015-05-16 07:26:10 +08:00
|
|
|
else
|
2017-10-18 15:00:44 +08:00
|
|
|
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
2016-03-22 02:03:02 +08:00
|
|
|
skcipher_request_free(req);
|
2015-05-16 07:26:10 +08:00
|
|
|
if (res) {
|
2019-07-25 02:07:58 +08:00
|
|
|
fscrypt_err(inode, "%scryption failed for block %llu: %d",
|
|
|
|
(rw == FS_DECRYPT ? "De" : "En"), lblk_num, res);
|
2015-05-16 07:26:10 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-12 03:13:56 +08:00
|
|
|
* fscrypt_encrypt_pagecache_blocks() - Encrypt filesystem blocks from a
|
|
|
|
* pagecache page
|
2019-05-21 00:29:44 +08:00
|
|
|
* @page: The locked pagecache page containing the block(s) to encrypt
|
|
|
|
* @len: Total size of the block(s) to encrypt. Must be a nonzero
|
|
|
|
* multiple of the filesystem's block size.
|
|
|
|
* @offs: Byte offset within @page of the first block to encrypt. Must be
|
|
|
|
* a multiple of the filesystem's block size.
|
2020-01-01 02:10:26 +08:00
|
|
|
* @gfp_flags: Memory allocation flags. See details below.
|
2019-05-21 00:29:44 +08:00
|
|
|
*
|
|
|
|
* A new bounce page is allocated, and the specified block(s) are encrypted into
|
|
|
|
* it. In the bounce page, the ciphertext block(s) will be located at the same
|
|
|
|
* offsets at which the plaintext block(s) were located in the source page; any
|
|
|
|
* other parts of the bounce page will be left uninitialized. However, normally
|
|
|
|
* blocksize == PAGE_SIZE and the whole page is encrypted at once.
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
2019-05-21 00:29:44 +08:00
|
|
|
* This is for use by the filesystem's ->writepages() method.
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
2020-01-01 02:10:26 +08:00
|
|
|
* The bounce page allocation is mempool-backed, so it will always succeed when
|
|
|
|
* @gfp_flags includes __GFP_DIRECT_RECLAIM, e.g. when it's GFP_NOFS. However,
|
|
|
|
* only the first page of each bio can be allocated this way. To prevent
|
|
|
|
* deadlocks, for any additional pages a mask like GFP_NOWAIT must be used.
|
|
|
|
*
|
2019-05-21 00:29:44 +08:00
|
|
|
* Return: the new encrypted bounce page on success; an ERR_PTR() on failure
|
2015-05-16 07:26:10 +08:00
|
|
|
*/
|
2019-05-21 00:29:44 +08:00
|
|
|
struct page *fscrypt_encrypt_pagecache_blocks(struct page *page,
|
|
|
|
unsigned int len,
|
|
|
|
unsigned int offs,
|
|
|
|
gfp_t gfp_flags)
|
2016-11-14 05:20:46 +08:00
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
{
|
2019-05-21 00:29:44 +08:00
|
|
|
const struct inode *inode = page->mapping->host;
|
|
|
|
const unsigned int blockbits = inode->i_blkbits;
|
|
|
|
const unsigned int blocksize = 1 << blockbits;
|
2019-05-21 00:29:43 +08:00
|
|
|
struct page *ciphertext_page;
|
2019-05-21 00:29:44 +08:00
|
|
|
u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
|
|
|
|
(offs >> blockbits);
|
|
|
|
unsigned int i;
|
2015-05-16 07:26:10 +08:00
|
|
|
int err;
|
|
|
|
|
2019-05-21 00:29:42 +08:00
|
|
|
if (WARN_ON_ONCE(!PageLocked(page)))
|
|
|
|
return ERR_PTR(-EINVAL);
|
2016-12-07 06:53:56 +08:00
|
|
|
|
2019-05-21 00:29:44 +08:00
|
|
|
if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2019-05-21 00:29:39 +08:00
|
|
|
ciphertext_page = fscrypt_alloc_bounce_page(gfp_flags);
|
|
|
|
if (!ciphertext_page)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-05-21 00:29:44 +08:00
|
|
|
for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
|
|
|
|
err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num,
|
|
|
|
page, ciphertext_page,
|
|
|
|
blocksize, i, gfp_flags);
|
|
|
|
if (err) {
|
|
|
|
fscrypt_free_bounce_page(ciphertext_page);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
2015-05-16 07:26:10 +08:00
|
|
|
}
|
2016-12-07 06:53:54 +08:00
|
|
|
SetPagePrivate(ciphertext_page);
|
2019-05-21 00:29:39 +08:00
|
|
|
set_page_private(ciphertext_page, (unsigned long)page);
|
2015-05-16 07:26:10 +08:00
|
|
|
return ciphertext_page;
|
|
|
|
}
|
2019-05-21 00:29:44 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-05-21 00:29:43 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_encrypt_block_inplace() - Encrypt a filesystem block in-place
|
|
|
|
* @inode: The inode to which this block belongs
|
|
|
|
* @page: The page containing the block to encrypt
|
|
|
|
* @len: Size of block to encrypt. Doesn't need to be a multiple of the
|
|
|
|
* fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE.
|
|
|
|
* @offs: Byte offset within @page at which the block to encrypt begins
|
|
|
|
* @lblk_num: Filesystem logical block number of the block, i.e. the 0-based
|
|
|
|
* number of the block within the file
|
|
|
|
* @gfp_flags: Memory allocation flags
|
|
|
|
*
|
|
|
|
* Encrypt a possibly-compressed filesystem block that is located in an
|
|
|
|
* arbitrary page, not necessarily in the original pagecache page. The @inode
|
|
|
|
* and @lblk_num must be specified, as they can't be determined from @page.
|
|
|
|
*
|
|
|
|
* Return: 0 on success; -errno on failure
|
|
|
|
*/
|
|
|
|
int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
|
|
|
|
unsigned int len, unsigned int offs,
|
|
|
|
u64 lblk_num, gfp_t gfp_flags)
|
|
|
|
{
|
|
|
|
return fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num, page, page,
|
|
|
|
len, offs, gfp_flags);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
|
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
/**
|
2020-05-12 03:13:56 +08:00
|
|
|
* fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a
|
|
|
|
* pagecache page
|
2019-05-21 00:29:47 +08:00
|
|
|
* @page: The locked pagecache page containing the block(s) to decrypt
|
|
|
|
* @len: Total size of the block(s) to decrypt. Must be a nonzero
|
|
|
|
* multiple of the filesystem's block size.
|
|
|
|
* @offs: Byte offset within @page of the first block to decrypt. Must be
|
|
|
|
* a multiple of the filesystem's block size.
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
2019-05-21 00:29:47 +08:00
|
|
|
* The specified block(s) are decrypted in-place within the pagecache page,
|
|
|
|
* which must still be locked and not uptodate. Normally, blocksize ==
|
|
|
|
* PAGE_SIZE and the whole page is decrypted at once.
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
2019-05-21 00:29:47 +08:00
|
|
|
* This is for use by the filesystem's ->readpages() method.
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
2019-05-21 00:29:47 +08:00
|
|
|
* Return: 0 on success; -errno on failure
|
2015-05-16 07:26:10 +08:00
|
|
|
*/
|
2019-05-21 00:29:47 +08:00
|
|
|
int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
|
|
|
|
unsigned int offs)
|
2015-05-16 07:26:10 +08:00
|
|
|
{
|
2019-05-21 00:29:47 +08:00
|
|
|
const struct inode *inode = page->mapping->host;
|
|
|
|
const unsigned int blockbits = inode->i_blkbits;
|
|
|
|
const unsigned int blocksize = 1 << blockbits;
|
|
|
|
u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
|
|
|
|
(offs >> blockbits);
|
|
|
|
unsigned int i;
|
|
|
|
int err;
|
|
|
|
|
2019-05-21 00:29:46 +08:00
|
|
|
if (WARN_ON_ONCE(!PageLocked(page)))
|
2019-05-21 00:29:42 +08:00
|
|
|
return -EINVAL;
|
2016-12-07 06:53:56 +08:00
|
|
|
|
2019-05-21 00:29:47 +08:00
|
|
|
if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
|
|
|
|
err = fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page,
|
|
|
|
page, blocksize, i, GFP_NOFS);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return 0;
|
2015-05-16 07:26:10 +08:00
|
|
|
}
|
2019-05-21 00:29:47 +08:00
|
|
|
EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-05-21 00:29:46 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
|
|
|
|
* @inode: The inode to which this block belongs
|
|
|
|
* @page: The page containing the block to decrypt
|
|
|
|
* @len: Size of block to decrypt. Doesn't need to be a multiple of the
|
|
|
|
* fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE.
|
|
|
|
* @offs: Byte offset within @page at which the block to decrypt begins
|
|
|
|
* @lblk_num: Filesystem logical block number of the block, i.e. the 0-based
|
|
|
|
* number of the block within the file
|
|
|
|
*
|
|
|
|
* Decrypt a possibly-compressed filesystem block that is located in an
|
|
|
|
* arbitrary page, not necessarily in the original pagecache page. The @inode
|
|
|
|
* and @lblk_num must be specified, as they can't be determined from @page.
|
|
|
|
*
|
|
|
|
* Return: 0 on success; -errno on failure
|
|
|
|
*/
|
|
|
|
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
|
|
|
|
unsigned int len, unsigned int offs,
|
|
|
|
u64 lblk_num)
|
|
|
|
{
|
|
|
|
return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page,
|
|
|
|
len, offs, GFP_NOFS);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
|
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_initialize() - allocate major buffers for fs encryption.
|
2016-12-07 06:53:57 +08:00
|
|
|
* @cop_flags: fscrypt operations flags
|
2015-05-16 07:26:10 +08:00
|
|
|
*
|
|
|
|
* We only call this when we start accessing encrypted files, since it
|
|
|
|
* results in memory getting allocated that wouldn't otherwise be used.
|
|
|
|
*
|
2019-10-10 07:34:17 +08:00
|
|
|
* Return: 0 on success; -errno on failure
|
2015-05-16 07:26:10 +08:00
|
|
|
*/
|
2016-12-07 06:53:57 +08:00
|
|
|
int fscrypt_initialize(unsigned int cop_flags)
|
2015-05-16 07:26:10 +08:00
|
|
|
{
|
2019-10-10 07:34:17 +08:00
|
|
|
int err = 0;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2017-10-29 18:30:19 +08:00
|
|
|
/* No need to allocate a bounce page pool if this FS won't use it. */
|
|
|
|
if (cop_flags & FS_CFLG_OWN_PAGES)
|
2015-05-16 07:26:10 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
mutex_lock(&fscrypt_init_mutex);
|
|
|
|
if (fscrypt_bounce_page_pool)
|
2019-10-10 07:34:17 +08:00
|
|
|
goto out_unlock;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-10-10 07:34:17 +08:00
|
|
|
err = -ENOMEM;
|
2015-05-16 07:26:10 +08:00
|
|
|
fscrypt_bounce_page_pool =
|
|
|
|
mempool_create_page_pool(num_prealloc_crypto_pages, 0);
|
|
|
|
if (!fscrypt_bounce_page_pool)
|
2019-10-10 07:34:17 +08:00
|
|
|
goto out_unlock;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
2019-10-10 07:34:17 +08:00
|
|
|
err = 0;
|
|
|
|
out_unlock:
|
2015-05-16 07:26:10 +08:00
|
|
|
mutex_unlock(&fscrypt_init_mutex);
|
2019-10-10 07:34:17 +08:00
|
|
|
return err;
|
2015-05-16 07:26:10 +08:00
|
|
|
}
|
|
|
|
|
2019-07-25 02:07:58 +08:00
|
|
|
void fscrypt_msg(const struct inode *inode, const char *level,
|
2018-05-01 06:51:47 +08:00
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
|
|
|
|
DEFAULT_RATELIMIT_BURST);
|
|
|
|
struct va_format vaf;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (!__ratelimit(&rs))
|
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vaf.fmt = fmt;
|
|
|
|
vaf.va = &args;
|
2019-07-25 02:07:58 +08:00
|
|
|
if (inode)
|
|
|
|
printk("%sfscrypt (%s, inode %lu): %pV\n",
|
|
|
|
level, inode->i_sb->s_id, inode->i_ino, &vaf);
|
2018-05-01 06:51:47 +08:00
|
|
|
else
|
|
|
|
printk("%sfscrypt: %pV\n", level, &vaf);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
/**
|
|
|
|
* fscrypt_init() - Set up for fs encryption.
|
2020-05-12 03:13:56 +08:00
|
|
|
*
|
|
|
|
* Return: 0 on success; -errno on failure
|
2015-05-16 07:26:10 +08:00
|
|
|
*/
|
|
|
|
static int __init fscrypt_init(void)
|
|
|
|
{
|
fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl
Add a new fscrypt ioctl, FS_IOC_ADD_ENCRYPTION_KEY. This ioctl adds an
encryption key to the filesystem's fscrypt keyring ->s_master_keys,
making any files encrypted with that key appear "unlocked".
Why we need this
~~~~~~~~~~~~~~~~
The main problem is that the "locked/unlocked" (ciphertext/plaintext)
status of encrypted files is global, but the fscrypt keys are not.
fscrypt only looks for keys in the keyring(s) the process accessing the
filesystem is subscribed to: the thread keyring, process keyring, and
session keyring, where the session keyring may contain the user keyring.
Therefore, userspace has to put fscrypt keys in the keyrings for
individual users or sessions. But this means that when a process with a
different keyring tries to access encrypted files, whether they appear
"unlocked" or not is nondeterministic. This is because it depends on
whether the files are currently present in the inode cache.
Fixing this by consistently providing each process its own view of the
filesystem depending on whether it has the key or not isn't feasible due
to how the VFS caches work. Furthermore, while sometimes users expect
this behavior, it is misguided for two reasons. First, it would be an
OS-level access control mechanism largely redundant with existing access
control mechanisms such as UNIX file permissions, ACLs, LSMs, etc.
Encryption is actually for protecting the data at rest.
Second, almost all users of fscrypt actually do need the keys to be
global. The largest users of fscrypt, Android and Chromium OS, achieve
this by having PID 1 create a "session keyring" that is inherited by
every process. This works, but it isn't scalable because it prevents
session keyrings from being used for any other purpose.
On general-purpose Linux distros, the 'fscrypt' userspace tool [1] can't
similarly abuse the session keyring, so to make 'sudo' work on all
systems it has to link all the user keyrings into root's user keyring
[2]. This is ugly and raises security concerns. Moreover it can't make
the keys available to system services, such as sshd trying to access the
user's '~/.ssh' directory (see [3], [4]) or NetworkManager trying to
read certificates from the user's home directory (see [5]); or to Docker
containers (see [6], [7]).
By having an API to add a key to the *filesystem* we'll be able to fix
the above bugs, remove userspace workarounds, and clearly express the
intended semantics: the locked/unlocked status of an encrypted directory
is global, and encryption is orthogonal to OS-level access control.
Why not use the add_key() syscall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use an ioctl for this API rather than the existing add_key() system
call because the ioctl gives us the flexibility needed to implement
fscrypt-specific semantics that will be introduced in later patches:
- Supporting key removal with the semantics such that the secret is
removed immediately and any unused inodes using the key are evicted;
also, the eviction of any in-use inodes can be retried.
- Calculating a key-dependent cryptographic identifier and returning it
to userspace.
- Allowing keys to be added and removed by non-root users, but only keys
for v2 encryption policies; and to prevent denial-of-service attacks,
users can only remove keys they themselves have added, and a key is
only really removed after all users who added it have removed it.
Trying to shoehorn these semantics into the keyrings syscalls would be
very difficult, whereas the ioctls make things much easier.
However, to reuse code the implementation still uses the keyrings
service internally. Thus we get lockless RCU-mode key lookups without
having to re-implement it, and the keys automatically show up in
/proc/keys for debugging purposes.
References:
[1] https://github.com/google/fscrypt
[2] https://goo.gl/55cCrI#heading=h.vf09isp98isb
[3] https://github.com/google/fscrypt/issues/111#issuecomment-444347939
[4] https://github.com/google/fscrypt/issues/116
[5] https://bugs.launchpad.net/ubuntu/+source/fscrypt/+bug/1770715
[6] https://github.com/google/fscrypt/issues/128
[7] https://askubuntu.com/questions/1130306/cannot-run-docker-on-an-encrypted-filesystem
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-08-05 10:35:46 +08:00
|
|
|
int err = -ENOMEM;
|
|
|
|
|
fscrypt: use unbound workqueue for decryption
Improve fscrypt read performance by switching the decryption workqueue
from bound to unbound. With the bound workqueue, when multiple bios
completed on the same CPU, they were decrypted on that same CPU. But
with the unbound queue, they are now decrypted in parallel on any CPU.
Although fscrypt read performance can be tough to measure due to the
many sources of variation, this change is most beneficial when
decryption is slow, e.g. on CPUs without AES instructions. For example,
I timed tarring up encrypted directories on f2fs. On x86 with AES-NI
instructions disabled, the unbound workqueue improved performance by
about 25-35%, using 1 to NUM_CPUs jobs with 4 or 8 CPUs available. But
with AES-NI enabled, performance was unchanged to within ~2%.
I also did the same test on a quad-core ARM CPU using xts-speck128-neon
encryption. There performance was usually about 10% better with the
unbound workqueue, bringing it closer to the unencrypted speed.
The unbound workqueue may be worse in some cases due to worse locality,
but I think it's still the better default. dm-crypt uses an unbound
workqueue by default too, so this change makes fscrypt match.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2018-04-21 07:30:02 +08:00
|
|
|
/*
|
|
|
|
* Use an unbound workqueue to allow bios to be decrypted in parallel
|
|
|
|
* even when they happen to complete on the same CPU. This sacrifices
|
|
|
|
* locality, but it's worthwhile since decryption is CPU-intensive.
|
|
|
|
*
|
|
|
|
* Also use a high-priority workqueue to prioritize decryption work,
|
|
|
|
* which blocks reads from completing, over regular application tasks.
|
|
|
|
*/
|
2015-05-16 07:26:10 +08:00
|
|
|
fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
|
fscrypt: use unbound workqueue for decryption
Improve fscrypt read performance by switching the decryption workqueue
from bound to unbound. With the bound workqueue, when multiple bios
completed on the same CPU, they were decrypted on that same CPU. But
with the unbound queue, they are now decrypted in parallel on any CPU.
Although fscrypt read performance can be tough to measure due to the
many sources of variation, this change is most beneficial when
decryption is slow, e.g. on CPUs without AES instructions. For example,
I timed tarring up encrypted directories on f2fs. On x86 with AES-NI
instructions disabled, the unbound workqueue improved performance by
about 25-35%, using 1 to NUM_CPUs jobs with 4 or 8 CPUs available. But
with AES-NI enabled, performance was unchanged to within ~2%.
I also did the same test on a quad-core ARM CPU using xts-speck128-neon
encryption. There performance was usually about 10% better with the
unbound workqueue, bringing it closer to the unencrypted speed.
The unbound workqueue may be worse in some cases due to worse locality,
but I think it's still the better default. dm-crypt uses an unbound
workqueue by default too, so this change makes fscrypt match.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2018-04-21 07:30:02 +08:00
|
|
|
WQ_UNBOUND | WQ_HIGHPRI,
|
|
|
|
num_online_cpus());
|
2015-05-16 07:26:10 +08:00
|
|
|
if (!fscrypt_read_workqueue)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
fscrypt_info_cachep = KMEM_CACHE(fscrypt_info, SLAB_RECLAIM_ACCOUNT);
|
|
|
|
if (!fscrypt_info_cachep)
|
2019-10-10 07:34:17 +08:00
|
|
|
goto fail_free_queue;
|
2015-05-16 07:26:10 +08:00
|
|
|
|
fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl
Add a new fscrypt ioctl, FS_IOC_ADD_ENCRYPTION_KEY. This ioctl adds an
encryption key to the filesystem's fscrypt keyring ->s_master_keys,
making any files encrypted with that key appear "unlocked".
Why we need this
~~~~~~~~~~~~~~~~
The main problem is that the "locked/unlocked" (ciphertext/plaintext)
status of encrypted files is global, but the fscrypt keys are not.
fscrypt only looks for keys in the keyring(s) the process accessing the
filesystem is subscribed to: the thread keyring, process keyring, and
session keyring, where the session keyring may contain the user keyring.
Therefore, userspace has to put fscrypt keys in the keyrings for
individual users or sessions. But this means that when a process with a
different keyring tries to access encrypted files, whether they appear
"unlocked" or not is nondeterministic. This is because it depends on
whether the files are currently present in the inode cache.
Fixing this by consistently providing each process its own view of the
filesystem depending on whether it has the key or not isn't feasible due
to how the VFS caches work. Furthermore, while sometimes users expect
this behavior, it is misguided for two reasons. First, it would be an
OS-level access control mechanism largely redundant with existing access
control mechanisms such as UNIX file permissions, ACLs, LSMs, etc.
Encryption is actually for protecting the data at rest.
Second, almost all users of fscrypt actually do need the keys to be
global. The largest users of fscrypt, Android and Chromium OS, achieve
this by having PID 1 create a "session keyring" that is inherited by
every process. This works, but it isn't scalable because it prevents
session keyrings from being used for any other purpose.
On general-purpose Linux distros, the 'fscrypt' userspace tool [1] can't
similarly abuse the session keyring, so to make 'sudo' work on all
systems it has to link all the user keyrings into root's user keyring
[2]. This is ugly and raises security concerns. Moreover it can't make
the keys available to system services, such as sshd trying to access the
user's '~/.ssh' directory (see [3], [4]) or NetworkManager trying to
read certificates from the user's home directory (see [5]); or to Docker
containers (see [6], [7]).
By having an API to add a key to the *filesystem* we'll be able to fix
the above bugs, remove userspace workarounds, and clearly express the
intended semantics: the locked/unlocked status of an encrypted directory
is global, and encryption is orthogonal to OS-level access control.
Why not use the add_key() syscall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use an ioctl for this API rather than the existing add_key() system
call because the ioctl gives us the flexibility needed to implement
fscrypt-specific semantics that will be introduced in later patches:
- Supporting key removal with the semantics such that the secret is
removed immediately and any unused inodes using the key are evicted;
also, the eviction of any in-use inodes can be retried.
- Calculating a key-dependent cryptographic identifier and returning it
to userspace.
- Allowing keys to be added and removed by non-root users, but only keys
for v2 encryption policies; and to prevent denial-of-service attacks,
users can only remove keys they themselves have added, and a key is
only really removed after all users who added it have removed it.
Trying to shoehorn these semantics into the keyrings syscalls would be
very difficult, whereas the ioctls make things much easier.
However, to reuse code the implementation still uses the keyrings
service internally. Thus we get lockless RCU-mode key lookups without
having to re-implement it, and the keys automatically show up in
/proc/keys for debugging purposes.
References:
[1] https://github.com/google/fscrypt
[2] https://goo.gl/55cCrI#heading=h.vf09isp98isb
[3] https://github.com/google/fscrypt/issues/111#issuecomment-444347939
[4] https://github.com/google/fscrypt/issues/116
[5] https://bugs.launchpad.net/ubuntu/+source/fscrypt/+bug/1770715
[6] https://github.com/google/fscrypt/issues/128
[7] https://askubuntu.com/questions/1130306/cannot-run-docker-on-an-encrypted-filesystem
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-08-05 10:35:46 +08:00
|
|
|
err = fscrypt_init_keyring();
|
|
|
|
if (err)
|
|
|
|
goto fail_free_info;
|
|
|
|
|
2015-05-16 07:26:10 +08:00
|
|
|
return 0;
|
|
|
|
|
fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl
Add a new fscrypt ioctl, FS_IOC_ADD_ENCRYPTION_KEY. This ioctl adds an
encryption key to the filesystem's fscrypt keyring ->s_master_keys,
making any files encrypted with that key appear "unlocked".
Why we need this
~~~~~~~~~~~~~~~~
The main problem is that the "locked/unlocked" (ciphertext/plaintext)
status of encrypted files is global, but the fscrypt keys are not.
fscrypt only looks for keys in the keyring(s) the process accessing the
filesystem is subscribed to: the thread keyring, process keyring, and
session keyring, where the session keyring may contain the user keyring.
Therefore, userspace has to put fscrypt keys in the keyrings for
individual users or sessions. But this means that when a process with a
different keyring tries to access encrypted files, whether they appear
"unlocked" or not is nondeterministic. This is because it depends on
whether the files are currently present in the inode cache.
Fixing this by consistently providing each process its own view of the
filesystem depending on whether it has the key or not isn't feasible due
to how the VFS caches work. Furthermore, while sometimes users expect
this behavior, it is misguided for two reasons. First, it would be an
OS-level access control mechanism largely redundant with existing access
control mechanisms such as UNIX file permissions, ACLs, LSMs, etc.
Encryption is actually for protecting the data at rest.
Second, almost all users of fscrypt actually do need the keys to be
global. The largest users of fscrypt, Android and Chromium OS, achieve
this by having PID 1 create a "session keyring" that is inherited by
every process. This works, but it isn't scalable because it prevents
session keyrings from being used for any other purpose.
On general-purpose Linux distros, the 'fscrypt' userspace tool [1] can't
similarly abuse the session keyring, so to make 'sudo' work on all
systems it has to link all the user keyrings into root's user keyring
[2]. This is ugly and raises security concerns. Moreover it can't make
the keys available to system services, such as sshd trying to access the
user's '~/.ssh' directory (see [3], [4]) or NetworkManager trying to
read certificates from the user's home directory (see [5]); or to Docker
containers (see [6], [7]).
By having an API to add a key to the *filesystem* we'll be able to fix
the above bugs, remove userspace workarounds, and clearly express the
intended semantics: the locked/unlocked status of an encrypted directory
is global, and encryption is orthogonal to OS-level access control.
Why not use the add_key() syscall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use an ioctl for this API rather than the existing add_key() system
call because the ioctl gives us the flexibility needed to implement
fscrypt-specific semantics that will be introduced in later patches:
- Supporting key removal with the semantics such that the secret is
removed immediately and any unused inodes using the key are evicted;
also, the eviction of any in-use inodes can be retried.
- Calculating a key-dependent cryptographic identifier and returning it
to userspace.
- Allowing keys to be added and removed by non-root users, but only keys
for v2 encryption policies; and to prevent denial-of-service attacks,
users can only remove keys they themselves have added, and a key is
only really removed after all users who added it have removed it.
Trying to shoehorn these semantics into the keyrings syscalls would be
very difficult, whereas the ioctls make things much easier.
However, to reuse code the implementation still uses the keyrings
service internally. Thus we get lockless RCU-mode key lookups without
having to re-implement it, and the keys automatically show up in
/proc/keys for debugging purposes.
References:
[1] https://github.com/google/fscrypt
[2] https://goo.gl/55cCrI#heading=h.vf09isp98isb
[3] https://github.com/google/fscrypt/issues/111#issuecomment-444347939
[4] https://github.com/google/fscrypt/issues/116
[5] https://bugs.launchpad.net/ubuntu/+source/fscrypt/+bug/1770715
[6] https://github.com/google/fscrypt/issues/128
[7] https://askubuntu.com/questions/1130306/cannot-run-docker-on-an-encrypted-filesystem
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-08-05 10:35:46 +08:00
|
|
|
fail_free_info:
|
|
|
|
kmem_cache_destroy(fscrypt_info_cachep);
|
2015-05-16 07:26:10 +08:00
|
|
|
fail_free_queue:
|
|
|
|
destroy_workqueue(fscrypt_read_workqueue);
|
|
|
|
fail:
|
fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl
Add a new fscrypt ioctl, FS_IOC_ADD_ENCRYPTION_KEY. This ioctl adds an
encryption key to the filesystem's fscrypt keyring ->s_master_keys,
making any files encrypted with that key appear "unlocked".
Why we need this
~~~~~~~~~~~~~~~~
The main problem is that the "locked/unlocked" (ciphertext/plaintext)
status of encrypted files is global, but the fscrypt keys are not.
fscrypt only looks for keys in the keyring(s) the process accessing the
filesystem is subscribed to: the thread keyring, process keyring, and
session keyring, where the session keyring may contain the user keyring.
Therefore, userspace has to put fscrypt keys in the keyrings for
individual users or sessions. But this means that when a process with a
different keyring tries to access encrypted files, whether they appear
"unlocked" or not is nondeterministic. This is because it depends on
whether the files are currently present in the inode cache.
Fixing this by consistently providing each process its own view of the
filesystem depending on whether it has the key or not isn't feasible due
to how the VFS caches work. Furthermore, while sometimes users expect
this behavior, it is misguided for two reasons. First, it would be an
OS-level access control mechanism largely redundant with existing access
control mechanisms such as UNIX file permissions, ACLs, LSMs, etc.
Encryption is actually for protecting the data at rest.
Second, almost all users of fscrypt actually do need the keys to be
global. The largest users of fscrypt, Android and Chromium OS, achieve
this by having PID 1 create a "session keyring" that is inherited by
every process. This works, but it isn't scalable because it prevents
session keyrings from being used for any other purpose.
On general-purpose Linux distros, the 'fscrypt' userspace tool [1] can't
similarly abuse the session keyring, so to make 'sudo' work on all
systems it has to link all the user keyrings into root's user keyring
[2]. This is ugly and raises security concerns. Moreover it can't make
the keys available to system services, such as sshd trying to access the
user's '~/.ssh' directory (see [3], [4]) or NetworkManager trying to
read certificates from the user's home directory (see [5]); or to Docker
containers (see [6], [7]).
By having an API to add a key to the *filesystem* we'll be able to fix
the above bugs, remove userspace workarounds, and clearly express the
intended semantics: the locked/unlocked status of an encrypted directory
is global, and encryption is orthogonal to OS-level access control.
Why not use the add_key() syscall
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We use an ioctl for this API rather than the existing add_key() system
call because the ioctl gives us the flexibility needed to implement
fscrypt-specific semantics that will be introduced in later patches:
- Supporting key removal with the semantics such that the secret is
removed immediately and any unused inodes using the key are evicted;
also, the eviction of any in-use inodes can be retried.
- Calculating a key-dependent cryptographic identifier and returning it
to userspace.
- Allowing keys to be added and removed by non-root users, but only keys
for v2 encryption policies; and to prevent denial-of-service attacks,
users can only remove keys they themselves have added, and a key is
only really removed after all users who added it have removed it.
Trying to shoehorn these semantics into the keyrings syscalls would be
very difficult, whereas the ioctls make things much easier.
However, to reuse code the implementation still uses the keyrings
service internally. Thus we get lockless RCU-mode key lookups without
having to re-implement it, and the keys automatically show up in
/proc/keys for debugging purposes.
References:
[1] https://github.com/google/fscrypt
[2] https://goo.gl/55cCrI#heading=h.vf09isp98isb
[3] https://github.com/google/fscrypt/issues/111#issuecomment-444347939
[4] https://github.com/google/fscrypt/issues/116
[5] https://bugs.launchpad.net/ubuntu/+source/fscrypt/+bug/1770715
[6] https://github.com/google/fscrypt/issues/128
[7] https://askubuntu.com/questions/1130306/cannot-run-docker-on-an-encrypted-filesystem
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-08-05 10:35:46 +08:00
|
|
|
return err;
|
2015-05-16 07:26:10 +08:00
|
|
|
}
|
2019-07-25 02:07:57 +08:00
|
|
|
late_initcall(fscrypt_init)
|