mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
fscrypt updates for 6.17
Simplify how fscrypt uses the crypto API, resulting in some significant performance improvements: - Drop the incomplete and problematic support for asynchronous algorithms. These drivers are bug-prone, and it turns out they are actually much slower than the CPU-based code as well. - Allocate crypto requests on the stack instead of the heap. This improves encryption and decryption performance, especially for filenames. It also eliminates a point of failure during I/O. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQSacvsUNc7UX4ntmEPzXCl4vpKOKwUCaIZ+fhQcZWJpZ2dlcnNA a2VybmVsLm9yZwAKCRDzXCl4vpKOK+dkAQDrHUTj9dGZI/cQ/TjP0kmOv9XfYAfj HOQDRikTX+Ip4QEA6L8FS8lJYf9EMznTvTPOkP7hXpwqzuf00vJWr+ySmQs= =N9vo -----END PGP SIGNATURE----- Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux Pull fscrypt updates from Eric Biggers: "Simplify how fscrypt uses the crypto API, resulting in some significant performance improvements: - Drop the incomplete and problematic support for asynchronous algorithms. These drivers are bug-prone, and it turns out they are actually much slower than the CPU-based code as well. - Allocate crypto requests on the stack instead of the heap. This improves encryption and decryption performance, especially for filenames. This also eliminates a point of failure during I/O" * tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/linux: ceph: Remove gfp_t argument from ceph_fscrypt_encrypt_*() fscrypt: Remove gfp_t argument from fscrypt_encrypt_block_inplace() fscrypt: Remove gfp_t argument from fscrypt_crypt_data_unit() fscrypt: Switch to sync_skcipher and on-stack requests fscrypt: Drop FORBID_WEAK_KEYS flag for AES-ECB fscrypt: Don't use asynchronous CryptoAPI algorithms fscrypt: Don't use problematic non-inline crypto engines fscrypt: Drop obsolete recommendation to enable optimized SHA-512 fscrypt: Explicitly include <linux/export.h>
This commit is contained in:
commit
283564a433
18 changed files with 145 additions and 181 deletions
|
@ -147,9 +147,8 @@ However, these ioctls have some limitations:
|
|||
were wiped. To partially solve this, you can add init_on_free=1 to
|
||||
your kernel command line. However, this has a performance cost.
|
||||
|
||||
- Secret keys might still exist in CPU registers, in crypto
|
||||
accelerator hardware (if used by the crypto API to implement any of
|
||||
the algorithms), or in other places not explicitly considered here.
|
||||
- Secret keys might still exist in CPU registers or in other places
|
||||
not explicitly considered here.
|
||||
|
||||
Full system compromise
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -406,9 +405,12 @@ the work is done by XChaCha12, which is much faster than AES when AES
|
|||
acceleration is unavailable. For more information about Adiantum, see
|
||||
`the Adiantum paper <https://eprint.iacr.org/2018/720.pdf>`_.
|
||||
|
||||
The (AES-128-CBC-ESSIV, AES-128-CBC-CTS) pair exists only to support
|
||||
systems whose only form of AES acceleration is an off-CPU crypto
|
||||
accelerator such as CAAM or CESA that does not support XTS.
|
||||
The (AES-128-CBC-ESSIV, AES-128-CBC-CTS) pair was added to try to
|
||||
provide a more efficient option for systems that lack AES instructions
|
||||
in the CPU but do have a non-inline crypto engine such as CAAM or CESA
|
||||
that supports AES-CBC (and not AES-XTS). This is deprecated. It has
|
||||
been shown that just doing AES on the CPU is actually faster.
|
||||
Moreover, Adiantum is faster still and is recommended on such systems.
|
||||
|
||||
The remaining mode pairs are the "national pride ciphers":
|
||||
|
||||
|
@ -468,14 +470,6 @@ API, but the filenames mode still does.
|
|||
- Recommended:
|
||||
- AES-CBC acceleration
|
||||
|
||||
fscrypt also uses HMAC-SHA512 for key derivation, so enabling SHA-512
|
||||
acceleration is recommended:
|
||||
|
||||
- SHA-512
|
||||
- Recommended:
|
||||
- arm64: CONFIG_CRYPTO_SHA512_ARM64_CE
|
||||
- x86: CONFIG_CRYPTO_SHA512_SSSE3
|
||||
|
||||
Contents encryption
|
||||
-------------------
|
||||
|
||||
|
@ -1326,22 +1320,13 @@ this by validating all top-level encryption policies prior to access.
|
|||
Inline encryption support
|
||||
=========================
|
||||
|
||||
By default, fscrypt uses the kernel crypto API for all cryptographic
|
||||
operations (other than HKDF, which fscrypt partially implements
|
||||
itself). The kernel crypto API supports hardware crypto accelerators,
|
||||
but only ones that work in the traditional way where all inputs and
|
||||
outputs (e.g. plaintexts and ciphertexts) are in memory. fscrypt can
|
||||
take advantage of such hardware, but the traditional acceleration
|
||||
model isn't particularly efficient and fscrypt hasn't been optimized
|
||||
for it.
|
||||
|
||||
Instead, many newer systems (especially mobile SoCs) have *inline
|
||||
encryption hardware* that can encrypt/decrypt data while it is on its
|
||||
way to/from the storage device. Linux supports inline encryption
|
||||
through a set of extensions to the block layer called *blk-crypto*.
|
||||
blk-crypto allows filesystems to attach encryption contexts to bios
|
||||
(I/O requests) to specify how the data will be encrypted or decrypted
|
||||
in-line. For more information about blk-crypto, see
|
||||
Many newer systems (especially mobile SoCs) have *inline encryption
|
||||
hardware* that can encrypt/decrypt data while it is on its way to/from
|
||||
the storage device. Linux supports inline encryption through a set of
|
||||
extensions to the block layer called *blk-crypto*. blk-crypto allows
|
||||
filesystems to attach encryption contexts to bios (I/O requests) to
|
||||
specify how the data will be encrypted or decrypted in-line. For more
|
||||
information about blk-crypto, see
|
||||
:ref:`Documentation/block/inline-encryption.rst <inline_encryption>`.
|
||||
|
||||
On supported filesystems (currently ext4 and f2fs), fscrypt can use
|
||||
|
|
|
@ -488,15 +488,13 @@ int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
|
|||
|
||||
int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
|
||||
struct page *page, unsigned int len,
|
||||
unsigned int offs, u64 lblk_num,
|
||||
gfp_t gfp_flags)
|
||||
unsigned int offs, u64 lblk_num)
|
||||
{
|
||||
struct ceph_client *cl = ceph_inode_to_client(inode);
|
||||
|
||||
doutc(cl, "%p %llx.%llx len %u offs %u blk %llu\n", inode,
|
||||
ceph_vinop(inode), len, offs, lblk_num);
|
||||
return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num,
|
||||
gfp_flags);
|
||||
return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -614,9 +612,8 @@ int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
|
|||
* @page: pointer to page array
|
||||
* @off: offset into the file that the data starts
|
||||
* @len: max length to encrypt
|
||||
* @gfp: gfp flags to use for allocation
|
||||
*
|
||||
* Decrypt an array of cleartext pages and return the amount of
|
||||
* Encrypt an array of cleartext pages and return the amount of
|
||||
* data encrypted. Any data in the page prior to the start of the
|
||||
* first complete block in the read is ignored. Any incomplete
|
||||
* crypto blocks at the end of the array are ignored.
|
||||
|
@ -624,7 +621,7 @@ int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
|
|||
* Returns the length of the encrypted data or a negative errno.
|
||||
*/
|
||||
int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
|
||||
int len, gfp_t gfp)
|
||||
int len)
|
||||
{
|
||||
int i, num_blocks;
|
||||
u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT;
|
||||
|
@ -645,7 +642,7 @@ int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
|
|||
|
||||
fret = ceph_fscrypt_encrypt_block_inplace(inode, page[pgidx],
|
||||
CEPH_FSCRYPT_BLOCK_SIZE, pgoffs,
|
||||
baseblk + i, gfp);
|
||||
baseblk + i);
|
||||
if (fret < 0) {
|
||||
if (ret == 0)
|
||||
ret = fret;
|
||||
|
|
|
@ -152,15 +152,14 @@ int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
|
|||
unsigned int offs, u64 lblk_num);
|
||||
int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
|
||||
struct page *page, unsigned int len,
|
||||
unsigned int offs, u64 lblk_num,
|
||||
gfp_t gfp_flags);
|
||||
unsigned int offs, u64 lblk_num);
|
||||
int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page,
|
||||
u64 off, int len);
|
||||
int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
|
||||
u64 off, struct ceph_sparse_extent *map,
|
||||
u32 ext_cnt);
|
||||
int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
|
||||
int len, gfp_t gfp);
|
||||
int len);
|
||||
|
||||
static inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
|
||||
{
|
||||
|
@ -236,8 +235,7 @@ static inline int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
|
|||
|
||||
static inline int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
|
||||
struct page *page, unsigned int len,
|
||||
unsigned int offs, u64 lblk_num,
|
||||
gfp_t gfp_flags)
|
||||
unsigned int offs, u64 lblk_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -259,7 +257,7 @@ static inline int ceph_fscrypt_decrypt_extents(struct inode *inode,
|
|||
|
||||
static inline int ceph_fscrypt_encrypt_pages(struct inode *inode,
|
||||
struct page **page, u64 off,
|
||||
int len, gfp_t gfp)
|
||||
int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1992,8 +1992,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
|
|||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
ret = ceph_fscrypt_encrypt_pages(inode, pages,
|
||||
write_pos, write_len,
|
||||
GFP_KERNEL);
|
||||
write_pos, write_len);
|
||||
if (ret < 0) {
|
||||
doutc(cl, "encryption failed with %d\n", ret);
|
||||
ceph_release_page_vector(pages, num_pages);
|
||||
|
|
|
@ -2436,8 +2436,7 @@ static int fill_fscrypt_truncate(struct inode *inode,
|
|||
/* encrypt the last block */
|
||||
ret = ceph_fscrypt_encrypt_block_inplace(inode, page,
|
||||
CEPH_FSCRYPT_BLOCK_SIZE,
|
||||
0, block,
|
||||
GFP_KERNEL);
|
||||
0, block);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
* Copyright (C) 2015, Motorola Mobility
|
||||
*/
|
||||
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
|
@ -165,8 +167,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
|||
do {
|
||||
err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, du_index,
|
||||
ZERO_PAGE(0), pages[i],
|
||||
du_size, offset,
|
||||
GFP_NOFS);
|
||||
du_size, offset);
|
||||
if (err)
|
||||
goto out;
|
||||
du_index++;
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
* Special Publication 800-38E and IEEE P1619/D16.
|
||||
*/
|
||||
|
||||
#include <linux/pagemap.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
static unsigned int num_prealloc_crypto_pages = 32;
|
||||
|
@ -108,15 +110,13 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 index,
|
|||
int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
||||
fscrypt_direction_t rw, u64 index,
|
||||
struct page *src_page, struct page *dest_page,
|
||||
unsigned int len, unsigned int offs,
|
||||
gfp_t gfp_flags)
|
||||
unsigned int len, unsigned int offs)
|
||||
{
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
union fscrypt_iv iv;
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist dst, src;
|
||||
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
int res = 0;
|
||||
int err;
|
||||
|
||||
if (WARN_ON_ONCE(len <= 0))
|
||||
return -EINVAL;
|
||||
|
@ -125,31 +125,23 @@ int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
|||
|
||||
fscrypt_generate_iv(&iv, index, ci);
|
||||
|
||||
req = skcipher_request_alloc(tfm, gfp_flags);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
|
||||
NULL, NULL);
|
||||
sg_init_table(&dst, 1);
|
||||
sg_set_page(&dst, dest_page, len, offs);
|
||||
sg_init_table(&src, 1);
|
||||
sg_set_page(&src, src_page, len, offs);
|
||||
skcipher_request_set_crypt(req, &src, &dst, len, &iv);
|
||||
if (rw == FS_DECRYPT)
|
||||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
err = crypto_skcipher_decrypt(req);
|
||||
else
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res) {
|
||||
err = crypto_skcipher_encrypt(req);
|
||||
if (err)
|
||||
fscrypt_err(ci->ci_inode,
|
||||
"%scryption failed for data unit %llu: %d",
|
||||
(rw == FS_DECRYPT ? "De" : "En"), index, res);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
(rw == FS_DECRYPT ? "De" : "En"), index, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,7 +196,7 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
|
|||
for (i = offs; i < offs + len; i += du_size, index++) {
|
||||
err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, index,
|
||||
&folio->page, ciphertext_page,
|
||||
du_size, i, gfp_flags);
|
||||
du_size, i);
|
||||
if (err) {
|
||||
fscrypt_free_bounce_page(ciphertext_page);
|
||||
return ERR_PTR(err);
|
||||
|
@ -225,7 +217,6 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
|
|||
* @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
|
||||
|
@ -237,13 +228,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks);
|
|||
*/
|
||||
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)
|
||||
u64 lblk_num)
|
||||
{
|
||||
if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
|
||||
return -EOPNOTSUPP;
|
||||
return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_ENCRYPT,
|
||||
lblk_num, page, page, len, offs,
|
||||
gfp_flags);
|
||||
lblk_num, page, page, len, offs);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
|
||||
|
||||
|
@ -283,8 +273,7 @@ int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
|
|||
struct page *page = folio_page(folio, i >> PAGE_SHIFT);
|
||||
|
||||
err = fscrypt_crypt_data_unit(ci, FS_DECRYPT, index, page,
|
||||
page, du_size, i & ~PAGE_MASK,
|
||||
GFP_NOFS);
|
||||
page, du_size, i & ~PAGE_MASK);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -317,8 +306,7 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
|
|||
if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units))
|
||||
return -EOPNOTSUPP;
|
||||
return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_DECRYPT,
|
||||
lblk_num, page, page, len, offs,
|
||||
GFP_NOFS);
|
||||
lblk_num, page, page, len, offs);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@
|
|||
* This has not yet undergone a rigorous security audit.
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha2.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/*
|
||||
|
@ -92,13 +94,12 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
|||
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
||||
u8 *out, unsigned int olen)
|
||||
{
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
union fscrypt_iv iv;
|
||||
struct scatterlist sg;
|
||||
int res;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Copy the filename to the output buffer for encrypting in-place and
|
||||
|
@ -109,28 +110,17 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
|||
memcpy(out, iname->name, iname->len);
|
||||
memset(out + iname->len, 0, olen - iname->len);
|
||||
|
||||
/* Initialize the IV */
|
||||
fscrypt_generate_iv(&iv, 0, ci);
|
||||
|
||||
/* Set up the encryption request */
|
||||
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
NULL, NULL);
|
||||
sg_init_one(&sg, out, olen);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, olen, &iv);
|
||||
|
||||
/* Do the encryption */
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
fscrypt_err(inode, "Filename encryption failed: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err = crypto_skcipher_encrypt(req);
|
||||
if (err)
|
||||
fscrypt_err(inode, "Filename encryption failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt);
|
||||
|
||||
|
@ -148,34 +138,25 @@ static int fname_decrypt(const struct inode *inode,
|
|||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm;
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
union fscrypt_iv iv;
|
||||
int res;
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
int err;
|
||||
|
||||
/* Allocate request */
|
||||
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
|
||||
/* Initialize IV */
|
||||
fscrypt_generate_iv(&iv, 0, ci);
|
||||
|
||||
/* Create decryption request */
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
NULL, NULL);
|
||||
sg_init_one(&src_sg, iname->name, iname->len);
|
||||
sg_init_one(&dst_sg, oname->name, oname->len);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv);
|
||||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
fscrypt_err(inode, "Filename decryption failed: %d", res);
|
||||
return res;
|
||||
err = crypto_skcipher_decrypt(req);
|
||||
if (err) {
|
||||
fscrypt_err(inode, "Filename decryption failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
oname->len = strnlen(oname->name, iname->len);
|
||||
|
|
|
@ -45,6 +45,24 @@
|
|||
*/
|
||||
#undef FSCRYPT_MAX_KEY_SIZE
|
||||
|
||||
/*
|
||||
* This mask is passed as the third argument to the crypto_alloc_*() functions
|
||||
* to prevent fscrypt from using the Crypto API drivers for non-inline crypto
|
||||
* engines. Those drivers have been problematic for fscrypt. fscrypt users
|
||||
* have reported hangs and even incorrect en/decryption with these drivers.
|
||||
* Since going to the driver, off CPU, and back again is really slow, such
|
||||
* drivers can be over 50 times slower than the CPU-based code for fscrypt's
|
||||
* workload. Even on platforms that lack AES instructions on the CPU, using the
|
||||
* offloads has been shown to be slower, even staying with AES. (Of course,
|
||||
* Adiantum is faster still, and is the recommended option on such platforms...)
|
||||
*
|
||||
* Note that fscrypt also supports inline crypto engines. Those don't use the
|
||||
* Crypto API and work much better than the old-style (non-inline) engines.
|
||||
*/
|
||||
#define FSCRYPT_CRYPTOAPI_MASK \
|
||||
(CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \
|
||||
CRYPTO_ALG_KERN_DRIVER_ONLY)
|
||||
|
||||
#define FSCRYPT_CONTEXT_V1 1
|
||||
#define FSCRYPT_CONTEXT_V2 2
|
||||
|
||||
|
@ -221,7 +239,7 @@ struct fscrypt_symlink_data {
|
|||
* Normally only one of the fields will be non-NULL.
|
||||
*/
|
||||
struct fscrypt_prepared_key {
|
||||
struct crypto_skcipher *tfm;
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
|
||||
struct blk_crypto_key *blk_key;
|
||||
#endif
|
||||
|
@ -319,8 +337,7 @@ int fscrypt_initialize(struct super_block *sb);
|
|||
int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci,
|
||||
fscrypt_direction_t rw, u64 index,
|
||||
struct page *src_page, struct page *dest_page,
|
||||
unsigned int len, unsigned int offs,
|
||||
gfp_t gfp_flags);
|
||||
unsigned int len, unsigned int offs);
|
||||
struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
|
||||
|
||||
void __printf(3, 4) __cold
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha2.h>
|
||||
#include <crypto/hkdf.h>
|
||||
#include <crypto/sha2.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
|
@ -58,7 +58,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
|
|||
u8 prk[HKDF_HASHLEN];
|
||||
int err;
|
||||
|
||||
hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, 0);
|
||||
hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, FSCRYPT_CRYPTOAPI_MASK);
|
||||
if (IS_ERR(hmac_tfm)) {
|
||||
fscrypt_err(NULL, "Error allocating " HKDF_HMAC_ALG ": %ld",
|
||||
PTR_ERR(hmac_tfm));
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* Encryption hooks for higher-level filesystem operations.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/blk-crypto.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uio.h>
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
* information about these ioctls.
|
||||
*/
|
||||
|
||||
#include <linux/unaligned.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/once.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
@ -96,14 +97,15 @@ select_encryption_mode(const union fscrypt_policy *policy,
|
|||
}
|
||||
|
||||
/* Create a symmetric cipher object for the given encryption mode and key */
|
||||
static struct crypto_skcipher *
|
||||
static struct crypto_sync_skcipher *
|
||||
fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
|
||||
const struct inode *inode)
|
||||
{
|
||||
struct crypto_skcipher *tfm;
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
int err;
|
||||
|
||||
tfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
|
||||
tfm = crypto_alloc_sync_skcipher(mode->cipher_str, 0,
|
||||
FSCRYPT_CRYPTOAPI_MASK);
|
||||
if (IS_ERR(tfm)) {
|
||||
if (PTR_ERR(tfm) == -ENOENT) {
|
||||
fscrypt_warn(inode,
|
||||
|
@ -123,21 +125,22 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
|
|||
* first time a mode is used.
|
||||
*/
|
||||
pr_info("fscrypt: %s using implementation \"%s\"\n",
|
||||
mode->friendly_name, crypto_skcipher_driver_name(tfm));
|
||||
mode->friendly_name,
|
||||
crypto_skcipher_driver_name(&tfm->base));
|
||||
}
|
||||
if (WARN_ON_ONCE(crypto_skcipher_ivsize(tfm) != mode->ivsize)) {
|
||||
if (WARN_ON_ONCE(crypto_sync_skcipher_ivsize(tfm) != mode->ivsize)) {
|
||||
err = -EINVAL;
|
||||
goto err_free_tfm;
|
||||
}
|
||||
crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
|
||||
err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize);
|
||||
crypto_sync_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
|
||||
err = crypto_sync_skcipher_setkey(tfm, raw_key, mode->keysize);
|
||||
if (err)
|
||||
goto err_free_tfm;
|
||||
|
||||
return tfm;
|
||||
|
||||
err_free_tfm:
|
||||
crypto_free_skcipher(tfm);
|
||||
crypto_free_sync_skcipher(tfm);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
|
@ -150,7 +153,7 @@ err_free_tfm:
|
|||
int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
|
||||
const u8 *raw_key, const struct fscrypt_inode_info *ci)
|
||||
{
|
||||
struct crypto_skcipher *tfm;
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
|
||||
if (fscrypt_using_inline_encryption(ci))
|
||||
return fscrypt_prepare_inline_crypt_key(prep_key, raw_key,
|
||||
|
@ -174,7 +177,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
|
|||
void fscrypt_destroy_prepared_key(struct super_block *sb,
|
||||
struct fscrypt_prepared_key *prep_key)
|
||||
{
|
||||
crypto_free_skcipher(prep_key->tfm);
|
||||
crypto_free_sync_skcipher(prep_key->tfm);
|
||||
fscrypt_destroy_inline_crypt_key(sb, prep_key);
|
||||
memzero_explicit(prep_key, sizeof(*prep_key));
|
||||
}
|
||||
|
|
|
@ -48,39 +48,30 @@ static int derive_key_aes(const u8 *master_key,
|
|||
const u8 nonce[FSCRYPT_FILE_NONCE_SIZE],
|
||||
u8 *derived_key, unsigned int derived_keysize)
|
||||
{
|
||||
int res = 0;
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
int err;
|
||||
|
||||
if (IS_ERR(tfm)) {
|
||||
res = PTR_ERR(tfm);
|
||||
tfm = NULL;
|
||||
goto out;
|
||||
}
|
||||
crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);
|
||||
req = skcipher_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req) {
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
res = crypto_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE);
|
||||
if (res < 0)
|
||||
goto out;
|
||||
tfm = crypto_alloc_sync_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
sg_init_one(&src_sg, master_key, derived_keysize);
|
||||
sg_init_one(&dst_sg, derived_key, derived_keysize);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, derived_keysize,
|
||||
NULL);
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
out:
|
||||
skcipher_request_free(req);
|
||||
crypto_free_skcipher(tfm);
|
||||
return res;
|
||||
err = crypto_sync_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE);
|
||||
if (err == 0) {
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
NULL, NULL);
|
||||
sg_init_one(&src_sg, master_key, derived_keysize);
|
||||
sg_init_one(&dst_sg, derived_key, derived_keysize);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg,
|
||||
derived_keysize, NULL);
|
||||
err = crypto_skcipher_encrypt(req);
|
||||
}
|
||||
crypto_free_sync_skcipher(tfm);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
* Modified by Eric Biggers, 2019 for v2 policy support.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,7 +51,7 @@ int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
|||
memset(p + in_len, 0, pad_len - in_len);
|
||||
|
||||
err = fscrypt_encrypt_block_inplace(inode, virt_to_page(p), pad_len,
|
||||
offset_in_page(p), block, GFP_NOFS);
|
||||
offset_in_page(p), block);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_encrypt_block_inplace() failed: %d", err);
|
||||
return err;
|
||||
|
|
|
@ -314,7 +314,7 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
|
|||
size_t len, size_t offs, gfp_t gfp_flags);
|
||||
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);
|
||||
u64 lblk_num);
|
||||
|
||||
int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len,
|
||||
size_t offs);
|
||||
|
@ -487,8 +487,7 @@ static inline struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio,
|
|||
static inline 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)
|
||||
unsigned int offs, u64 lblk_num)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue