Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.4.y' into android-5.4
* aosp/upstream-f2fs-stable-linux-5.4.y: fs-verity: use u64_to_user_ptr() fs-verity: use mempool for hash requests fs-verity: implement readahead of Merkle tree pages fs-verity: implement readahead for FS_IOC_ENABLE_VERITY fscrypt: improve format of no-key names ubifs: allow both hash and disk name to be provided in no-key names ubifs: don't trigger assertion on invalid no-key filename fscrypt: clarify what is meant by a per-file key fscrypt: derive dirhash key for casefolded directories fscrypt: don't allow v1 policies with casefolding fscrypt: add "fscrypt_" prefix to fname_encrypt() fscrypt: don't print name of busy file when removing key ubifs: use IS_ENCRYPTED() instead of ubifs_crypt_is_encrypted() fscrypt: document gfp_flags for bounce page allocation fscrypt: optimize fscrypt_zeroout_range() fscrypt: remove redundant bi_status check fscrypt: Allow modular crypto algorithms fscrypt: include <linux/ioctl.h> in UAPI header fscrypt: don't check for ENOKEY from fscrypt_get_encryption_info() fscrypt: remove fscrypt_is_direct_key_policy() fscrypt: move fscrypt_valid_enc_modes() to policy.c fscrypt: check for appropriate use of DIRECT_KEY flag earlier fscrypt: split up fscrypt_supported_policy() by policy version fscrypt: introduce fscrypt_needs_contents_encryption() fscrypt: move fscrypt_d_revalidate() to fname.c fscrypt: constify inode parameter to filename encryption functions fscrypt: constify struct fscrypt_hkdf parameter to fscrypt_hkdf_expand() fscrypt: verify that the crypto_skcipher has the correct ivsize fscrypt: use crypto_skcipher_driver_name() fscrypt: support passing a keyring key to FS_IOC_ADD_ENCRYPTION_KEY Conflicts: fs/crypto/Kconfig fs/crypto/bio.c fs/crypto/fname.c fs/crypto/fscrypt_private.h fs/crypto/keyring.c fs/crypto/keysetup.c fs/ubifs/dir.c include/uapi/linux/fscrypt.h Resolved the conflicts as per the corresponding android-mainline change, Ib1e6b9eda8fb5dcfc6bdc8fa89d93f72b088c5f6. Bug: 148667616 Change-Id: I5f8b846f0cd4d5403d8c61b9e12acb4581fac6f7 Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
commit
b115f51088
@ -234,8 +234,8 @@ HKDF is more flexible, is nonreversible, and evenly distributes
|
||||
entropy from the master key. HKDF is also standardized and widely
|
||||
used by other software, whereas the AES-128-ECB based KDF is ad-hoc.
|
||||
|
||||
Per-file keys
|
||||
-------------
|
||||
Per-file encryption keys
|
||||
------------------------
|
||||
|
||||
Since each master key can protect many files, it is necessary to
|
||||
"tweak" the encryption of each file so that the same plaintext in two
|
||||
@ -268,9 +268,9 @@ is greater than that of an AES-256-XTS key.
|
||||
Therefore, to improve performance and save memory, for Adiantum a
|
||||
"direct key" configuration is supported. When the user has enabled
|
||||
this by setting FSCRYPT_POLICY_FLAG_DIRECT_KEY in the fscrypt policy,
|
||||
per-file keys are not used. Instead, whenever any data (contents or
|
||||
filenames) is encrypted, the file's 16-byte nonce is included in the
|
||||
IV. Moreover:
|
||||
per-file encryption keys are not used. Instead, whenever any data
|
||||
(contents or filenames) is encrypted, the file's 16-byte nonce is
|
||||
included in the IV. Moreover:
|
||||
|
||||
- For v1 encryption policies, the encryption is done directly with the
|
||||
master key. Because of this, users **must not** use the same master
|
||||
@ -302,6 +302,16 @@ For master keys used for v2 encryption policies, a unique 16-byte "key
|
||||
identifier" is also derived using the KDF. This value is stored in
|
||||
the clear, since it is needed to reliably identify the key itself.
|
||||
|
||||
Dirhash keys
|
||||
------------
|
||||
|
||||
For directories that are indexed using a secret-keyed dirhash over the
|
||||
plaintext filenames, the KDF is also used to derive a 128-bit
|
||||
SipHash-2-4 key per directory in order to hash filenames. This works
|
||||
just like deriving a per-file encryption key, except that a different
|
||||
KDF context is used. Currently, only casefolded ("case-insensitive")
|
||||
encrypted directories use this style of hashing.
|
||||
|
||||
Encryption modes and usage
|
||||
==========================
|
||||
|
||||
@ -325,11 +335,11 @@ used.
|
||||
Adiantum is a (primarily) stream cipher-based mode that is fast even
|
||||
on CPUs without dedicated crypto instructions. It's also a true
|
||||
wide-block mode, unlike XTS. It can also eliminate the need to derive
|
||||
per-file keys. However, it depends on the security of two primitives,
|
||||
XChaCha12 and AES-256, rather than just one. See the paper
|
||||
"Adiantum: length-preserving encryption for entry-level processors"
|
||||
(https://eprint.iacr.org/2018/720.pdf) for more details. To use
|
||||
Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast
|
||||
per-file encryption keys. However, it depends on the security of two
|
||||
primitives, XChaCha12 and AES-256, rather than just one. See the
|
||||
paper "Adiantum: length-preserving encryption for entry-level
|
||||
processors" (https://eprint.iacr.org/2018/720.pdf) for more details.
|
||||
To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast
|
||||
implementations of ChaCha and NHPoly1305 should be enabled, e.g.
|
||||
CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM.
|
||||
|
||||
@ -513,7 +523,9 @@ FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors:
|
||||
- ``EEXIST``: the file is already encrypted with an encryption policy
|
||||
different from the one specified
|
||||
- ``EINVAL``: an invalid encryption policy was specified (invalid
|
||||
version, mode(s), or flags; or reserved bits were set)
|
||||
version, mode(s), or flags; or reserved bits were set); or a v1
|
||||
encryption policy was specified but the directory has the casefold
|
||||
flag enabled (casefolding is incompatible with v1 policies).
|
||||
- ``ENOKEY``: a v2 encryption policy was specified, but the key with
|
||||
the specified ``master_key_identifier`` has not been added, nor does
|
||||
the process have the CAP_FOWNER capability in the initial user
|
||||
@ -638,7 +650,8 @@ follows::
|
||||
struct fscrypt_add_key_arg {
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
__u32 raw_size;
|
||||
__u32 __reserved[9];
|
||||
__u32 key_id;
|
||||
__u32 __reserved[8];
|
||||
__u8 raw[];
|
||||
};
|
||||
|
||||
@ -655,6 +668,12 @@ follows::
|
||||
} u;
|
||||
};
|
||||
|
||||
struct fscrypt_provisioning_key_payload {
|
||||
__u32 type;
|
||||
__u32 __reserved;
|
||||
__u8 raw[];
|
||||
};
|
||||
|
||||
:c:type:`struct fscrypt_add_key_arg` must be zeroed, then initialized
|
||||
as follows:
|
||||
|
||||
@ -677,9 +696,26 @@ as follows:
|
||||
``Documentation/security/keys/core.rst``).
|
||||
|
||||
- ``raw_size`` must be the size of the ``raw`` key provided, in bytes.
|
||||
Alternatively, if ``key_id`` is nonzero, this field must be 0, since
|
||||
in that case the size is implied by the specified Linux keyring key.
|
||||
|
||||
- ``key_id`` is 0 if the raw key is given directly in the ``raw``
|
||||
field. Otherwise ``key_id`` is the ID of a Linux keyring key of
|
||||
type "fscrypt-provisioning" whose payload is a :c:type:`struct
|
||||
fscrypt_provisioning_key_payload` whose ``raw`` field contains the
|
||||
raw key and whose ``type`` field matches ``key_spec.type``. Since
|
||||
``raw`` is variable-length, the total size of this key's payload
|
||||
must be ``sizeof(struct fscrypt_provisioning_key_payload)`` plus the
|
||||
raw key size. The process must have Search permission on this key.
|
||||
|
||||
Most users should leave this 0 and specify the raw key directly.
|
||||
The support for specifying a Linux keyring key is intended mainly to
|
||||
allow re-adding keys after a filesystem is unmounted and re-mounted,
|
||||
without having to store the raw keys in userspace memory.
|
||||
|
||||
- ``raw`` is a variable-length field which must contain the actual
|
||||
key, ``raw_size`` bytes long.
|
||||
key, ``raw_size`` bytes long. Alternatively, if ``key_id`` is
|
||||
nonzero, then this field is unused.
|
||||
|
||||
For v2 policy keys, the kernel keeps track of which user (identified
|
||||
by effective user ID) added the key, and only allows the key to be
|
||||
@ -701,11 +737,16 @@ FS_IOC_ADD_ENCRYPTION_KEY can fail with the following errors:
|
||||
|
||||
- ``EACCES``: FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR was specified, but the
|
||||
caller does not have the CAP_SYS_ADMIN capability in the initial
|
||||
user namespace
|
||||
user namespace; or the raw key was specified by Linux key ID but the
|
||||
process lacks Search permission on the key.
|
||||
- ``EDQUOT``: the key quota for this user would be exceeded by adding
|
||||
the key
|
||||
- ``EINVAL``: invalid key size or key specifier type, or reserved bits
|
||||
were set
|
||||
- ``EKEYREJECTED``: the raw key was specified by Linux key ID, but the
|
||||
key has the wrong type
|
||||
- ``ENOKEY``: the raw key was specified by Linux key ID, but no key
|
||||
exists with that ID
|
||||
- ``ENOTTY``: this type of filesystem does not implement encryption
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with encryption
|
||||
support for this filesystem, or the filesystem superblock has not
|
||||
@ -1108,8 +1149,8 @@ The context structs contain the same information as the corresponding
|
||||
policy structs (see `Setting an encryption policy`_), except that the
|
||||
context structs also contain a nonce. The nonce is randomly generated
|
||||
by the kernel and is used as KDF input or as a tweak to cause
|
||||
different files to be encrypted differently; see `Per-file keys`_ and
|
||||
`DIRECT_KEY policies`_.
|
||||
different files to be encrypted differently; see `Per-file encryption
|
||||
keys`_ and `DIRECT_KEY policies`_.
|
||||
|
||||
Data path changes
|
||||
-----------------
|
||||
@ -1161,7 +1202,7 @@ filesystem-specific hash(es) needed for directory lookups. This
|
||||
allows the filesystem to still, with a high degree of confidence, map
|
||||
the filename given in ->lookup() back to a particular directory entry
|
||||
that was previously listed by readdir(). See :c:type:`struct
|
||||
fscrypt_digested_name` in the source for more details.
|
||||
fscrypt_nokey_name` in the source for more details.
|
||||
|
||||
Note that the precise way that filenames are presented to userspace
|
||||
without the key is subject to change in the future. It is only meant
|
||||
|
@ -2,13 +2,8 @@
|
||||
config FS_ENCRYPTION
|
||||
bool "FS Encryption (Per-file encryption)"
|
||||
select CRYPTO
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CBC
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_XTS
|
||||
select CRYPTO_CTS
|
||||
select CRYPTO_SHA512
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_BLKCIPHER
|
||||
select KEYS
|
||||
help
|
||||
Enable encryption of files and directories. This
|
||||
@ -17,6 +12,19 @@ config FS_ENCRYPTION
|
||||
decrypted pages in the page cache. Currently Ext4,
|
||||
F2FS and UBIFS make use of this feature.
|
||||
|
||||
# Filesystems supporting encryption must select this if FS_ENCRYPTION. This
|
||||
# allows the algorithms to be built as modules when all the filesystems are.
|
||||
config FS_ENCRYPTION_ALGS
|
||||
tristate
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CBC
|
||||
select CRYPTO_CTS
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA256
|
||||
select CRYPTO_SHA512
|
||||
select CRYPTO_XTS
|
||||
|
||||
config FS_ENCRYPTION_INLINE_CRYPT
|
||||
bool "Enable fscrypt to use inline crypto"
|
||||
depends on FS_ENCRYPTION && BLK_INLINE_ENCRYPTION
|
||||
|
183
fs/crypto/bio.c
183
fs/crypto/bio.c
@ -41,63 +41,154 @@ void fscrypt_decrypt_bio(struct bio *bio)
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_decrypt_bio);
|
||||
|
||||
int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
||||
sector_t pblk, unsigned int len)
|
||||
static int fscrypt_zeroout_range_inlinecrypt(const struct inode *inode,
|
||||
pgoff_t lblk,
|
||||
sector_t pblk, unsigned int len)
|
||||
{
|
||||
const unsigned int blockbits = inode->i_blkbits;
|
||||
const unsigned int blocksize = 1 << blockbits;
|
||||
const bool inlinecrypt = fscrypt_inode_uses_inline_crypto(inode);
|
||||
struct page *ciphertext_page;
|
||||
const unsigned int blocks_per_page_bits = PAGE_SHIFT - blockbits;
|
||||
const unsigned int blocks_per_page = 1 << blocks_per_page_bits;
|
||||
unsigned int i;
|
||||
struct bio *bio;
|
||||
int ret, err = 0;
|
||||
int ret, err;
|
||||
|
||||
if (inlinecrypt) {
|
||||
ciphertext_page = ZERO_PAGE(0);
|
||||
} else {
|
||||
ciphertext_page = fscrypt_alloc_bounce_page(GFP_NOWAIT);
|
||||
if (!ciphertext_page)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
if (!inlinecrypt) {
|
||||
err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk,
|
||||
ZERO_PAGE(0), ciphertext_page,
|
||||
blocksize, 0, GFP_NOFS);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
bio = bio_alloc(GFP_NOWAIT, 1);
|
||||
if (!bio) {
|
||||
err = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOIO);
|
||||
/* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
|
||||
bio = bio_alloc(GFP_NOFS, BIO_MAX_PAGES);
|
||||
|
||||
do {
|
||||
bio_set_dev(bio, inode->i_sb->s_bdev);
|
||||
bio->bi_iter.bi_sector = pblk << (blockbits - 9);
|
||||
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
|
||||
ret = bio_add_page(bio, ciphertext_page, blocksize, 0);
|
||||
if (WARN_ON(ret != blocksize)) {
|
||||
/* should never happen! */
|
||||
bio_put(bio);
|
||||
err = -EIO;
|
||||
goto errout;
|
||||
}
|
||||
fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS);
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
unsigned int blocks_this_page =
|
||||
min(len, blocks_per_page);
|
||||
unsigned int bytes_this_page =
|
||||
blocks_this_page << blockbits;
|
||||
|
||||
ret = bio_add_page(bio, ZERO_PAGE(0),
|
||||
bytes_this_page, 0);
|
||||
if (WARN_ON(ret != bytes_this_page)) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
lblk += blocks_this_page;
|
||||
pblk += blocks_this_page;
|
||||
len -= blocks_this_page;
|
||||
} while (++i != BIO_MAX_PAGES && len != 0);
|
||||
|
||||
err = submit_bio_wait(bio);
|
||||
if (err == 0 && bio->bi_status)
|
||||
err = -EIO;
|
||||
bio_put(bio);
|
||||
if (err)
|
||||
goto errout;
|
||||
lblk++;
|
||||
pblk++;
|
||||
}
|
||||
goto out;
|
||||
bio_reset(bio);
|
||||
} while (len != 0);
|
||||
err = 0;
|
||||
errout:
|
||||
if (!inlinecrypt)
|
||||
fscrypt_free_bounce_page(ciphertext_page);
|
||||
out:
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file
|
||||
* @inode: the file's inode
|
||||
* @lblk: the first file logical block to zero out
|
||||
* @pblk: the first filesystem physical block to zero out
|
||||
* @len: number of blocks to zero out
|
||||
*
|
||||
* Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write
|
||||
* ciphertext blocks which decrypt to the all-zeroes block. The blocks must be
|
||||
* both logically and physically contiguous. It's also assumed that the
|
||||
* filesystem only uses a single block device, ->s_bdev.
|
||||
*
|
||||
* Note that since each block uses a different IV, this involves writing a
|
||||
* different ciphertext to each block; we can't simply reuse the same one.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
||||
sector_t pblk, unsigned int len)
|
||||
{
|
||||
const unsigned int blockbits = inode->i_blkbits;
|
||||
const unsigned int blocksize = 1 << blockbits;
|
||||
const unsigned int blocks_per_page_bits = PAGE_SHIFT - blockbits;
|
||||
const unsigned int blocks_per_page = 1 << blocks_per_page_bits;
|
||||
struct page *pages[16]; /* write up to 16 pages at a time */
|
||||
unsigned int nr_pages;
|
||||
unsigned int i;
|
||||
unsigned int offset;
|
||||
struct bio *bio;
|
||||
int ret, err;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (fscrypt_inode_uses_inline_crypto(inode))
|
||||
return fscrypt_zeroout_range_inlinecrypt(inode, lblk, pblk,
|
||||
len);
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_PAGES);
|
||||
nr_pages = min_t(unsigned int, ARRAY_SIZE(pages),
|
||||
(len + blocks_per_page - 1) >> blocks_per_page_bits);
|
||||
|
||||
/*
|
||||
* We need at least one page for ciphertext. Allocate the first one
|
||||
* from a mempool, with __GFP_DIRECT_RECLAIM set so that it can't fail.
|
||||
*
|
||||
* Any additional page allocations are allowed to fail, as they only
|
||||
* help performance, and waiting on the mempool for them could deadlock.
|
||||
*/
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
pages[i] = fscrypt_alloc_bounce_page(i == 0 ? GFP_NOFS :
|
||||
GFP_NOWAIT | __GFP_NOWARN);
|
||||
if (!pages[i])
|
||||
break;
|
||||
}
|
||||
nr_pages = i;
|
||||
if (WARN_ON(nr_pages <= 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
|
||||
bio = bio_alloc(GFP_NOFS, nr_pages);
|
||||
|
||||
do {
|
||||
bio_set_dev(bio, inode->i_sb->s_bdev);
|
||||
bio->bi_iter.bi_sector = pblk << (blockbits - 9);
|
||||
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
|
||||
|
||||
i = 0;
|
||||
offset = 0;
|
||||
do {
|
||||
err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk,
|
||||
ZERO_PAGE(0), pages[i],
|
||||
blocksize, offset, GFP_NOFS);
|
||||
if (err)
|
||||
goto out;
|
||||
lblk++;
|
||||
pblk++;
|
||||
len--;
|
||||
offset += blocksize;
|
||||
if (offset == PAGE_SIZE || len == 0) {
|
||||
ret = bio_add_page(bio, pages[i++], offset, 0);
|
||||
if (WARN_ON(ret != offset)) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
offset = 0;
|
||||
}
|
||||
} while (i != nr_pages && len != 0);
|
||||
|
||||
err = submit_bio_wait(bio);
|
||||
if (err)
|
||||
goto out;
|
||||
bio_reset(bio);
|
||||
} while (len != 0);
|
||||
err = 0;
|
||||
out:
|
||||
bio_put(bio);
|
||||
for (i = 0; i < nr_pages; i++)
|
||||
fscrypt_free_bounce_page(pages[i]);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_zeroout_range);
|
||||
|
@ -25,8 +25,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/namei.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
@ -140,7 +138,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
|
||||
* 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.
|
||||
* @gfp_flags: Memory allocation flags
|
||||
* @gfp_flags: Memory allocation flags. See details below.
|
||||
*
|
||||
* 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
|
||||
@ -150,6 +148,11 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
|
||||
*
|
||||
* This is for use by the filesystem's ->writepages() method.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Return: the new encrypted bounce page on success; an ERR_PTR() on failure
|
||||
*/
|
||||
struct page *fscrypt_encrypt_pagecache_blocks(struct page *page,
|
||||
@ -286,54 +289,6 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
|
||||
|
||||
/*
|
||||
* Validate dentries in encrypted directories to make sure we aren't potentially
|
||||
* caching stale dentries after a key has been added.
|
||||
*/
|
||||
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct dentry *dir;
|
||||
int err;
|
||||
int valid;
|
||||
|
||||
/*
|
||||
* Plaintext names are always valid, since fscrypt doesn't support
|
||||
* reverting to ciphertext names without evicting the directory's inode
|
||||
* -- which implies eviction of the dentries in the directory.
|
||||
*/
|
||||
if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Ciphertext name; valid if the directory's key is still unavailable.
|
||||
*
|
||||
* Although fscrypt forbids rename() on ciphertext names, we still must
|
||||
* use dget_parent() here rather than use ->d_parent directly. That's
|
||||
* because a corrupted fs image may contain directory hard links, which
|
||||
* the VFS handles by moving the directory's dentry tree in the dcache
|
||||
* each time ->lookup() finds the directory and it already has a dentry
|
||||
* elsewhere. Thus ->d_parent can be changing, and we must safely grab
|
||||
* a reference to some ->d_parent to prevent it from being freed.
|
||||
*/
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
dir = dget_parent(dentry);
|
||||
err = fscrypt_get_encryption_info(d_inode(dir));
|
||||
valid = !fscrypt_has_encryption_key(d_inode(dir));
|
||||
dput(dir);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
const struct dentry_operations fscrypt_d_ops = {
|
||||
.d_revalidate = fscrypt_d_revalidate,
|
||||
};
|
||||
|
||||
/**
|
||||
* fscrypt_initialize() - allocate major buffers for fs encryption.
|
||||
* @cop_flags: fscrypt operations flags
|
||||
|
@ -11,10 +11,87 @@
|
||||
* This has not yet undergone a rigorous security audit.
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
* struct fscrypt_nokey_name - identifier for directory entry when key is absent
|
||||
*
|
||||
* When userspace lists an encrypted directory without access to the key, the
|
||||
* filesystem must present a unique "no-key name" for each filename that allows
|
||||
* it to find the directory entry again if requested. Naively, that would just
|
||||
* mean using the ciphertext filenames. However, since the ciphertext filenames
|
||||
* can contain illegal characters ('\0' and '/'), they must be encoded in some
|
||||
* way. We use base64. But that can cause names to exceed NAME_MAX (255
|
||||
* bytes), so we also need to use a strong hash to abbreviate long names.
|
||||
*
|
||||
* The filesystem may also need another kind of hash, the "dirhash", to quickly
|
||||
* find the directory entry. Since filesystems normally compute the dirhash
|
||||
* over the on-disk filename (i.e. the ciphertext), it's not computable from
|
||||
* no-key names that abbreviate the ciphertext using the strong hash to fit in
|
||||
* NAME_MAX. It's also not computable if it's a keyed hash taken over the
|
||||
* plaintext (but it may still be available in the on-disk directory entry);
|
||||
* casefolded directories use this type of dirhash. At least in these cases,
|
||||
* each no-key name must include the name's dirhash too.
|
||||
*
|
||||
* To meet all these requirements, we base64-encode the following
|
||||
* variable-length structure. It contains the dirhash, or 0's if the filesystem
|
||||
* didn't provide one; up to 149 bytes of the ciphertext name; and for
|
||||
* ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes.
|
||||
*
|
||||
* This ensures that each no-key name contains everything needed to find the
|
||||
* directory entry again, contains only legal characters, doesn't exceed
|
||||
* NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only
|
||||
* take the performance hit of SHA-256 on very long filenames (which are rare).
|
||||
*/
|
||||
struct fscrypt_nokey_name {
|
||||
u32 dirhash[2];
|
||||
u8 bytes[149];
|
||||
u8 sha256[SHA256_DIGEST_SIZE];
|
||||
}; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */
|
||||
|
||||
/*
|
||||
* Decoded size of max-size nokey name, i.e. a name that was abbreviated using
|
||||
* the strong hash and thus includes the 'sha256' field. This isn't simply
|
||||
* sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included.
|
||||
*/
|
||||
#define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256)
|
||||
|
||||
static struct crypto_shash *sha256_hash_tfm;
|
||||
|
||||
static int fscrypt_do_sha256(const u8 *data, unsigned int data_len, u8 *result)
|
||||
{
|
||||
struct crypto_shash *tfm = READ_ONCE(sha256_hash_tfm);
|
||||
|
||||
if (unlikely(!tfm)) {
|
||||
struct crypto_shash *prev_tfm;
|
||||
|
||||
tfm = crypto_alloc_shash("sha256", 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
fscrypt_err(NULL,
|
||||
"Error allocating SHA-256 transform: %ld",
|
||||
PTR_ERR(tfm));
|
||||
return PTR_ERR(tfm);
|
||||
}
|
||||
prev_tfm = cmpxchg(&sha256_hash_tfm, NULL, tfm);
|
||||
if (prev_tfm) {
|
||||
crypto_free_shash(tfm);
|
||||
tfm = prev_tfm;
|
||||
}
|
||||
}
|
||||
{
|
||||
SHASH_DESC_ON_STACK(desc, tfm);
|
||||
|
||||
desc->tfm = tfm;
|
||||
|
||||
return crypto_shash_digest(desc, data, data_len, result);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
{
|
||||
if (str->len == 1 && str->name[0] == '.')
|
||||
@ -27,19 +104,19 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
}
|
||||
|
||||
/**
|
||||
* fname_encrypt() - encrypt a filename
|
||||
* fscrypt_fname_encrypt() - encrypt a filename
|
||||
*
|
||||
* The output buffer must be at least as large as the input buffer.
|
||||
* Any extra space is filled with NUL padding before encryption.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
u8 *out, unsigned int olen)
|
||||
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);
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_key.tfm;
|
||||
union fscrypt_iv iv;
|
||||
struct scatterlist sg;
|
||||
@ -85,14 +162,14 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
static int fname_decrypt(struct inode *inode,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
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;
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_key.tfm;
|
||||
union fscrypt_iv iv;
|
||||
int res;
|
||||
@ -206,9 +283,7 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode,
|
||||
u32 max_encrypted_len,
|
||||
struct fscrypt_str *crypto_str)
|
||||
{
|
||||
const u32 max_encoded_len =
|
||||
max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
|
||||
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
|
||||
const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX);
|
||||
u32 max_presented_len;
|
||||
|
||||
max_presented_len = max(max_encoded_len, max_encrypted_len);
|
||||
@ -241,19 +316,21 @@ EXPORT_SYMBOL(fscrypt_fname_free_buffer);
|
||||
*
|
||||
* The caller must have allocated sufficient memory for the @oname string.
|
||||
*
|
||||
* If the key is available, we'll decrypt the disk name; otherwise, we'll encode
|
||||
* it for presentation. Short names are directly base64-encoded, while long
|
||||
* names are encoded in fscrypt_digested_name format.
|
||||
* If the key is available, we'll decrypt the disk name. Otherwise, we'll
|
||||
* encode it for presentation in fscrypt_nokey_name format.
|
||||
* See struct fscrypt_nokey_name for details.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
int fscrypt_fname_disk_to_usr(struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
int fscrypt_fname_disk_to_usr(const struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
const struct qstr qname = FSTR_TO_QSTR(iname);
|
||||
struct fscrypt_digested_name digested_name;
|
||||
struct fscrypt_nokey_name nokey_name;
|
||||
u32 size; /* size of the unencoded no-key name */
|
||||
int err;
|
||||
|
||||
if (fscrypt_is_dot_dotdot(&qname)) {
|
||||
oname->name[0] = '.';
|
||||
@ -268,24 +345,37 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
|
||||
if (fscrypt_has_encryption_key(inode))
|
||||
return fname_decrypt(inode, iname, oname);
|
||||
|
||||
if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
|
||||
oname->len = base64_encode(iname->name, iname->len,
|
||||
oname->name);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Sanity check that struct fscrypt_nokey_name doesn't have padding
|
||||
* between fields and that its encoded size never exceeds NAME_MAX.
|
||||
*/
|
||||
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, dirhash) !=
|
||||
offsetof(struct fscrypt_nokey_name, bytes));
|
||||
BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) !=
|
||||
offsetof(struct fscrypt_nokey_name, sha256));
|
||||
BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX);
|
||||
|
||||
if (hash) {
|
||||
digested_name.hash = hash;
|
||||
digested_name.minor_hash = minor_hash;
|
||||
nokey_name.dirhash[0] = hash;
|
||||
nokey_name.dirhash[1] = minor_hash;
|
||||
} else {
|
||||
digested_name.hash = 0;
|
||||
digested_name.minor_hash = 0;
|
||||
nokey_name.dirhash[0] = 0;
|
||||
nokey_name.dirhash[1] = 0;
|
||||
}
|
||||
memcpy(digested_name.digest,
|
||||
FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
|
||||
FSCRYPT_FNAME_DIGEST_SIZE);
|
||||
oname->name[0] = '_';
|
||||
oname->len = 1 + base64_encode((const u8 *)&digested_name,
|
||||
sizeof(digested_name), oname->name + 1);
|
||||
if (iname->len <= sizeof(nokey_name.bytes)) {
|
||||
memcpy(nokey_name.bytes, iname->name, iname->len);
|
||||
size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]);
|
||||
} else {
|
||||
memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes));
|
||||
/* Compute strong hash of remaining part of name. */
|
||||
err = fscrypt_do_sha256(&iname->name[sizeof(nokey_name.bytes)],
|
||||
iname->len - sizeof(nokey_name.bytes),
|
||||
nokey_name.sha256);
|
||||
if (err)
|
||||
return err;
|
||||
size = FSCRYPT_NOKEY_NAME_MAX;
|
||||
}
|
||||
oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
|
||||
@ -306,8 +396,7 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
|
||||
* get the disk_name.
|
||||
*
|
||||
* Else, for keyless @lookup operations, @iname is the presented ciphertext, so
|
||||
* we decode it to get either the ciphertext disk_name (for short names) or the
|
||||
* fscrypt_digested_name (for long names). Non-@lookup operations will be
|
||||
* we decode it to get the fscrypt_nokey_name. Non-@lookup operations will be
|
||||
* impossible in this case, so we fail them with ENOKEY.
|
||||
*
|
||||
* If successful, fscrypt_free_filename() must be called later to clean up.
|
||||
@ -317,8 +406,8 @@ EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
|
||||
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
int lookup, struct fscrypt_name *fname)
|
||||
{
|
||||
struct fscrypt_nokey_name *nokey_name;
|
||||
int ret;
|
||||
int digested;
|
||||
|
||||
memset(fname, 0, sizeof(struct fscrypt_name));
|
||||
fname->usr_fname = iname;
|
||||
@ -342,8 +431,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
if (!fname->crypto_buf.name)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fname_encrypt(dir, iname, fname->crypto_buf.name,
|
||||
fname->crypto_buf.len);
|
||||
ret = fscrypt_fname_encrypt(dir, iname, fname->crypto_buf.name,
|
||||
fname->crypto_buf.len);
|
||||
if (ret)
|
||||
goto errout;
|
||||
fname->disk_name.name = fname->crypto_buf.name;
|
||||
@ -358,40 +447,31 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
* We don't have the key and we are doing a lookup; decode the
|
||||
* user-supplied name
|
||||
*/
|
||||
if (iname->name[0] == '_') {
|
||||
if (iname->len !=
|
||||
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)))
|
||||
return -ENOENT;
|
||||
digested = 1;
|
||||
} else {
|
||||
if (iname->len >
|
||||
BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE))
|
||||
return -ENOENT;
|
||||
digested = 0;
|
||||
}
|
||||
|
||||
fname->crypto_buf.name =
|
||||
kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE,
|
||||
sizeof(struct fscrypt_digested_name)),
|
||||
GFP_KERNEL);
|
||||
if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX))
|
||||
return -ENOENT;
|
||||
|
||||
fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL);
|
||||
if (fname->crypto_buf.name == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = base64_decode(iname->name + digested, iname->len - digested,
|
||||
fname->crypto_buf.name);
|
||||
if (ret < 0) {
|
||||
ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name);
|
||||
if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) ||
|
||||
(ret > offsetof(struct fscrypt_nokey_name, sha256) &&
|
||||
ret != FSCRYPT_NOKEY_NAME_MAX)) {
|
||||
ret = -ENOENT;
|
||||
goto errout;
|
||||
}
|
||||
fname->crypto_buf.len = ret;
|
||||
if (digested) {
|
||||
const struct fscrypt_digested_name *n =
|
||||
(const void *)fname->crypto_buf.name;
|
||||
fname->hash = n->hash;
|
||||
fname->minor_hash = n->minor_hash;
|
||||
} else {
|
||||
fname->disk_name.name = fname->crypto_buf.name;
|
||||
fname->disk_name.len = fname->crypto_buf.len;
|
||||
|
||||
nokey_name = (void *)fname->crypto_buf.name;
|
||||
fname->hash = nokey_name->dirhash[0];
|
||||
fname->minor_hash = nokey_name->dirhash[1];
|
||||
if (ret != FSCRYPT_NOKEY_NAME_MAX) {
|
||||
/* The full ciphertext filename is available. */
|
||||
fname->disk_name.name = nokey_name->bytes;
|
||||
fname->disk_name.len =
|
||||
ret - offsetof(struct fscrypt_nokey_name, bytes);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@ -400,3 +480,109 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_setup_filename);
|
||||
|
||||
/**
|
||||
* fscrypt_match_name() - test whether the given name matches a directory entry
|
||||
* @fname: the name being searched for
|
||||
* @de_name: the name from the directory entry
|
||||
* @de_name_len: the length of @de_name in bytes
|
||||
*
|
||||
* Normally @fname->disk_name will be set, and in that case we simply compare
|
||||
* that to the name stored in the directory entry. The only exception is that
|
||||
* if we don't have the key for an encrypted directory and the name we're
|
||||
* looking for is very long, then we won't have the full disk_name and instead
|
||||
* we'll need to match against a fscrypt_nokey_name that includes a strong hash.
|
||||
*
|
||||
* Return: %true if the name matches, otherwise %false.
|
||||
*/
|
||||
bool fscrypt_match_name(const struct fscrypt_name *fname,
|
||||
const u8 *de_name, u32 de_name_len)
|
||||
{
|
||||
const struct fscrypt_nokey_name *nokey_name =
|
||||
(const void *)fname->crypto_buf.name;
|
||||
u8 sha256[SHA256_DIGEST_SIZE];
|
||||
|
||||
if (likely(fname->disk_name.name)) {
|
||||
if (de_name_len != fname->disk_name.len)
|
||||
return false;
|
||||
return !memcmp(de_name, fname->disk_name.name, de_name_len);
|
||||
}
|
||||
if (de_name_len <= sizeof(nokey_name->bytes))
|
||||
return false;
|
||||
if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes)))
|
||||
return false;
|
||||
if (fscrypt_do_sha256(&de_name[sizeof(nokey_name->bytes)],
|
||||
de_name_len - sizeof(nokey_name->bytes), sha256))
|
||||
return false;
|
||||
return !memcmp(sha256, nokey_name->sha256, sizeof(sha256));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_match_name);
|
||||
|
||||
/**
|
||||
* fscrypt_fname_siphash() - calculate the SipHash of a filename
|
||||
* @dir: the parent directory
|
||||
* @name: the filename to calculate the SipHash of
|
||||
*
|
||||
* Given a plaintext filename @name and a directory @dir which uses SipHash as
|
||||
* its dirhash method and has had its fscrypt key set up, this function
|
||||
* calculates the SipHash of that name using the directory's secret dirhash key.
|
||||
*
|
||||
* Return: the SipHash of @name using the hash key of @dir
|
||||
*/
|
||||
u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name)
|
||||
{
|
||||
const struct fscrypt_info *ci = dir->i_crypt_info;
|
||||
|
||||
WARN_ON(!ci->ci_dirhash_key_initialized);
|
||||
|
||||
return siphash(name->name, name->len, &ci->ci_dirhash_key);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_fname_siphash);
|
||||
|
||||
/*
|
||||
* Validate dentries in encrypted directories to make sure we aren't potentially
|
||||
* caching stale dentries after a key has been added.
|
||||
*/
|
||||
static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct dentry *dir;
|
||||
int err;
|
||||
int valid;
|
||||
|
||||
/*
|
||||
* Plaintext names are always valid, since fscrypt doesn't support
|
||||
* reverting to ciphertext names without evicting the directory's inode
|
||||
* -- which implies eviction of the dentries in the directory.
|
||||
*/
|
||||
if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Ciphertext name; valid if the directory's key is still unavailable.
|
||||
*
|
||||
* Although fscrypt forbids rename() on ciphertext names, we still must
|
||||
* use dget_parent() here rather than use ->d_parent directly. That's
|
||||
* because a corrupted fs image may contain directory hard links, which
|
||||
* the VFS handles by moving the directory's dentry tree in the dcache
|
||||
* each time ->lookup() finds the directory and it already has a dentry
|
||||
* elsewhere. Thus ->d_parent can be changing, and we must safely grab
|
||||
* a reference to some ->d_parent to prevent it from being freed.
|
||||
*/
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
dir = dget_parent(dentry);
|
||||
err = fscrypt_get_encryption_info(d_inode(dir));
|
||||
valid = !fscrypt_has_encryption_key(d_inode(dir));
|
||||
dput(dir);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
const struct dentry_operations fscrypt_d_ops = {
|
||||
.d_revalidate = fscrypt_d_revalidate,
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define _FSCRYPT_PRIVATE_H
|
||||
|
||||
#include <linux/fscrypt.h>
|
||||
#include <linux/siphash.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/bio-crypt-ctx.h>
|
||||
|
||||
@ -138,12 +139,6 @@ fscrypt_policy_flags(const union fscrypt_policy *policy)
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
fscrypt_is_direct_key_policy(const union fscrypt_policy *policy)
|
||||
{
|
||||
return fscrypt_policy_flags(policy) & FSCRYPT_POLICY_FLAG_DIRECT_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* For encrypted symlinks, the ciphertext length is stored at the beginning
|
||||
* of the string in little-endian format.
|
||||
@ -218,6 +213,14 @@ struct fscrypt_info {
|
||||
*/
|
||||
struct fscrypt_direct_key *ci_direct_key;
|
||||
|
||||
/*
|
||||
* This inode's hash key for filenames. This is a 128-bit SipHash-2-4
|
||||
* key. This is only set for directories that use a keyed dirhash over
|
||||
* the plaintext filenames -- currently just casefolded directories.
|
||||
*/
|
||||
siphash_key_t ci_dirhash_key;
|
||||
bool ci_dirhash_key_initialized;
|
||||
|
||||
/* The encryption policy used by this inode */
|
||||
union fscrypt_policy ci_policy;
|
||||
|
||||
@ -230,24 +233,6 @@ typedef enum {
|
||||
FS_ENCRYPT,
|
||||
} fscrypt_direction_t;
|
||||
|
||||
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
u32 filenames_mode)
|
||||
{
|
||||
if (contents_mode == FSCRYPT_MODE_AES_128_CBC &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_128_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_256_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FSCRYPT_MODE_ADIANTUM &&
|
||||
filenames_mode == FSCRYPT_MODE_ADIANTUM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* crypto.c */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern int fscrypt_initialize(unsigned int cop_flags);
|
||||
@ -257,7 +242,6 @@ extern int fscrypt_crypt_block(const struct inode *inode,
|
||||
unsigned int len, unsigned int offs,
|
||||
gfp_t gfp_flags);
|
||||
extern struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
|
||||
extern void __printf(3, 4) __cold
|
||||
fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...);
|
||||
@ -285,11 +269,13 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
|
||||
const struct fscrypt_info *ci);
|
||||
|
||||
/* fname.c */
|
||||
extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
u8 *out, unsigned int olen);
|
||||
extern int fscrypt_fname_encrypt(const struct inode *inode,
|
||||
const struct qstr *iname,
|
||||
u8 *out, unsigned int olen);
|
||||
extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
|
||||
u32 orig_len, u32 max_len,
|
||||
u32 *encrypted_len_ret);
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
|
||||
/* hkdf.c */
|
||||
|
||||
@ -308,11 +294,12 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
|
||||
* output doesn't reveal another.
|
||||
*/
|
||||
#define HKDF_CONTEXT_KEY_IDENTIFIER 1
|
||||
#define HKDF_CONTEXT_PER_FILE_KEY 2
|
||||
#define HKDF_CONTEXT_PER_FILE_ENC_KEY 2
|
||||
#define HKDF_CONTEXT_DIRECT_KEY 3
|
||||
#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4
|
||||
#define HKDF_CONTEXT_DIRHASH_KEY 5
|
||||
|
||||
extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context,
|
||||
extern int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
|
||||
const u8 *info, unsigned int infolen,
|
||||
u8 *okm, unsigned int okmlen);
|
||||
|
||||
@ -568,20 +555,17 @@ struct fscrypt_mode {
|
||||
|
||||
extern struct fscrypt_mode fscrypt_modes[];
|
||||
|
||||
static inline bool
|
||||
fscrypt_mode_supports_direct_key(const struct fscrypt_mode *mode)
|
||||
{
|
||||
return mode->ivsize >= offsetofend(union fscrypt_iv, nonce);
|
||||
}
|
||||
|
||||
extern int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
|
||||
const u8 *raw_key, unsigned int raw_key_size,
|
||||
const struct fscrypt_info *ci);
|
||||
|
||||
extern void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key);
|
||||
|
||||
extern int fscrypt_set_derived_key(struct fscrypt_info *ci,
|
||||
const u8 *derived_key);
|
||||
extern int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci,
|
||||
const u8 *raw_key);
|
||||
|
||||
extern int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
|
||||
const struct fscrypt_master_key *mk);
|
||||
|
||||
/* keysetup_v1.c */
|
||||
|
||||
|
@ -112,7 +112,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
|
||||
* adds to its application-specific info strings to guarantee that it doesn't
|
||||
* accidentally repeat an info string when using HKDF for different purposes.)
|
||||
*/
|
||||
int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context,
|
||||
int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
|
||||
const u8 *info, unsigned int infolen,
|
||||
u8 *okm, unsigned int okmlen)
|
||||
{
|
||||
|
@ -5,6 +5,8 @@
|
||||
* Encryption hooks for higher-level filesystem operations.
|
||||
*/
|
||||
|
||||
#include <linux/key.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/**
|
||||
@ -122,6 +124,48 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
|
||||
|
||||
/**
|
||||
* fscrypt_prepare_setflags() - prepare to change flags with FS_IOC_SETFLAGS
|
||||
* @inode: the inode on which flags are being changed
|
||||
* @oldflags: the old flags
|
||||
* @flags: the new flags
|
||||
*
|
||||
* The caller should be holding i_rwsem for write.
|
||||
*
|
||||
* Return: 0 on success; -errno if the flags change isn't allowed or if
|
||||
* another error occurs.
|
||||
*/
|
||||
int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags, unsigned int flags)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
struct fscrypt_master_key *mk;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* When the CASEFOLD flag is set on an encrypted directory, we must
|
||||
* derive the secret key needed for the dirhash. This is only possible
|
||||
* if the directory uses a v2 encryption policy.
|
||||
*/
|
||||
if (IS_ENCRYPTED(inode) && (flags & ~oldflags & FS_CASEFOLD_FL)) {
|
||||
err = fscrypt_require_key(inode);
|
||||
if (err)
|
||||
return err;
|
||||
ci = inode->i_crypt_info;
|
||||
if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
|
||||
return -EINVAL;
|
||||
mk = ci->ci_master_key->payload.data[0];
|
||||
down_read(&mk->mk_secret_sem);
|
||||
if (is_master_key_secret_present(&mk->mk_secret))
|
||||
err = fscrypt_derive_dirhash_key(ci, mk);
|
||||
else
|
||||
err = -ENOKEY;
|
||||
up_read(&mk->mk_secret_sem);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
|
||||
unsigned int max_len,
|
||||
struct fscrypt_str *disk_link)
|
||||
@ -188,7 +232,8 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
|
||||
ciphertext_len = disk_link->len - sizeof(*sd);
|
||||
sd->len = cpu_to_le16(ciphertext_len);
|
||||
|
||||
err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
|
||||
err = fscrypt_fname_encrypt(inode, &iname, sd->encrypted_path,
|
||||
ciphertext_len);
|
||||
if (err)
|
||||
goto err_free_sd;
|
||||
|
||||
|
@ -465,6 +465,111 @@ static int add_master_key(struct super_block *sb,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fscrypt_provisioning_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
const struct fscrypt_provisioning_key_payload *payload = prep->data;
|
||||
|
||||
BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE < FSCRYPT_MAX_KEY_SIZE);
|
||||
|
||||
if (prep->datalen < sizeof(*payload) + FSCRYPT_MIN_KEY_SIZE ||
|
||||
prep->datalen > sizeof(*payload) + FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (payload->type != FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR &&
|
||||
payload->type != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER)
|
||||
return -EINVAL;
|
||||
|
||||
if (payload->__reserved)
|
||||
return -EINVAL;
|
||||
|
||||
prep->payload.data[0] = kmemdup(payload, prep->datalen, GFP_KERNEL);
|
||||
if (!prep->payload.data[0])
|
||||
return -ENOMEM;
|
||||
|
||||
prep->quotalen = prep->datalen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fscrypt_provisioning_key_free_preparse(
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
kzfree(prep->payload.data[0]);
|
||||
}
|
||||
|
||||
static void fscrypt_provisioning_key_describe(const struct key *key,
|
||||
struct seq_file *m)
|
||||
{
|
||||
seq_puts(m, key->description);
|
||||
if (key_is_positive(key)) {
|
||||
const struct fscrypt_provisioning_key_payload *payload =
|
||||
key->payload.data[0];
|
||||
|
||||
seq_printf(m, ": %u [%u]", key->datalen, payload->type);
|
||||
}
|
||||
}
|
||||
|
||||
static void fscrypt_provisioning_key_destroy(struct key *key)
|
||||
{
|
||||
kzfree(key->payload.data[0]);
|
||||
}
|
||||
|
||||
static struct key_type key_type_fscrypt_provisioning = {
|
||||
.name = "fscrypt-provisioning",
|
||||
.preparse = fscrypt_provisioning_key_preparse,
|
||||
.free_preparse = fscrypt_provisioning_key_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.describe = fscrypt_provisioning_key_describe,
|
||||
.destroy = fscrypt_provisioning_key_destroy,
|
||||
};
|
||||
|
||||
/*
|
||||
* Retrieve the raw key from the Linux keyring key specified by 'key_id', and
|
||||
* store it into 'secret'.
|
||||
*
|
||||
* The key must be of type "fscrypt-provisioning" and must have the field
|
||||
* fscrypt_provisioning_key_payload::type set to 'type', indicating that it's
|
||||
* only usable with fscrypt with the particular KDF version identified by
|
||||
* 'type'. We don't use the "logon" key type because there's no way to
|
||||
* completely restrict the use of such keys; they can be used by any kernel API
|
||||
* that accepts "logon" keys and doesn't require a specific service prefix.
|
||||
*
|
||||
* The ability to specify the key via Linux keyring key is intended for cases
|
||||
* where userspace needs to re-add keys after the filesystem is unmounted and
|
||||
* re-mounted. Most users should just provide the raw key directly instead.
|
||||
*/
|
||||
static int get_keyring_key(u32 key_id, u32 type,
|
||||
struct fscrypt_master_key_secret *secret)
|
||||
{
|
||||
key_ref_t ref;
|
||||
struct key *key;
|
||||
const struct fscrypt_provisioning_key_payload *payload;
|
||||
int err;
|
||||
|
||||
ref = lookup_user_key(key_id, 0, KEY_NEED_SEARCH);
|
||||
if (IS_ERR(ref))
|
||||
return PTR_ERR(ref);
|
||||
key = key_ref_to_ptr(ref);
|
||||
|
||||
if (key->type != &key_type_fscrypt_provisioning)
|
||||
goto bad_key;
|
||||
payload = key->payload.data[0];
|
||||
|
||||
/* Don't allow fscrypt v1 keys to be used as v2 keys and vice versa. */
|
||||
if (payload->type != type)
|
||||
goto bad_key;
|
||||
|
||||
secret->size = key->datalen - sizeof(*payload);
|
||||
memcpy(secret->raw, payload->raw, secret->size);
|
||||
err = 0;
|
||||
goto out_put;
|
||||
|
||||
bad_key:
|
||||
err = -EKEYREJECTED;
|
||||
out_put:
|
||||
key_ref_put(ref);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Size of software "secret" derived from hardware-wrapped key */
|
||||
#define RAW_SECRET_SIZE 32
|
||||
|
||||
@ -512,20 +617,28 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
|
||||
if (memchr_inv(arg.__reserved, 0, sizeof(arg.__reserved)))
|
||||
return -EINVAL;
|
||||
|
||||
BUILD_BUG_ON(FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE <
|
||||
FSCRYPT_MAX_KEY_SIZE);
|
||||
|
||||
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
|
||||
arg.raw_size >
|
||||
((arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) ?
|
||||
FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE : FSCRYPT_MAX_KEY_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&secret, 0, sizeof(secret));
|
||||
secret.size = arg.raw_size;
|
||||
err = -EFAULT;
|
||||
if (copy_from_user(secret.raw, uarg->raw, secret.size))
|
||||
goto out_wipe_secret;
|
||||
if (arg.key_id) {
|
||||
if (arg.raw_size != 0)
|
||||
return -EINVAL;
|
||||
err = get_keyring_key(arg.key_id, arg.key_spec.type, &secret);
|
||||
if (err)
|
||||
goto out_wipe_secret;
|
||||
err = -EINVAL;
|
||||
if (!(arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) &&
|
||||
secret.size > FSCRYPT_MAX_KEY_SIZE)
|
||||
goto out_wipe_secret;
|
||||
} else {
|
||||
if (arg.raw_size < FSCRYPT_MIN_KEY_SIZE ||
|
||||
arg.raw_size >
|
||||
((arg.__flags & __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED) ?
|
||||
FSCRYPT_MAX_HW_WRAPPED_KEY_SIZE : FSCRYPT_MAX_KEY_SIZE))
|
||||
return -EINVAL;
|
||||
secret.size = arg.raw_size;
|
||||
err = -EFAULT;
|
||||
if (copy_from_user(secret.raw, uarg->raw, secret.size))
|
||||
goto out_wipe_secret;
|
||||
}
|
||||
|
||||
switch (arg.key_spec.type) {
|
||||
case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
|
||||
@ -1019,8 +1132,14 @@ int __init fscrypt_init_keyring(void)
|
||||
if (err)
|
||||
goto err_unregister_fscrypt;
|
||||
|
||||
err = register_key_type(&key_type_fscrypt_provisioning);
|
||||
if (err)
|
||||
goto err_unregister_fscrypt_user;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_fscrypt_user:
|
||||
unregister_key_type(&key_type_fscrypt_user);
|
||||
err_unregister_fscrypt:
|
||||
unregister_key_type(&key_type_fscrypt);
|
||||
return err;
|
||||
|
@ -92,8 +92,11 @@ 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_alg(tfm)->base.cra_driver_name);
|
||||
mode->friendly_name, crypto_skcipher_driver_name(tfm));
|
||||
}
|
||||
if (WARN_ON(crypto_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);
|
||||
@ -143,18 +146,18 @@ void fscrypt_destroy_prepared_key(struct fscrypt_prepared_key *prep_key)
|
||||
fscrypt_destroy_inline_crypt_key(prep_key);
|
||||
}
|
||||
|
||||
/* Given the per-file key, set up the file's crypto transform object */
|
||||
int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key)
|
||||
/* Given a per-file encryption key, set up the file's crypto transform object */
|
||||
int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key)
|
||||
{
|
||||
ci->ci_owns_key = true;
|
||||
return fscrypt_prepare_key(&ci->ci_key, derived_key,
|
||||
return fscrypt_prepare_key(&ci->ci_key, raw_key,
|
||||
ci->ci_mode->keysize, ci);
|
||||
}
|
||||
|
||||
static int setup_per_mode_key(struct fscrypt_info *ci,
|
||||
struct fscrypt_master_key *mk,
|
||||
struct fscrypt_prepared_key *keys,
|
||||
u8 hkdf_context, bool include_fs_uuid)
|
||||
static int setup_per_mode_enc_key(struct fscrypt_info *ci,
|
||||
struct fscrypt_master_key *mk,
|
||||
struct fscrypt_prepared_key *keys,
|
||||
u8 hkdf_context, bool include_fs_uuid)
|
||||
{
|
||||
static DEFINE_MUTEX(mode_key_setup_mutex);
|
||||
const struct inode *inode = ci->ci_inode;
|
||||
@ -231,10 +234,24 @@ static int setup_per_mode_key(struct fscrypt_info *ci,
|
||||
return err;
|
||||
}
|
||||
|
||||
int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
|
||||
const struct fscrypt_master_key *mk)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, HKDF_CONTEXT_DIRHASH_KEY,
|
||||
ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE,
|
||||
(u8 *)&ci->ci_dirhash_key,
|
||||
sizeof(ci->ci_dirhash_key));
|
||||
if (err)
|
||||
return err;
|
||||
ci->ci_dirhash_key_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
|
||||
struct fscrypt_master_key *mk)
|
||||
{
|
||||
u8 derived_key[FSCRYPT_MAX_KEY_SIZE];
|
||||
int err;
|
||||
|
||||
if (mk->mk_secret.is_hw_wrapped &&
|
||||
@ -246,21 +263,15 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
|
||||
|
||||
if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
|
||||
/*
|
||||
* DIRECT_KEY: instead of deriving per-file keys, the per-file
|
||||
* nonce will be included in all the IVs. But unlike v1
|
||||
* policies, for v2 policies in this case we don't encrypt with
|
||||
* the master key directly but rather derive a per-mode key.
|
||||
* This ensures that the master key is consistently used only
|
||||
* for HKDF, avoiding key reuse issues.
|
||||
* DIRECT_KEY: instead of deriving per-file encryption keys, the
|
||||
* per-file nonce will be included in all the IVs. But unlike
|
||||
* v1 policies, for v2 policies in this case we don't encrypt
|
||||
* with the master key directly but rather derive a per-mode
|
||||
* encryption key. This ensures that the master key is
|
||||
* consistently used only for HKDF, avoiding key reuse issues.
|
||||
*/
|
||||
if (!fscrypt_mode_supports_direct_key(ci->ci_mode)) {
|
||||
fscrypt_warn(ci->ci_inode,
|
||||
"Direct key flag not allowed with %s",
|
||||
ci->ci_mode->friendly_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return setup_per_mode_key(ci, mk, mk->mk_direct_keys,
|
||||
HKDF_CONTEXT_DIRECT_KEY, false);
|
||||
err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
|
||||
HKDF_CONTEXT_DIRECT_KEY, false);
|
||||
} else if (ci->ci_policy.v2.flags &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
|
||||
/*
|
||||
@ -269,21 +280,34 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
|
||||
* the IVs. This format is optimized for use with inline
|
||||
* encryption hardware compliant with the UFS or eMMC standards.
|
||||
*/
|
||||
return setup_per_mode_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
|
||||
HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
|
||||
true);
|
||||
}
|
||||
err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
|
||||
HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
|
||||
true);
|
||||
} else {
|
||||
u8 derived_key[FSCRYPT_MAX_KEY_SIZE];
|
||||
|
||||
err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf,
|
||||
HKDF_CONTEXT_PER_FILE_KEY,
|
||||
ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE,
|
||||
derived_key, ci->ci_mode->keysize);
|
||||
err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf,
|
||||
HKDF_CONTEXT_PER_FILE_ENC_KEY,
|
||||
ci->ci_nonce,
|
||||
FS_KEY_DERIVATION_NONCE_SIZE,
|
||||
derived_key, ci->ci_mode->keysize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_set_per_file_enc_key(ci, derived_key);
|
||||
memzero_explicit(derived_key, ci->ci_mode->keysize);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_set_derived_key(ci, derived_key);
|
||||
memzero_explicit(derived_key, ci->ci_mode->keysize);
|
||||
return err;
|
||||
/* Derive a secret dirhash key for directories that need it. */
|
||||
if (S_ISDIR(ci->ci_inode->i_mode) && IS_CASEFOLDED(ci->ci_inode)) {
|
||||
err = fscrypt_derive_dirhash_key(ci, mk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9,7 +9,7 @@
|
||||
* This file implements compatibility functions for the original encryption
|
||||
* policy version ("v1"), including:
|
||||
*
|
||||
* - Deriving per-file keys using the AES-128-ECB based KDF
|
||||
* - Deriving per-file encryption keys using the AES-128-ECB based KDF
|
||||
* (rather than the new method of using HKDF-SHA512)
|
||||
*
|
||||
* - Retrieving fscrypt master keys from process-subscribed keyrings
|
||||
@ -252,23 +252,8 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key)
|
||||
static int setup_v1_file_key_direct(struct fscrypt_info *ci,
|
||||
const u8 *raw_master_key)
|
||||
{
|
||||
const struct fscrypt_mode *mode = ci->ci_mode;
|
||||
struct fscrypt_direct_key *dk;
|
||||
|
||||
if (!fscrypt_mode_supports_direct_key(mode)) {
|
||||
fscrypt_warn(ci->ci_inode,
|
||||
"Direct key mode not allowed with %s",
|
||||
mode->friendly_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ci->ci_policy.v1.contents_encryption_mode !=
|
||||
ci->ci_policy.v1.filenames_encryption_mode) {
|
||||
fscrypt_warn(ci->ci_inode,
|
||||
"Direct key mode not allowed with different contents and filenames modes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dk = fscrypt_get_direct_key(ci, raw_master_key);
|
||||
if (IS_ERR(dk))
|
||||
return PTR_ERR(dk);
|
||||
@ -297,7 +282,7 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = fscrypt_set_derived_key(ci, derived_key);
|
||||
err = fscrypt_set_per_file_enc_key(ci, derived_key);
|
||||
out:
|
||||
kzfree(derived_key);
|
||||
return err;
|
||||
|
@ -29,6 +29,43 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
|
||||
return !memcmp(policy1, policy2, fscrypt_policy_size(policy1));
|
||||
}
|
||||
|
||||
static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode)
|
||||
{
|
||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_256_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FSCRYPT_MODE_AES_128_CBC &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_128_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FSCRYPT_MODE_ADIANTUM &&
|
||||
filenames_mode == FSCRYPT_MODE_ADIANTUM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool supported_direct_key_modes(const struct inode *inode,
|
||||
u32 contents_mode, u32 filenames_mode)
|
||||
{
|
||||
const struct fscrypt_mode *mode;
|
||||
|
||||
if (contents_mode != filenames_mode) {
|
||||
fscrypt_warn(inode,
|
||||
"Direct key flag not allowed with different contents and filenames modes");
|
||||
return false;
|
||||
}
|
||||
mode = &fscrypt_modes[contents_mode];
|
||||
|
||||
if (mode->ivsize < offsetofend(union fscrypt_iv, nonce)) {
|
||||
fscrypt_warn(inode, "Direct key flag not allowed with %s",
|
||||
mode->friendly_name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool supported_iv_ino_lblk_64_policy(
|
||||
const struct fscrypt_policy_v2 *policy,
|
||||
const struct inode *inode)
|
||||
@ -63,13 +100,82 @@ static bool supported_iv_ino_lblk_64_policy(
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
|
||||
const struct inode *inode)
|
||||
{
|
||||
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode)) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption modes (contents %d, filenames %d)",
|
||||
policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK |
|
||||
FSCRYPT_POLICY_FLAG_DIRECT_KEY)) {
|
||||
fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)",
|
||||
policy->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) &&
|
||||
!supported_direct_key_modes(inode, policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode))
|
||||
return false;
|
||||
|
||||
if (IS_CASEFOLDED(inode)) {
|
||||
/* With v1, there's no way to derive dirhash keys. */
|
||||
fscrypt_warn(inode,
|
||||
"v1 policies can't be used on casefolded directories");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
|
||||
const struct inode *inode)
|
||||
{
|
||||
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode)) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption modes (contents %d, filenames %d)",
|
||||
policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) {
|
||||
fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)",
|
||||
policy->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) &&
|
||||
!supported_direct_key_modes(inode, policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode))
|
||||
return false;
|
||||
|
||||
if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) &&
|
||||
!supported_iv_ino_lblk_64_policy(policy, inode))
|
||||
return false;
|
||||
|
||||
if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) {
|
||||
fscrypt_warn(inode, "Reserved bits set in encryption policy");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_supported_policy - check whether an encryption policy is supported
|
||||
*
|
||||
* Given an encryption policy, check whether all its encryption modes and other
|
||||
* settings are supported by this kernel. (But we don't currently don't check
|
||||
* for crypto API support here, so attempting to use an algorithm not configured
|
||||
* into the crypto API will still fail later.)
|
||||
* settings are supported by this kernel on the given inode. (But we don't
|
||||
* currently don't check for crypto API support here, so attempting to use an
|
||||
* algorithm not configured into the crypto API will still fail later.)
|
||||
*
|
||||
* Return: %true if supported, else %false
|
||||
*/
|
||||
@ -77,60 +183,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
|
||||
const struct inode *inode)
|
||||
{
|
||||
switch (policy_u->version) {
|
||||
case FSCRYPT_POLICY_V1: {
|
||||
const struct fscrypt_policy_v1 *policy = &policy_u->v1;
|
||||
|
||||
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode)) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption modes (contents %d, filenames %d)",
|
||||
policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK |
|
||||
FSCRYPT_POLICY_FLAG_DIRECT_KEY)) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption flags (0x%02x)",
|
||||
policy->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case FSCRYPT_POLICY_V2: {
|
||||
const struct fscrypt_policy_v2 *policy = &policy_u->v2;
|
||||
|
||||
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode)) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption modes (contents %d, filenames %d)",
|
||||
policy->contents_encryption_mode,
|
||||
policy->filenames_encryption_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) {
|
||||
fscrypt_warn(inode,
|
||||
"Unsupported encryption flags (0x%02x)",
|
||||
policy->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) &&
|
||||
!supported_iv_ino_lblk_64_policy(policy, inode))
|
||||
return false;
|
||||
|
||||
if (memchr_inv(policy->__reserved, 0,
|
||||
sizeof(policy->__reserved))) {
|
||||
fscrypt_warn(inode,
|
||||
"Reserved bits set in encryption policy");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case FSCRYPT_POLICY_V1:
|
||||
return fscrypt_supported_v1_policy(&policy_u->v1, inode);
|
||||
case FSCRYPT_POLICY_V2:
|
||||
return fscrypt_supported_v2_policy(&policy_u->v2, inode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ config EXT4_FS
|
||||
select CRYPTO
|
||||
select CRYPTO_CRC32C
|
||||
select FS_IOMAP
|
||||
select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
|
||||
help
|
||||
This is the next generation of the ext3 filesystem.
|
||||
|
||||
|
@ -121,7 +121,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err && err != -ENOKEY)
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -342,12 +342,55 @@ static int ext4_get_verity_descriptor(struct inode *inode, void *buf,
|
||||
return desc_size;
|
||||
}
|
||||
|
||||
static struct page *ext4_read_merkle_tree_page(struct inode *inode,
|
||||
pgoff_t index)
|
||||
/*
|
||||
* Prefetch some pages from the file's Merkle tree.
|
||||
*
|
||||
* This is basically a stripped-down version of __do_page_cache_readahead()
|
||||
* which works on pages past i_size.
|
||||
*/
|
||||
static void ext4_merkle_tree_readahead(struct address_space *mapping,
|
||||
pgoff_t start_index, unsigned long count)
|
||||
{
|
||||
LIST_HEAD(pages);
|
||||
unsigned int nr_pages = 0;
|
||||
struct page *page;
|
||||
pgoff_t index;
|
||||
struct blk_plug plug;
|
||||
|
||||
for (index = start_index; index < start_index + count; index++) {
|
||||
page = xa_load(&mapping->i_pages, index);
|
||||
if (!page || xa_is_value(page)) {
|
||||
page = __page_cache_alloc(readahead_gfp_mask(mapping));
|
||||
if (!page)
|
||||
break;
|
||||
page->index = index;
|
||||
list_add(&page->lru, &pages);
|
||||
nr_pages++;
|
||||
}
|
||||
}
|
||||
blk_start_plug(&plug);
|
||||
ext4_mpage_readpages(mapping, &pages, NULL, nr_pages, true);
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
static struct page *ext4_read_merkle_tree_page(struct inode *inode,
|
||||
pgoff_t index,
|
||||
unsigned long num_ra_pages)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
index += ext4_verity_metadata_pos(inode) >> PAGE_SHIFT;
|
||||
|
||||
return read_mapping_page(inode->i_mapping, index, NULL);
|
||||
page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED);
|
||||
if (!page || !PageUptodate(page)) {
|
||||
if (page)
|
||||
put_page(page);
|
||||
else if (num_ra_pages > 1)
|
||||
ext4_merkle_tree_readahead(inode->i_mapping, index,
|
||||
num_ra_pages);
|
||||
page = read_mapping_page(inode->i_mapping, index, NULL);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
static int ext4_write_merkle_tree_block(struct inode *inode, const void *buf,
|
||||
|
@ -6,6 +6,7 @@ config F2FS_FS
|
||||
select CRYPTO
|
||||
select CRYPTO_CRC32
|
||||
select F2FS_FS_XATTR if FS_ENCRYPTION
|
||||
select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
|
||||
help
|
||||
F2FS is based on Log-structured File System (LFS), which supports
|
||||
versatile "flash-friendly" features. The design has been focused on
|
||||
|
@ -1001,7 +1001,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err && err != -ENOKEY)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = fscrypt_fname_alloc_buffer(inode, F2FS_NAME_LEN, &fstr);
|
||||
|
@ -222,12 +222,55 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf,
|
||||
return size;
|
||||
}
|
||||
|
||||
static struct page *f2fs_read_merkle_tree_page(struct inode *inode,
|
||||
pgoff_t index)
|
||||
/*
|
||||
* Prefetch some pages from the file's Merkle tree.
|
||||
*
|
||||
* This is basically a stripped-down version of __do_page_cache_readahead()
|
||||
* which works on pages past i_size.
|
||||
*/
|
||||
static void f2fs_merkle_tree_readahead(struct address_space *mapping,
|
||||
pgoff_t start_index, unsigned long count)
|
||||
{
|
||||
LIST_HEAD(pages);
|
||||
unsigned int nr_pages = 0;
|
||||
struct page *page;
|
||||
pgoff_t index;
|
||||
struct blk_plug plug;
|
||||
|
||||
for (index = start_index; index < start_index + count; index++) {
|
||||
page = xa_load(&mapping->i_pages, index);
|
||||
if (!page || xa_is_value(page)) {
|
||||
page = __page_cache_alloc(readahead_gfp_mask(mapping));
|
||||
if (!page)
|
||||
break;
|
||||
page->index = index;
|
||||
list_add(&page->lru, &pages);
|
||||
nr_pages++;
|
||||
}
|
||||
}
|
||||
blk_start_plug(&plug);
|
||||
f2fs_mpage_readpages(mapping, &pages, NULL, nr_pages, true);
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
static struct page *f2fs_read_merkle_tree_page(struct inode *inode,
|
||||
pgoff_t index,
|
||||
unsigned long num_ra_pages)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT;
|
||||
|
||||
return read_mapping_page(inode->i_mapping, index, NULL);
|
||||
page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED);
|
||||
if (!page || !PageUptodate(page)) {
|
||||
if (page)
|
||||
put_page(page);
|
||||
else if (num_ra_pages > 1)
|
||||
f2fs_merkle_tree_readahead(inode->i_mapping, index,
|
||||
num_ra_pages);
|
||||
page = read_mapping_page(inode->i_mapping, index, NULL);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/security.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/fscrypt.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/posix_acl.h>
|
||||
@ -2252,7 +2253,7 @@ int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
return fscrypt_prepare_setflags(inode, oldflags, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_ioc_setflags_prepare);
|
||||
|
||||
|
@ -12,6 +12,7 @@ config UBIFS_FS
|
||||
select CRYPTO_ZSTD if UBIFS_FS_ZSTD
|
||||
select CRYPTO_HASH_INFO
|
||||
select UBIFS_FS_XATTR if FS_ENCRYPTION
|
||||
select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
|
||||
depends on MTD_UBI
|
||||
help
|
||||
UBIFS is a file system for flash devices which works on top of UBI.
|
||||
|
@ -81,7 +81,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
struct ubifs_inode *ui;
|
||||
bool encrypted = false;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
if (IS_ENCRYPTED(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err);
|
||||
@ -225,9 +225,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (nm.hash) {
|
||||
ubifs_assert(c, fname_len(&nm) == 0);
|
||||
ubifs_assert(c, fname_name(&nm) == NULL);
|
||||
if (fname_name(&nm) == NULL) {
|
||||
if (nm.hash & ~UBIFS_S_KEY_HASH_MASK)
|
||||
goto done; /* ENOENT */
|
||||
dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
|
||||
@ -263,7 +261,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir) &&
|
||||
if (IS_ENCRYPTED(dir) &&
|
||||
(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
|
||||
!fscrypt_has_permitted_context(dir, inode)) {
|
||||
ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu",
|
||||
@ -501,7 +499,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
struct ubifs_dent_node *dent;
|
||||
struct inode *dir = file_inode(file);
|
||||
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
||||
bool encrypted = ubifs_crypt_is_encrypted(dir);
|
||||
bool encrypted = IS_ENCRYPTED(dir);
|
||||
|
||||
dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
|
||||
|
||||
@ -514,7 +512,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
if (encrypted) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err && err != -ENOKEY)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
|
||||
@ -1620,7 +1618,7 @@ int ubifs_getattr(const struct path *path, struct kstat *stat,
|
||||
|
||||
static int ubifs_dir_open(struct inode *dir, struct file *file)
|
||||
{
|
||||
if (ubifs_crypt_is_encrypted(dir))
|
||||
if (IS_ENCRYPTED(dir))
|
||||
return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
|
||||
|
||||
return 0;
|
||||
|
@ -67,7 +67,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
|
||||
|
||||
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, block);
|
||||
if (err)
|
||||
goto dump;
|
||||
@ -647,7 +647,7 @@ static int populate_page(struct ubifs_info *c, struct page *page,
|
||||
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
out_len = UBIFS_BLOCK_SIZE;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, page_block);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
@ -588,7 +588,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
|
||||
if (!xent) {
|
||||
dent->ch.node_type = UBIFS_DENT_NODE;
|
||||
if (nm->hash)
|
||||
if (fname_name(nm) == NULL)
|
||||
dent_key_init_hash(c, &dent_key, dir->i_ino, nm->hash);
|
||||
else
|
||||
dent_key_init(c, &dent_key, dir->i_ino, nm);
|
||||
@ -646,7 +646,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
ubifs_add_auth_dirt(c, lnum);
|
||||
|
||||
if (deletion) {
|
||||
if (nm->hash)
|
||||
if (fname_name(nm) == NULL)
|
||||
err = ubifs_tnc_remove_dh(c, &dent_key, nm->minor_hash);
|
||||
else
|
||||
err = ubifs_tnc_remove_nm(c, &dent_key, nm);
|
||||
@ -727,7 +727,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
|
||||
int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
|
||||
int write_len;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
bool encrypted = ubifs_crypt_is_encrypted(inode);
|
||||
bool encrypted = IS_ENCRYPTED(inode);
|
||||
u8 hash[UBIFS_HASH_ARR_SZ];
|
||||
|
||||
dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
|
||||
@ -1449,7 +1449,7 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
|
||||
dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
compr_type = le16_to_cpu(dn->compr_type);
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, block);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -1465,7 +1465,7 @@ static int truncate_data_node(const struct ubifs_info *c, const struct inode *in
|
||||
ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
|
||||
}
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = ubifs_encrypt(inode, dn, out_len, &old_dlen, block);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -150,7 +150,6 @@ static inline void dent_key_init(const struct ubifs_info *c,
|
||||
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
|
||||
|
||||
ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
|
||||
ubifs_assert(c, !nm->hash && !nm->minor_hash);
|
||||
key->u32[0] = inum;
|
||||
key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
|
||||
}
|
||||
|
@ -2095,13 +2095,6 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
|
||||
extern const struct fscrypt_operations ubifs_crypt_operations;
|
||||
|
||||
static inline bool ubifs_crypt_is_encrypted(const struct inode *inode)
|
||||
{
|
||||
const struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
|
||||
return ui->flags & UBIFS_CRYPT_FL;
|
||||
}
|
||||
|
||||
/* Normal UBIFS messages */
|
||||
__printf(2, 3)
|
||||
void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
|
||||
|
@ -8,18 +8,48 @@
|
||||
#include "fsverity_private.h"
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
static int build_merkle_tree_level(struct inode *inode, unsigned int level,
|
||||
/*
|
||||
* Read a file data page for Merkle tree construction. Do aggressive readahead,
|
||||
* since we're sequentially reading the entire file.
|
||||
*/
|
||||
static struct page *read_file_data_page(struct file *filp, pgoff_t index,
|
||||
struct file_ra_state *ra,
|
||||
unsigned long remaining_pages)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = find_get_page_flags(filp->f_mapping, index, FGP_ACCESSED);
|
||||
if (!page || !PageUptodate(page)) {
|
||||
if (page)
|
||||
put_page(page);
|
||||
else
|
||||
page_cache_sync_readahead(filp->f_mapping, ra, filp,
|
||||
index, remaining_pages);
|
||||
page = read_mapping_page(filp->f_mapping, index, NULL);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
}
|
||||
if (PageReadahead(page))
|
||||
page_cache_async_readahead(filp->f_mapping, ra, filp, page,
|
||||
index, remaining_pages);
|
||||
return page;
|
||||
}
|
||||
|
||||
static int build_merkle_tree_level(struct file *filp, unsigned int level,
|
||||
u64 num_blocks_to_hash,
|
||||
const struct merkle_tree_params *params,
|
||||
u8 *pending_hashes,
|
||||
struct ahash_request *req)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
const struct fsverity_operations *vops = inode->i_sb->s_vop;
|
||||
struct file_ra_state ra = { 0 };
|
||||
unsigned int pending_size = 0;
|
||||
u64 dst_block_num;
|
||||
u64 i;
|
||||
@ -36,6 +66,8 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level,
|
||||
dst_block_num = 0; /* unused */
|
||||
}
|
||||
|
||||
file_ra_state_init(&ra, filp->f_mapping);
|
||||
|
||||
for (i = 0; i < num_blocks_to_hash; i++) {
|
||||
struct page *src_page;
|
||||
|
||||
@ -45,7 +77,8 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level,
|
||||
|
||||
if (level == 0) {
|
||||
/* Leaf: hashing a data block */
|
||||
src_page = read_mapping_page(inode->i_mapping, i, NULL);
|
||||
src_page = read_file_data_page(filp, i, &ra,
|
||||
num_blocks_to_hash - i);
|
||||
if (IS_ERR(src_page)) {
|
||||
err = PTR_ERR(src_page);
|
||||
fsverity_err(inode,
|
||||
@ -54,9 +87,14 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level,
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
unsigned long num_ra_pages =
|
||||
min_t(unsigned long, num_blocks_to_hash - i,
|
||||
inode->i_sb->s_bdi->io_pages);
|
||||
|
||||
/* Non-leaf: hashing hash block from level below */
|
||||
src_page = vops->read_merkle_tree_page(inode,
|
||||
params->level_start[level - 1] + i);
|
||||
params->level_start[level - 1] + i,
|
||||
num_ra_pages);
|
||||
if (IS_ERR(src_page)) {
|
||||
err = PTR_ERR(src_page);
|
||||
fsverity_err(inode,
|
||||
@ -103,17 +141,18 @@ static int build_merkle_tree_level(struct inode *inode, unsigned int level,
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the Merkle tree for the given inode using the given parameters, and
|
||||
* Build the Merkle tree for the given file using the given parameters, and
|
||||
* return the root hash in @root_hash.
|
||||
*
|
||||
* The tree is written to a filesystem-specific location as determined by the
|
||||
* ->write_merkle_tree_block() method. However, the blocks that comprise the
|
||||
* tree are the same for all filesystems.
|
||||
*/
|
||||
static int build_merkle_tree(struct inode *inode,
|
||||
static int build_merkle_tree(struct file *filp,
|
||||
const struct merkle_tree_params *params,
|
||||
u8 *root_hash)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
u8 *pending_hashes;
|
||||
struct ahash_request *req;
|
||||
u64 blocks;
|
||||
@ -126,9 +165,11 @@ static int build_merkle_tree(struct inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This allocation never fails, since it's mempool-backed. */
|
||||
req = fsverity_alloc_hash_request(params->hash_alg, GFP_KERNEL);
|
||||
|
||||
pending_hashes = kmalloc(params->block_size, GFP_KERNEL);
|
||||
req = ahash_request_alloc(params->hash_alg->tfm, GFP_KERNEL);
|
||||
if (!pending_hashes || !req)
|
||||
if (!pending_hashes)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@ -139,7 +180,7 @@ static int build_merkle_tree(struct inode *inode,
|
||||
blocks = (inode->i_size + params->block_size - 1) >>
|
||||
params->log_blocksize;
|
||||
for (level = 0; level <= params->num_levels; level++) {
|
||||
err = build_merkle_tree_level(inode, level, blocks, params,
|
||||
err = build_merkle_tree_level(filp, level, blocks, params,
|
||||
pending_hashes, req);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -150,7 +191,7 @@ static int build_merkle_tree(struct inode *inode,
|
||||
err = 0;
|
||||
out:
|
||||
kfree(pending_hashes);
|
||||
ahash_request_free(req);
|
||||
fsverity_free_hash_request(params->hash_alg, req);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -175,8 +216,7 @@ static int enable_verity(struct file *filp,
|
||||
|
||||
/* Get the salt if the user provided one */
|
||||
if (arg->salt_size &&
|
||||
copy_from_user(desc->salt,
|
||||
(const u8 __user *)(uintptr_t)arg->salt_ptr,
|
||||
copy_from_user(desc->salt, u64_to_user_ptr(arg->salt_ptr),
|
||||
arg->salt_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
@ -185,8 +225,7 @@ static int enable_verity(struct file *filp,
|
||||
|
||||
/* Get the signature if the user provided one */
|
||||
if (arg->sig_size &&
|
||||
copy_from_user(desc->signature,
|
||||
(const u8 __user *)(uintptr_t)arg->sig_ptr,
|
||||
copy_from_user(desc->signature, u64_to_user_ptr(arg->sig_ptr),
|
||||
arg->sig_size)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
@ -227,7 +266,7 @@ static int enable_verity(struct file *filp,
|
||||
*/
|
||||
pr_debug("Building Merkle tree...\n");
|
||||
BUILD_BUG_ON(sizeof(desc->root_hash) < FS_VERITY_MAX_DIGEST_SIZE);
|
||||
err = build_merkle_tree(inode, ¶ms, desc->root_hash);
|
||||
err = build_merkle_tree(filp, ¶ms, desc->root_hash);
|
||||
if (err) {
|
||||
fsverity_err(inode, "Error %d building Merkle tree", err);
|
||||
goto rollback;
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <crypto/sha.h>
|
||||
#include <linux/fsverity.h>
|
||||
#include <linux/mempool.h>
|
||||
|
||||
struct ahash_request;
|
||||
|
||||
@ -37,11 +38,12 @@ struct fsverity_hash_alg {
|
||||
const char *name; /* crypto API name, e.g. sha256 */
|
||||
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
|
||||
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
|
||||
mempool_t req_pool; /* mempool with a preallocated hash request */
|
||||
};
|
||||
|
||||
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
|
||||
struct merkle_tree_params {
|
||||
const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
|
||||
struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
|
||||
const u8 *hashstate; /* initial hash state or NULL */
|
||||
unsigned int digest_size; /* same as hash_alg->digest_size */
|
||||
unsigned int block_size; /* size of data and tree blocks */
|
||||
@ -50,6 +52,7 @@ struct merkle_tree_params {
|
||||
unsigned int log_arity; /* log2(hashes_per_block) */
|
||||
unsigned int num_levels; /* number of levels in Merkle tree */
|
||||
u64 tree_size; /* Merkle tree size in bytes */
|
||||
unsigned long level0_blocks; /* number of blocks in tree level 0 */
|
||||
|
||||
/*
|
||||
* Starting block index for each tree level, ordered from leaf level (0)
|
||||
@ -114,14 +117,18 @@ struct fsverity_signed_digest {
|
||||
|
||||
extern struct fsverity_hash_alg fsverity_hash_algs[];
|
||||
|
||||
const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
unsigned int num);
|
||||
const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
|
||||
struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
unsigned int num);
|
||||
struct ahash_request *fsverity_alloc_hash_request(struct fsverity_hash_alg *alg,
|
||||
gfp_t gfp_flags);
|
||||
void fsverity_free_hash_request(struct fsverity_hash_alg *alg,
|
||||
struct ahash_request *req);
|
||||
const u8 *fsverity_prepare_hash_state(struct fsverity_hash_alg *alg,
|
||||
const u8 *salt, size_t salt_size);
|
||||
int fsverity_hash_page(const struct merkle_tree_params *params,
|
||||
const struct inode *inode,
|
||||
struct ahash_request *req, struct page *page, u8 *out);
|
||||
int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
|
||||
int fsverity_hash_buffer(struct fsverity_hash_alg *alg,
|
||||
const void *data, size_t size, u8 *out);
|
||||
void __init fsverity_check_hash_algs(void);
|
||||
|
||||
|
@ -24,6 +24,8 @@ struct fsverity_hash_alg fsverity_hash_algs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(fsverity_hash_alg_init_mutex);
|
||||
|
||||
/**
|
||||
* fsverity_get_hash_alg() - validate and prepare a hash algorithm
|
||||
* @inode: optional inode for logging purposes
|
||||
@ -36,8 +38,8 @@ struct fsverity_hash_alg fsverity_hash_algs[] = {
|
||||
*
|
||||
* Return: pointer to the hash alg on success, else an ERR_PTR()
|
||||
*/
|
||||
const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
unsigned int num)
|
||||
struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
unsigned int num)
|
||||
{
|
||||
struct fsverity_hash_alg *alg;
|
||||
struct crypto_ahash *tfm;
|
||||
@ -50,10 +52,15 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
}
|
||||
alg = &fsverity_hash_algs[num];
|
||||
|
||||
/* pairs with cmpxchg() below */
|
||||
tfm = READ_ONCE(alg->tfm);
|
||||
if (likely(tfm != NULL))
|
||||
/* pairs with smp_store_release() below */
|
||||
if (likely(smp_load_acquire(&alg->tfm) != NULL))
|
||||
return alg;
|
||||
|
||||
mutex_lock(&fsverity_hash_alg_init_mutex);
|
||||
|
||||
if (alg->tfm != NULL)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* Using the shash API would make things a bit simpler, but the ahash
|
||||
* API is preferable as it allows the use of crypto accelerators.
|
||||
@ -64,12 +71,14 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
fsverity_warn(inode,
|
||||
"Missing crypto API support for hash algorithm \"%s\"",
|
||||
alg->name);
|
||||
return ERR_PTR(-ENOPKG);
|
||||
alg = ERR_PTR(-ENOPKG);
|
||||
goto out_unlock;
|
||||
}
|
||||
fsverity_err(inode,
|
||||
"Error allocating hash algorithm \"%s\": %ld",
|
||||
alg->name, PTR_ERR(tfm));
|
||||
return ERR_CAST(tfm);
|
||||
alg = ERR_CAST(tfm);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = -EINVAL;
|
||||
@ -78,18 +87,61 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
if (WARN_ON(alg->block_size != crypto_ahash_blocksize(tfm)))
|
||||
goto err_free_tfm;
|
||||
|
||||
err = mempool_init_kmalloc_pool(&alg->req_pool, 1,
|
||||
sizeof(struct ahash_request) +
|
||||
crypto_ahash_reqsize(tfm));
|
||||
if (err)
|
||||
goto err_free_tfm;
|
||||
|
||||
pr_info("%s using implementation \"%s\"\n",
|
||||
alg->name, crypto_ahash_driver_name(tfm));
|
||||
|
||||
/* pairs with READ_ONCE() above */
|
||||
if (cmpxchg(&alg->tfm, NULL, tfm) != NULL)
|
||||
crypto_free_ahash(tfm);
|
||||
|
||||
return alg;
|
||||
/* pairs with smp_load_acquire() above */
|
||||
smp_store_release(&alg->tfm, tfm);
|
||||
goto out_unlock;
|
||||
|
||||
err_free_tfm:
|
||||
crypto_free_ahash(tfm);
|
||||
return ERR_PTR(err);
|
||||
alg = ERR_PTR(err);
|
||||
out_unlock:
|
||||
mutex_unlock(&fsverity_hash_alg_init_mutex);
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* fsverity_alloc_hash_request() - allocate a hash request object
|
||||
* @alg: the hash algorithm for which to allocate the request
|
||||
* @gfp_flags: memory allocation flags
|
||||
*
|
||||
* This is mempool-backed, so this never fails if __GFP_DIRECT_RECLAIM is set in
|
||||
* @gfp_flags. However, in that case this might need to wait for all
|
||||
* previously-allocated requests to be freed. So to avoid deadlocks, callers
|
||||
* must never need multiple requests at a time to make forward progress.
|
||||
*
|
||||
* Return: the request object on success; NULL on failure (but see above)
|
||||
*/
|
||||
struct ahash_request *fsverity_alloc_hash_request(struct fsverity_hash_alg *alg,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct ahash_request *req = mempool_alloc(&alg->req_pool, gfp_flags);
|
||||
|
||||
if (req)
|
||||
ahash_request_set_tfm(req, alg->tfm);
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* fsverity_free_hash_request() - free a hash request object
|
||||
* @alg: the hash algorithm
|
||||
* @req: the hash request object to free
|
||||
*/
|
||||
void fsverity_free_hash_request(struct fsverity_hash_alg *alg,
|
||||
struct ahash_request *req)
|
||||
{
|
||||
if (req) {
|
||||
ahash_request_zero(req);
|
||||
mempool_free(req, &alg->req_pool);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,7 +153,7 @@ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
||||
* Return: NULL if the salt is empty, otherwise the kmalloc()'ed precomputed
|
||||
* initial hash state on success or an ERR_PTR() on failure.
|
||||
*/
|
||||
const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
|
||||
const u8 *fsverity_prepare_hash_state(struct fsverity_hash_alg *alg,
|
||||
const u8 *salt, size_t salt_size)
|
||||
{
|
||||
u8 *hashstate = NULL;
|
||||
@ -119,11 +171,8 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
|
||||
if (!hashstate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
req = ahash_request_alloc(alg->tfm, GFP_KERNEL);
|
||||
if (!req) {
|
||||
err = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
/* This allocation never fails, since it's mempool-backed. */
|
||||
req = fsverity_alloc_hash_request(alg, GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Zero-pad the salt to the next multiple of the input size of the hash
|
||||
@ -158,7 +207,7 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
|
||||
if (err)
|
||||
goto err_free;
|
||||
out:
|
||||
ahash_request_free(req);
|
||||
fsverity_free_hash_request(alg, req);
|
||||
kfree(padded_salt);
|
||||
return hashstate;
|
||||
|
||||
@ -229,7 +278,7 @@ int fsverity_hash_page(const struct merkle_tree_params *params,
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
|
||||
int fsverity_hash_buffer(struct fsverity_hash_alg *alg,
|
||||
const void *data, size_t size, u8 *out)
|
||||
{
|
||||
struct ahash_request *req;
|
||||
@ -237,9 +286,8 @@ int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
int err;
|
||||
|
||||
req = ahash_request_alloc(alg->tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
/* This allocation never fails, since it's mempool-backed. */
|
||||
req = fsverity_alloc_hash_request(alg, GFP_KERNEL);
|
||||
|
||||
sg_init_one(&sg, data, size);
|
||||
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP |
|
||||
@ -249,7 +297,7 @@ int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
|
||||
|
||||
err = crypto_wait_req(crypto_ahash_digest(req), &wait);
|
||||
|
||||
ahash_request_free(req);
|
||||
fsverity_free_hash_request(alg, req);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
||||
unsigned int log_blocksize,
|
||||
const u8 *salt, size_t salt_size)
|
||||
{
|
||||
const struct fsverity_hash_alg *hash_alg;
|
||||
struct fsverity_hash_alg *hash_alg;
|
||||
int err;
|
||||
u64 blocks;
|
||||
u64 offset;
|
||||
@ -102,6 +102,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
||||
/* temporarily using level_start[] to store blocks in level */
|
||||
params->level_start[params->num_levels++] = blocks;
|
||||
}
|
||||
params->level0_blocks = params->level_start[0];
|
||||
|
||||
/* Compute the starting block of each level */
|
||||
offset = 0;
|
||||
@ -126,7 +127,7 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
||||
* Compute the file measurement by hashing the fsverity_descriptor excluding the
|
||||
* signature and with the sig_size field set to 0.
|
||||
*/
|
||||
static int compute_file_measurement(const struct fsverity_hash_alg *hash_alg,
|
||||
static int compute_file_measurement(struct fsverity_hash_alg *hash_alg,
|
||||
struct fsverity_descriptor *desc,
|
||||
u8 *measurement)
|
||||
{
|
||||
|
@ -84,7 +84,8 @@ static inline int cmp_hashes(const struct fsverity_info *vi,
|
||||
* Return: true if the page is valid, else false.
|
||||
*/
|
||||
static bool verify_page(struct inode *inode, const struct fsverity_info *vi,
|
||||
struct ahash_request *req, struct page *data_page)
|
||||
struct ahash_request *req, struct page *data_page,
|
||||
unsigned long level0_ra_pages)
|
||||
{
|
||||
const struct merkle_tree_params *params = &vi->tree_params;
|
||||
const unsigned int hsize = params->digest_size;
|
||||
@ -117,8 +118,8 @@ static bool verify_page(struct inode *inode, const struct fsverity_info *vi,
|
||||
pr_debug_ratelimited("Level %d: hindex=%lu, hoffset=%u\n",
|
||||
level, hindex, hoffset);
|
||||
|
||||
hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode,
|
||||
hindex);
|
||||
hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, hindex,
|
||||
level == 0 ? level0_ra_pages : 0);
|
||||
if (IS_ERR(hpage)) {
|
||||
err = PTR_ERR(hpage);
|
||||
fsverity_err(inode,
|
||||
@ -191,13 +192,12 @@ bool fsverity_verify_page(struct page *page)
|
||||
struct ahash_request *req;
|
||||
bool valid;
|
||||
|
||||
req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS);
|
||||
if (unlikely(!req))
|
||||
return false;
|
||||
/* This allocation never fails, since it's mempool-backed. */
|
||||
req = fsverity_alloc_hash_request(vi->tree_params.hash_alg, GFP_NOFS);
|
||||
|
||||
valid = verify_page(inode, vi, req, page);
|
||||
valid = verify_page(inode, vi, req, page, 0);
|
||||
|
||||
ahash_request_free(req);
|
||||
fsverity_free_hash_request(vi->tree_params.hash_alg, req);
|
||||
|
||||
return valid;
|
||||
}
|
||||
@ -222,25 +222,42 @@ void fsverity_verify_bio(struct bio *bio)
|
||||
{
|
||||
struct inode *inode = bio_first_page_all(bio)->mapping->host;
|
||||
const struct fsverity_info *vi = inode->i_verity_info;
|
||||
const struct merkle_tree_params *params = &vi->tree_params;
|
||||
struct ahash_request *req;
|
||||
struct bio_vec *bv;
|
||||
struct bvec_iter_all iter_all;
|
||||
unsigned long max_ra_pages = 0;
|
||||
|
||||
req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS);
|
||||
if (unlikely(!req)) {
|
||||
/* This allocation never fails, since it's mempool-backed. */
|
||||
req = fsverity_alloc_hash_request(params->hash_alg, GFP_NOFS);
|
||||
|
||||
if (bio->bi_opf & REQ_RAHEAD) {
|
||||
/*
|
||||
* If this bio is for data readahead, then we also do readahead
|
||||
* of the first (largest) level of the Merkle tree. Namely,
|
||||
* when a Merkle tree page is read, we also try to piggy-back on
|
||||
* some additional pages -- up to 1/4 the number of data pages.
|
||||
*
|
||||
* This improves sequential read performance, as it greatly
|
||||
* reduces the number of I/O requests made to the Merkle tree.
|
||||
*/
|
||||
bio_for_each_segment_all(bv, bio, iter_all)
|
||||
SetPageError(bv->bv_page);
|
||||
return;
|
||||
max_ra_pages++;
|
||||
max_ra_pages /= 4;
|
||||
}
|
||||
|
||||
bio_for_each_segment_all(bv, bio, iter_all) {
|
||||
struct page *page = bv->bv_page;
|
||||
unsigned long level0_index = page->index >> params->log_arity;
|
||||
unsigned long level0_ra_pages =
|
||||
min(max_ra_pages, params->level0_blocks - level0_index);
|
||||
|
||||
if (!PageError(page) && !verify_page(inode, vi, req, page))
|
||||
if (!PageError(page) &&
|
||||
!verify_page(inode, vi, req, page, level0_ra_pages))
|
||||
SetPageError(page);
|
||||
}
|
||||
|
||||
ahash_request_free(req);
|
||||
fsverity_free_hash_request(params->hash_alg, req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsverity_verify_bio);
|
||||
#endif /* CONFIG_BLOCK */
|
||||
|
@ -76,6 +76,21 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
return READ_ONCE(inode->i_crypt_info) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_needs_contents_encryption() - check whether an inode needs
|
||||
* contents encryption
|
||||
*
|
||||
* Return: %true iff the inode is an encrypted regular file and the kernel was
|
||||
* built with fscrypt support.
|
||||
*
|
||||
* If you need to know whether the encrypt bit is set even when the kernel was
|
||||
* built without fscrypt support, you must use IS_ENCRYPTED() directly instead.
|
||||
*/
|
||||
static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
|
||||
{
|
||||
return IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
return inode->i_sb->s_cop->dummy_context &&
|
||||
@ -159,82 +174,14 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname)
|
||||
extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
|
||||
struct fscrypt_str *);
|
||||
extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
|
||||
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
|
||||
const struct fscrypt_str *, struct fscrypt_str *);
|
||||
|
||||
#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
|
||||
|
||||
/* Extracts the second-to-last ciphertext block; see explanation below */
|
||||
#define FSCRYPT_FNAME_DIGEST(name, len) \
|
||||
((name) + round_down((len) - FS_CRYPTO_BLOCK_SIZE - 1, \
|
||||
FS_CRYPTO_BLOCK_SIZE))
|
||||
|
||||
#define FSCRYPT_FNAME_DIGEST_SIZE FS_CRYPTO_BLOCK_SIZE
|
||||
|
||||
/**
|
||||
* fscrypt_digested_name - alternate identifier for an on-disk filename
|
||||
*
|
||||
* When userspace lists an encrypted directory without access to the key,
|
||||
* filenames whose ciphertext is longer than FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE
|
||||
* bytes are shown in this abbreviated form (base64-encoded) rather than as the
|
||||
* full ciphertext (base64-encoded). This is necessary to allow supporting
|
||||
* filenames up to NAME_MAX bytes, since base64 encoding expands the length.
|
||||
*
|
||||
* To make it possible for filesystems to still find the correct directory entry
|
||||
* despite not knowing the full on-disk name, we encode any filesystem-specific
|
||||
* 'hash' and/or 'minor_hash' which the filesystem may need for its lookups,
|
||||
* followed by the second-to-last ciphertext block of the filename. Due to the
|
||||
* use of the CBC-CTS encryption mode, the second-to-last ciphertext block
|
||||
* depends on the full plaintext. (Note that ciphertext stealing causes the
|
||||
* last two blocks to appear "flipped".) This makes accidental collisions very
|
||||
* unlikely: just a 1 in 2^128 chance for two filenames to collide even if they
|
||||
* share the same filesystem-specific hashes.
|
||||
*
|
||||
* However, this scheme isn't immune to intentional collisions, which can be
|
||||
* created by anyone able to create arbitrary plaintext filenames and view them
|
||||
* without the key. Making the "digest" be a real cryptographic hash like
|
||||
* SHA-256 over the full ciphertext would prevent this, although it would be
|
||||
* less efficient and harder to implement, especially since the filesystem would
|
||||
* need to calculate it for each directory entry examined during a search.
|
||||
*/
|
||||
struct fscrypt_digested_name {
|
||||
u32 hash;
|
||||
u32 minor_hash;
|
||||
u8 digest[FSCRYPT_FNAME_DIGEST_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* fscrypt_match_name() - test whether the given name matches a directory entry
|
||||
* @fname: the name being searched for
|
||||
* @de_name: the name from the directory entry
|
||||
* @de_name_len: the length of @de_name in bytes
|
||||
*
|
||||
* Normally @fname->disk_name will be set, and in that case we simply compare
|
||||
* that to the name stored in the directory entry. The only exception is that
|
||||
* if we don't have the key for an encrypted directory and a filename in it is
|
||||
* very long, then we won't have the full disk_name and we'll instead need to
|
||||
* match against the fscrypt_digested_name.
|
||||
*
|
||||
* Return: %true if the name matches, otherwise %false.
|
||||
*/
|
||||
static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
|
||||
const u8 *de_name, u32 de_name_len)
|
||||
{
|
||||
if (unlikely(!fname->disk_name.name)) {
|
||||
const struct fscrypt_digested_name *n =
|
||||
(const void *)fname->crypto_buf.name;
|
||||
if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_'))
|
||||
return false;
|
||||
if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)
|
||||
return false;
|
||||
return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len),
|
||||
n->digest, FSCRYPT_FNAME_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
if (de_name_len != fname->disk_name.len)
|
||||
return false;
|
||||
return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
|
||||
}
|
||||
extern int fscrypt_fname_disk_to_usr(const struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname);
|
||||
extern bool fscrypt_match_name(const struct fscrypt_name *fname,
|
||||
const u8 *de_name, u32 de_name_len);
|
||||
extern u64 fscrypt_fname_siphash(const struct inode *dir,
|
||||
const struct qstr *name);
|
||||
|
||||
/* bio.c */
|
||||
extern void fscrypt_decrypt_bio(struct bio *);
|
||||
@ -252,6 +199,8 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir,
|
||||
unsigned int flags);
|
||||
extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct fscrypt_name *fname);
|
||||
extern int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags, unsigned int flags);
|
||||
extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
|
||||
unsigned int max_len,
|
||||
struct fscrypt_str *disk_link);
|
||||
@ -273,6 +222,11 @@ static inline bool fscrypt_has_encryption_key(const struct inode *inode)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_needs_contents_encryption(const struct inode *inode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
return false;
|
||||
@ -456,7 +410,7 @@ static inline void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
|
||||
static inline int fscrypt_fname_disk_to_usr(const struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
@ -473,6 +427,13 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
|
||||
return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
|
||||
}
|
||||
|
||||
static inline u64 fscrypt_fname_siphash(const struct inode *dir,
|
||||
const struct qstr *name)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bio.c */
|
||||
static inline void fscrypt_decrypt_bio(struct bio *bio)
|
||||
{
|
||||
@ -515,6 +476,13 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_prepare_setflags(struct inode *inode,
|
||||
unsigned int oldflags,
|
||||
unsigned int flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __fscrypt_prepare_symlink(struct inode *dir,
|
||||
unsigned int len,
|
||||
unsigned int max_len,
|
||||
|
@ -77,6 +77,10 @@ struct fsverity_operations {
|
||||
*
|
||||
* @inode: the inode
|
||||
* @index: 0-based index of the page within the Merkle tree
|
||||
* @num_ra_pages: The number of Merkle tree pages that should be
|
||||
* prefetched starting at @index if the page at @index
|
||||
* isn't already cached. Implementations may ignore this
|
||||
* argument; it's only a performance optimization.
|
||||
*
|
||||
* This can be called at any time on an open verity file, as well as
|
||||
* between ->begin_enable_verity() and ->end_enable_verity(). It may be
|
||||
@ -87,7 +91,8 @@ struct fsverity_operations {
|
||||
* Return: the page on success, ERR_PTR() on failure
|
||||
*/
|
||||
struct page *(*read_merkle_tree_page)(struct inode *inode,
|
||||
pgoff_t index);
|
||||
pgoff_t index,
|
||||
unsigned long num_ra_pages);
|
||||
|
||||
/**
|
||||
* Write a Merkle tree block to the given inode.
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef _UAPI_LINUX_FSCRYPT_H
|
||||
#define _UAPI_LINUX_FSCRYPT_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Encryption policy flags */
|
||||
@ -109,11 +110,22 @@ struct fscrypt_key_specifier {
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Payload of Linux keyring key of type "fscrypt-provisioning", referenced by
|
||||
* fscrypt_add_key_arg::key_id as an alternative to fscrypt_add_key_arg::raw.
|
||||
*/
|
||||
struct fscrypt_provisioning_key_payload {
|
||||
__u32 type;
|
||||
__u32 __reserved;
|
||||
__u8 raw[];
|
||||
};
|
||||
|
||||
/* Struct passed to FS_IOC_ADD_ENCRYPTION_KEY */
|
||||
struct fscrypt_add_key_arg {
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
__u32 raw_size;
|
||||
__u32 __reserved[8];
|
||||
__u32 key_id;
|
||||
__u32 __reserved[7];
|
||||
/* N.B.: "temporary" flag, not reserved upstream */
|
||||
#define __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED 0x00000001
|
||||
__u32 __flags;
|
||||
|
Loading…
Reference in New Issue
Block a user