mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-4.19.y' into android-4.19
* aosp/upstream-f2fs-stable-linux-4.19.y:
f2fs: add a condition to detect overflow in f2fs_ioc_gc_range()
f2fs: fix to add missing F2FS_IO_ALIGNED() condition
f2fs: fix to fallback to buffered IO in IO aligned mode
f2fs: fix to handle error path correctly in f2fs_map_blocks
f2fs: fix extent corrupotion during directIO in LFS mode
f2fs: check all the data segments against all node ones
f2fs: Add a small clarification to CONFIG_FS_F2FS_FS_SECURITY
f2fs: fix inode rwsem regression
f2fs: fix to avoid accessing uninitialized field of inode page in is_alive()
f2fs: avoid infinite GC loop due to stale atomic files
f2fs: Fix indefinite loop in f2fs_gc()
f2fs: convert inline_data in prior to i_size_write
f2fs: fix error path of f2fs_convert_inline_page()
f2fs: add missing documents of reserve_root/resuid/resgid
f2fs: fix flushing node pages when checkpoint is disabled
f2fs: enhance f2fs_is_checkpoint_ready()'s readability
f2fs: clean up __bio_alloc()'s parameter
f2fs: fix wrong error injection path in inc_valid_block_count()
f2fs: fix to writeout dirty inode during node flush
f2fs: optimize case-insensitive lookups
f2fs: introduce f2fs_match_name() for cleanup
f2fs: Fix indefinite loop in f2fs_gc()
f2fs: allocate memory in batch in build_sit_info()
f2fs: support FS_IOC_{GET,SET}FSLABEL
f2fs: fix to avoid data corruption by forbidding SSR overwrite
f2fs: Fix build error while CONFIG_NLS=m
Revert "f2fs: avoid out-of-range memory access"
f2fs: cleanup the code in build_sit_entries.
f2fs: fix wrong available node count calculation
f2fs: remove duplicate code in f2fs_file_write_iter
f2fs: fix to migrate blocks correctly during defragment
f2fs: use wrapped f2fs_cp_error()
f2fs: fix to use more generic EOPNOTSUPP
f2fs: use wrapped IS_SWAPFILE()
f2fs: Support case-insensitive file name lookups
f2fs: include charset encoding information in the superblock
fs: Reserve flag for casefolding
f2fs: fix to avoid call kvfree under spinlock
fs: f2fs: Remove unnecessary checks of SM_I(sbi) in update_general_status()
f2fs: disallow direct IO in atomic write
f2fs: fix to handle quota_{on,off} correctly
f2fs: fix to detect cp error in f2fs_setxattr()
f2fs: fix to spread f2fs_is_checkpoint_ready()
f2fs: support fiemap() for directory inode
f2fs: fix to avoid discard command leak
f2fs: fix to avoid tagging SBI_QUOTA_NEED_REPAIR incorrectly
f2fs: fix to drop meta/node pages during umount
f2fs: disallow switching io_bits option during remount
f2fs: fix panic of IO alignment feature
f2fs: introduce {page,io}_is_mergeable() for readability
f2fs: fix livelock in swapfile writes
f2fs: add fs-verity support
ext4: update on-disk format documentation for fs-verity
ext4: add fs-verity read support
ext4: add basic fs-verity support
fs-verity: support builtin file signatures
fs-verity: add SHA-512 support
fs-verity: implement FS_IOC_MEASURE_VERITY ioctl
fs-verity: implement FS_IOC_ENABLE_VERITY ioctl
fs-verity: add data verification hooks for ->readpages()
fs-verity: add the hook for file ->setattr()
fs-verity: add the hook for file ->open()
fs-verity: add inode and superblock fields
fs-verity: add Kconfig and the helper functions for hashing
fs: uapi: define verity bit for FS_IOC_GETFLAGS
fs-verity: add UAPI header
fs-verity: add MAINTAINERS file entry
fs-verity: add a documentation file
ext4: fix kernel oops caused by spurious casefold flag
ext4: fix coverity warning on error path of filename setup
ext4: optimize case-insensitive lookups
ext4: fix dcache lookup of !casefolded directories
unicode: update to Unicode 12.1.0 final
unicode: add missing check for an error return from utf8lookup()
ext4: export /sys/fs/ext4/feature/casefold if Unicode support is present
unicode: refactor the rule for regenerating utf8data.h
ext4: Support case-insensitive file name lookups
ext4: include charset encoding information in the superblock
unicode: update unicode database unicode version 12.1.0
unicode: introduce test module for normalized utf8 implementation
unicode: implement higher level API for string handling
unicode: reduce the size of utf8data[]
unicode: introduce code for UTF-8 normalization
unicode: introduce UTF-8 character database
ext4 crypto: fix to check feature status before get policy
fscrypt: document the new ioctls and policy version
ubifs: wire up new fscrypt ioctls
f2fs: wire up new fscrypt ioctls
ext4: wire up new fscrypt ioctls
fscrypt: require that key be added when setting a v2 encryption policy
fscrypt: add FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctl
fscrypt: allow unprivileged users to add/remove keys for v2 policies
fscrypt: v2 encryption policy support
fscrypt: add an HKDF-SHA512 implementation
fscrypt: add FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl
fscrypt: add FS_IOC_REMOVE_ENCRYPTION_KEY ioctl
fscrypt: add FS_IOC_ADD_ENCRYPTION_KEY ioctl
fscrypt: rename keyinfo.c to keysetup.c
fscrypt: move v1 policy key setup to keysetup_v1.c
fscrypt: refactor key setup code in preparation for v2 policies
fscrypt: rename fscrypt_master_key to fscrypt_direct_key
fscrypt: add ->ci_inode to fscrypt_info
fscrypt: use FSCRYPT_* definitions, not FS_*
fscrypt: use FSCRYPT_ prefix for uapi constants
fs, fscrypt: move uapi definitions to new header <linux/fscrypt.h>
fscrypt: use ENOPKG when crypto API support missing
fscrypt: improve warnings for missing crypto API support
fscrypt: improve warning messages for unsupported encryption contexts
fscrypt: make fscrypt_msg() take inode instead of super_block
fscrypt: clean up base64 encoding/decoding
fscrypt: remove loadable module related code
Conflicts:
fs/ext4/ioctl.c
fs/ext4/readpage.c
Bug: 141329812
Change-Id: I2e10c22a7c52982d073ac6897cc8aa4d5a811a38
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
This commit is contained in:
commit
c2ad33f029
90 changed files with 18137 additions and 1292 deletions
|
|
@ -251,3 +251,10 @@ Description:
|
|||
If checkpoint=disable, it displays the number of blocks that are unusable.
|
||||
If checkpoint=enable it displays the enumber of blocks that would be unusable
|
||||
if checkpoint=disable were to be set.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/encoding
|
||||
Date July 2019
|
||||
Contact: "Daniel Rosenberg" <drosen@google.com>
|
||||
Description:
|
||||
Displays name and version of the encoding set for the filesystem.
|
||||
If no encoding is set, displays (none)
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ mkprep
|
|||
mkregtable
|
||||
mktables
|
||||
mktree
|
||||
mkutf8data
|
||||
modpost
|
||||
modules.builtin
|
||||
modules.order
|
||||
|
|
@ -255,6 +256,7 @@ vsyscall_32.lds
|
|||
wanxlfw.inc
|
||||
uImage
|
||||
unifdef
|
||||
utf8data.h
|
||||
wakeup.bin
|
||||
wakeup.elf
|
||||
wakeup.lds
|
||||
|
|
|
|||
|
|
@ -24,3 +24,4 @@ order.
|
|||
.. include:: bigalloc.rst
|
||||
.. include:: inlinedata.rst
|
||||
.. include:: eainode.rst
|
||||
.. include:: verity.rst
|
||||
|
|
|
|||
41
Documentation/filesystems/ext4/verity.rst
Normal file
41
Documentation/filesystems/ext4/verity.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Verity files
|
||||
------------
|
||||
|
||||
ext4 supports fs-verity, which is a filesystem feature that provides
|
||||
Merkle tree based hashing for individual readonly files. Most of
|
||||
fs-verity is common to all filesystems that support it; see
|
||||
:ref:`Documentation/filesystems/fsverity.rst <fsverity>` for the
|
||||
fs-verity documentation. However, the on-disk layout of the verity
|
||||
metadata is filesystem-specific. On ext4, the verity metadata is
|
||||
stored after the end of the file data itself, in the following format:
|
||||
|
||||
- Zero-padding to the next 65536-byte boundary. This padding need not
|
||||
actually be allocated on-disk, i.e. it may be a hole.
|
||||
|
||||
- The Merkle tree, as documented in
|
||||
:ref:`Documentation/filesystems/fsverity.rst
|
||||
<fsverity_merkle_tree>`, with the tree levels stored in order from
|
||||
root to leaf, and the tree blocks within each level stored in their
|
||||
natural order.
|
||||
|
||||
- Zero-padding to the next filesystem block boundary.
|
||||
|
||||
- The verity descriptor, as documented in
|
||||
:ref:`Documentation/filesystems/fsverity.rst <fsverity_descriptor>`,
|
||||
with optionally appended signature blob.
|
||||
|
||||
- Zero-padding to the next offset that is 4 bytes before a filesystem
|
||||
block boundary.
|
||||
|
||||
- The size of the verity descriptor in bytes, as a 4-byte little
|
||||
endian integer.
|
||||
|
||||
Verity inodes have EXT4_VERITY_FL set, and they must use extents, i.e.
|
||||
EXT4_EXTENTS_FL must be set and EXT4_INLINE_DATA_FL must be clear.
|
||||
They can have EXT4_ENCRYPT_FL set, in which case the verity metadata
|
||||
is encrypted as well as the data itself.
|
||||
|
||||
Verity files cannot have blocks allocated past the end of the verity
|
||||
metadata.
|
||||
|
|
@ -157,6 +157,11 @@ noinline_data Disable the inline data feature, inline data feature is
|
|||
enabled by default.
|
||||
data_flush Enable data flushing before checkpoint in order to
|
||||
persist data of regular and symlink.
|
||||
reserve_root=%d Support configuring reserved space which is used for
|
||||
allocation from a privileged user with specified uid or
|
||||
gid, unit: 4KB, the default limit is 0.2% of user blocks.
|
||||
resuid=%d The user ID which may use the reserved blocks.
|
||||
resgid=%d The group ID which may use the reserved blocks.
|
||||
fault_injection=%d Enable fault injection in all supported types with
|
||||
specified injection rate.
|
||||
fault_type=%d Support configuring fault injection type, should be
|
||||
|
|
@ -413,6 +418,9 @@ Files in /sys/fs/f2fs/<devname>
|
|||
that would be unusable if checkpoint=disable were
|
||||
to be set.
|
||||
|
||||
encoding This shows the encoding used for casefolding.
|
||||
If casefolding is not enabled, returns (none)
|
||||
|
||||
================================================================================
|
||||
USAGE
|
||||
================================================================================
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ Online attacks
|
|||
fscrypt (and storage encryption in general) can only provide limited
|
||||
protection, if any at all, against online attacks. In detail:
|
||||
|
||||
Side-channel attacks
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
fscrypt is only resistant to side-channel attacks, such as timing or
|
||||
electromagnetic attacks, to the extent that the underlying Linux
|
||||
Cryptographic API algorithms are. If a vulnerable algorithm is used,
|
||||
|
|
@ -80,29 +83,90 @@ attacker to mount a side channel attack against the online system.
|
|||
Side channel attacks may also be mounted against applications
|
||||
consuming decrypted data.
|
||||
|
||||
After an encryption key has been provided, fscrypt is not designed to
|
||||
hide the plaintext file contents or filenames from other users on the
|
||||
same system, regardless of the visibility of the keyring key.
|
||||
Instead, existing access control mechanisms such as file mode bits,
|
||||
POSIX ACLs, LSMs, or mount namespaces should be used for this purpose.
|
||||
Also note that as long as the encryption keys are *anywhere* in
|
||||
memory, an online attacker can necessarily compromise them by mounting
|
||||
a physical attack or by exploiting any kernel security vulnerability
|
||||
which provides an arbitrary memory read primitive.
|
||||
Unauthorized file access
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While it is ostensibly possible to "evict" keys from the system,
|
||||
recently accessed encrypted files will remain accessible at least
|
||||
until the filesystem is unmounted or the VFS caches are dropped, e.g.
|
||||
using ``echo 2 > /proc/sys/vm/drop_caches``. Even after that, if the
|
||||
RAM is compromised before being powered off, it will likely still be
|
||||
possible to recover portions of the plaintext file contents, if not
|
||||
some of the encryption keys as well. (Since Linux v4.12, all
|
||||
in-kernel keys related to fscrypt are sanitized before being freed.
|
||||
However, userspace would need to do its part as well.)
|
||||
After an encryption key has been added, fscrypt does not hide the
|
||||
plaintext file contents or filenames from other users on the same
|
||||
system. Instead, existing access control mechanisms such as file mode
|
||||
bits, POSIX ACLs, LSMs, or namespaces should be used for this purpose.
|
||||
|
||||
Currently, fscrypt does not prevent a user from maliciously providing
|
||||
an incorrect key for another user's existing encrypted files. A
|
||||
protection against this is planned.
|
||||
(For the reasoning behind this, understand that while the key is
|
||||
added, the confidentiality of the data, from the perspective of the
|
||||
system itself, is *not* protected by the mathematical properties of
|
||||
encryption but rather only by the correctness of the kernel.
|
||||
Therefore, any encryption-specific access control checks would merely
|
||||
be enforced by kernel *code* and therefore would be largely redundant
|
||||
with the wide variety of access control mechanisms already available.)
|
||||
|
||||
Kernel memory compromise
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An attacker who compromises the system enough to read from arbitrary
|
||||
memory, e.g. by mounting a physical attack or by exploiting a kernel
|
||||
security vulnerability, can compromise all encryption keys that are
|
||||
currently in use.
|
||||
|
||||
However, fscrypt allows encryption keys to be removed from the kernel,
|
||||
which may protect them from later compromise.
|
||||
|
||||
In more detail, the FS_IOC_REMOVE_ENCRYPTION_KEY ioctl (or the
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS ioctl) can wipe a master
|
||||
encryption key from kernel memory. If it does so, it will also try to
|
||||
evict all cached inodes which had been "unlocked" using the key,
|
||||
thereby wiping their per-file keys and making them once again appear
|
||||
"locked", i.e. in ciphertext or encrypted form.
|
||||
|
||||
However, these ioctls have some limitations:
|
||||
|
||||
- Per-file keys for in-use files will *not* be removed or wiped.
|
||||
Therefore, for maximum effect, userspace should close the relevant
|
||||
encrypted files and directories before removing a master key, as
|
||||
well as kill any processes whose working directory is in an affected
|
||||
encrypted directory.
|
||||
|
||||
- The kernel cannot magically wipe copies of the master key(s) that
|
||||
userspace might have as well. Therefore, userspace must wipe all
|
||||
copies of the master key(s) it makes as well; normally this should
|
||||
be done immediately after FS_IOC_ADD_ENCRYPTION_KEY, without waiting
|
||||
for FS_IOC_REMOVE_ENCRYPTION_KEY. Naturally, the same also applies
|
||||
to all higher levels in the key hierarchy. Userspace should also
|
||||
follow other security precautions such as mlock()ing memory
|
||||
containing keys to prevent it from being swapped out.
|
||||
|
||||
- In general, decrypted contents and filenames in the kernel VFS
|
||||
caches are freed but not wiped. Therefore, portions thereof may be
|
||||
recoverable from freed memory, even after the corresponding key(s)
|
||||
were wiped. To partially solve this, you can set
|
||||
CONFIG_PAGE_POISONING=y in your kernel config and add page_poison=1
|
||||
to your kernel command line. However, this has a performance cost.
|
||||
|
||||
- Secret keys might still exist in CPU registers, in crypto
|
||||
accelerator hardware (if used by the crypto API to implement any of
|
||||
the algorithms), or in other places not explicitly considered here.
|
||||
|
||||
Limitations of v1 policies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
v1 encryption policies have some weaknesses with respect to online
|
||||
attacks:
|
||||
|
||||
- There is no verification that the provided master key is correct.
|
||||
Therefore, a malicious user can temporarily associate the wrong key
|
||||
with another user's encrypted files to which they have read-only
|
||||
access. Because of filesystem caching, the wrong key will then be
|
||||
used by the other user's accesses to those files, even if the other
|
||||
user has the correct key in their own keyring. This violates the
|
||||
meaning of "read-only access".
|
||||
|
||||
- A compromise of a per-file key also compromises the master key from
|
||||
which it was derived.
|
||||
|
||||
- Non-root users cannot securely remove encryption keys.
|
||||
|
||||
All the above problems are fixed with v2 encryption policies. For
|
||||
this reason among others, it is recommended to use v2 encryption
|
||||
policies on all new encrypted directories.
|
||||
|
||||
Key hierarchy
|
||||
=============
|
||||
|
|
@ -123,11 +187,52 @@ appropriate master key. There can be any number of master keys, each
|
|||
of which protects any number of directory trees on any number of
|
||||
filesystems.
|
||||
|
||||
Userspace should generate master keys either using a cryptographically
|
||||
secure random number generator, or by using a KDF (Key Derivation
|
||||
Function). Note that whenever a KDF is used to "stretch" a
|
||||
lower-entropy secret such as a passphrase, it is critical that a KDF
|
||||
designed for this purpose be used, such as scrypt, PBKDF2, or Argon2.
|
||||
Master keys must be real cryptographic keys, i.e. indistinguishable
|
||||
from random bytestrings of the same length. This implies that users
|
||||
**must not** directly use a password as a master key, zero-pad a
|
||||
shorter key, or repeat a shorter key. Security cannot be guaranteed
|
||||
if userspace makes any such error, as the cryptographic proofs and
|
||||
analysis would no longer apply.
|
||||
|
||||
Instead, users should generate master keys either using a
|
||||
cryptographically secure random number generator, or by using a KDF
|
||||
(Key Derivation Function). The kernel does not do any key stretching;
|
||||
therefore, if userspace derives the key from a low-entropy secret such
|
||||
as a passphrase, it is critical that a KDF designed for this purpose
|
||||
be used, such as scrypt, PBKDF2, or Argon2.
|
||||
|
||||
Key derivation function
|
||||
-----------------------
|
||||
|
||||
With one exception, fscrypt never uses the master key(s) for
|
||||
encryption directly. Instead, they are only used as input to a KDF
|
||||
(Key Derivation Function) to derive the actual keys.
|
||||
|
||||
The KDF used for a particular master key differs depending on whether
|
||||
the key is used for v1 encryption policies or for v2 encryption
|
||||
policies. Users **must not** use the same key for both v1 and v2
|
||||
encryption policies. (No real-world attack is currently known on this
|
||||
specific case of key reuse, but its security cannot be guaranteed
|
||||
since the cryptographic proofs and analysis would no longer apply.)
|
||||
|
||||
For v1 encryption policies, the KDF only supports deriving per-file
|
||||
encryption keys. It works by encrypting the master key with
|
||||
AES-128-ECB, using the file's 16-byte nonce as the AES key. The
|
||||
resulting ciphertext is used as the derived key. If the ciphertext is
|
||||
longer than needed, then it is truncated to the needed length.
|
||||
|
||||
For v2 encryption policies, the KDF is HKDF-SHA512. The master key is
|
||||
passed as the "input keying material", no salt is used, and a distinct
|
||||
"application-specific information string" is used for each distinct
|
||||
key to be derived. For example, when a per-file encryption key is
|
||||
derived, the application-specific information string is the file's
|
||||
nonce prefixed with "fscrypt\\0" and a context byte. Different
|
||||
context bytes are used for other types of derived keys.
|
||||
|
||||
HKDF-SHA512 is preferred to the original AES-128-ECB based KDF because
|
||||
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
|
||||
-------------
|
||||
|
|
@ -138,29 +243,9 @@ files doesn't map to the same ciphertext, or vice versa. In most
|
|||
cases, fscrypt does this by deriving per-file keys. When a new
|
||||
encrypted inode (regular file, directory, or symlink) is created,
|
||||
fscrypt randomly generates a 16-byte nonce and stores it in the
|
||||
inode's encryption xattr. Then, it uses a KDF (Key Derivation
|
||||
Function) to derive the file's key from the master key and nonce.
|
||||
|
||||
The Adiantum encryption mode (see `Encryption modes and usage`_) is
|
||||
special, since it accepts longer IVs and is suitable for both contents
|
||||
and filenames encryption. For it, a "direct key" option is offered
|
||||
where the file's nonce is included in the IVs and the master key is
|
||||
used for encryption directly. This improves performance; however,
|
||||
users must not use the same master key for any other encryption mode.
|
||||
|
||||
Below, the KDF and design considerations are described in more detail.
|
||||
|
||||
The current KDF works by encrypting the master key with AES-128-ECB,
|
||||
using the file's nonce as the AES key. The output is used as the
|
||||
derived key. If the output is longer than needed, then it is
|
||||
truncated to the needed length.
|
||||
|
||||
Note: this KDF meets the primary security requirement, which is to
|
||||
produce unique derived keys that preserve the entropy of the master
|
||||
key, assuming that the master key is already a good pseudorandom key.
|
||||
However, it is nonstandard and has some problems such as being
|
||||
reversible, so it is generally considered to be a mistake! It may be
|
||||
replaced with HKDF or another more standard KDF in the future.
|
||||
inode's encryption xattr. Then, it uses a KDF (as described in `Key
|
||||
derivation function`_) to derive the file's key from the master key
|
||||
and nonce.
|
||||
|
||||
Key derivation was chosen over key wrapping because wrapped keys would
|
||||
require larger xattrs which would be less likely to fit in-line in the
|
||||
|
|
@ -176,6 +261,37 @@ rejected as it would have prevented ext4 filesystems from being
|
|||
resized, and by itself still wouldn't have been sufficient to prevent
|
||||
the same key from being directly reused for both XTS and CTS-CBC.
|
||||
|
||||
DIRECT_KEY and per-mode keys
|
||||
----------------------------
|
||||
|
||||
The Adiantum encryption mode (see `Encryption modes and usage`_) is
|
||||
suitable for both contents and filenames encryption, and it accepts
|
||||
long IVs --- long enough to hold both an 8-byte logical block number
|
||||
and a 16-byte per-file nonce. Also, the overhead of each Adiantum key
|
||||
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:
|
||||
|
||||
- For v1 encryption policies, the encryption is done directly with the
|
||||
master key. Because of this, users **must not** use the same master
|
||||
key for any other purpose, even for other v1 policies.
|
||||
|
||||
- For v2 encryption policies, the encryption is done with a per-mode
|
||||
key derived using the KDF. Users may use the same master key for
|
||||
other v2 encryption policies.
|
||||
|
||||
Key identifiers
|
||||
---------------
|
||||
|
||||
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.
|
||||
|
||||
Encryption modes and usage
|
||||
==========================
|
||||
|
||||
|
|
@ -225,9 +341,10 @@ a little endian number, except that:
|
|||
is encrypted with AES-256 where the AES-256 key is the SHA-256 hash
|
||||
of the file's data encryption key.
|
||||
|
||||
- In the "direct key" configuration (FS_POLICY_FLAG_DIRECT_KEY set in
|
||||
the fscrypt_policy), the file's nonce is also appended to the IV.
|
||||
Currently this is only allowed with the Adiantum encryption mode.
|
||||
- In the "direct key" configuration (FSCRYPT_POLICY_FLAG_DIRECT_KEY
|
||||
set in the fscrypt_policy), the file's nonce is also appended to the
|
||||
IV. Currently this is only allowed with the Adiantum encryption
|
||||
mode.
|
||||
|
||||
Filenames encryption
|
||||
--------------------
|
||||
|
|
@ -269,49 +386,77 @@ User API
|
|||
Setting an encryption policy
|
||||
----------------------------
|
||||
|
||||
FS_IOC_SET_ENCRYPTION_POLICY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_SET_ENCRYPTION_POLICY ioctl sets an encryption policy on an
|
||||
empty directory or verifies that a directory or regular file already
|
||||
has the specified encryption policy. It takes in a pointer to a
|
||||
:c:type:`struct fscrypt_policy`, defined as follows::
|
||||
:c:type:`struct fscrypt_policy_v1` or a :c:type:`struct
|
||||
fscrypt_policy_v2`, defined as follows::
|
||||
|
||||
#define FS_KEY_DESCRIPTOR_SIZE 8
|
||||
|
||||
struct fscrypt_policy {
|
||||
#define FSCRYPT_POLICY_V1 0
|
||||
#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8
|
||||
struct fscrypt_policy_v1 {
|
||||
__u8 version;
|
||||
__u8 contents_encryption_mode;
|
||||
__u8 filenames_encryption_mode;
|
||||
__u8 flags;
|
||||
__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
__u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
|
||||
};
|
||||
#define fscrypt_policy fscrypt_policy_v1
|
||||
|
||||
#define FSCRYPT_POLICY_V2 2
|
||||
#define FSCRYPT_KEY_IDENTIFIER_SIZE 16
|
||||
struct fscrypt_policy_v2 {
|
||||
__u8 version;
|
||||
__u8 contents_encryption_mode;
|
||||
__u8 filenames_encryption_mode;
|
||||
__u8 flags;
|
||||
__u8 __reserved[4];
|
||||
__u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
|
||||
};
|
||||
|
||||
This structure must be initialized as follows:
|
||||
|
||||
- ``version`` must be 0.
|
||||
- ``version`` must be FSCRYPT_POLICY_V1 (0) if the struct is
|
||||
:c:type:`fscrypt_policy_v1` or FSCRYPT_POLICY_V2 (2) if the struct
|
||||
is :c:type:`fscrypt_policy_v2`. (Note: we refer to the original
|
||||
policy version as "v1", though its version code is really 0.) For
|
||||
new encrypted directories, use v2 policies.
|
||||
|
||||
- ``contents_encryption_mode`` and ``filenames_encryption_mode`` must
|
||||
be set to constants from ``<linux/fs.h>`` which identify the
|
||||
encryption modes to use. If unsure, use
|
||||
FS_ENCRYPTION_MODE_AES_256_XTS (1) for ``contents_encryption_mode``
|
||||
and FS_ENCRYPTION_MODE_AES_256_CTS (4) for
|
||||
``filenames_encryption_mode``.
|
||||
be set to constants from ``<linux/fscrypt.h>`` which identify the
|
||||
encryption modes to use. If unsure, use FSCRYPT_MODE_AES_256_XTS
|
||||
(1) for ``contents_encryption_mode`` and FSCRYPT_MODE_AES_256_CTS
|
||||
(4) for ``filenames_encryption_mode``.
|
||||
|
||||
- ``flags`` must contain a value from ``<linux/fs.h>`` which
|
||||
- ``flags`` must contain a value from ``<linux/fscrypt.h>`` which
|
||||
identifies the amount of NUL-padding to use when encrypting
|
||||
filenames. If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3).
|
||||
In addition, if the chosen encryption modes are both
|
||||
FS_ENCRYPTION_MODE_ADIANTUM, this can contain
|
||||
FS_POLICY_FLAG_DIRECT_KEY to specify that the master key should be
|
||||
used directly, without key derivation.
|
||||
filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 (0x3).
|
||||
Additionally, if the encryption modes are both
|
||||
FSCRYPT_MODE_ADIANTUM, this can contain
|
||||
FSCRYPT_POLICY_FLAG_DIRECT_KEY; see `DIRECT_KEY and per-mode keys`_.
|
||||
|
||||
- ``master_key_descriptor`` specifies how to find the master key in
|
||||
the keyring; see `Adding keys`_. It is up to userspace to choose a
|
||||
unique ``master_key_descriptor`` for each master key. The e4crypt
|
||||
and fscrypt tools use the first 8 bytes of
|
||||
- For v2 encryption policies, ``__reserved`` must be zeroed.
|
||||
|
||||
- For v1 encryption policies, ``master_key_descriptor`` specifies how
|
||||
to find the master key in a keyring; see `Adding keys`_. It is up
|
||||
to userspace to choose a unique ``master_key_descriptor`` for each
|
||||
master key. The e4crypt and fscrypt tools use the first 8 bytes of
|
||||
``SHA-512(SHA-512(master_key))``, but this particular scheme is not
|
||||
required. Also, the master key need not be in the keyring yet when
|
||||
FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added
|
||||
before any files can be created in the encrypted directory.
|
||||
|
||||
For v2 encryption policies, ``master_key_descriptor`` has been
|
||||
replaced with ``master_key_identifier``, which is longer and cannot
|
||||
be arbitrarily chosen. Instead, the key must first be added using
|
||||
`FS_IOC_ADD_ENCRYPTION_KEY`_. Then, the ``key_spec.u.identifier``
|
||||
the kernel returned in the :c:type:`struct fscrypt_add_key_arg` must
|
||||
be used as the ``master_key_identifier`` in the :c:type:`struct
|
||||
fscrypt_policy_v2`.
|
||||
|
||||
If the file is not yet encrypted, then FS_IOC_SET_ENCRYPTION_POLICY
|
||||
verifies that the file is an empty directory. If so, the specified
|
||||
encryption policy is assigned to the directory, turning it into an
|
||||
|
|
@ -327,6 +472,15 @@ policy exactly matches the actual one. If they match, then the ioctl
|
|||
returns 0. Otherwise, it fails with EEXIST. This works on both
|
||||
regular files and directories, including nonempty directories.
|
||||
|
||||
When a v2 encryption policy is assigned to a directory, it is also
|
||||
required that either the specified key has been added by the current
|
||||
user or that the caller has CAP_FOWNER in the initial user namespace.
|
||||
(This is needed to prevent a user from encrypting their data with
|
||||
another user's key.) The key must remain added while
|
||||
FS_IOC_SET_ENCRYPTION_POLICY is executing. However, if the new
|
||||
encrypted directory does not need to be accessed immediately, then the
|
||||
key can be removed right away afterwards.
|
||||
|
||||
Note that the ext4 filesystem does not allow the root directory to be
|
||||
encrypted, even if it is empty. Users who want to encrypt an entire
|
||||
filesystem with one key should consider using dm-crypt instead.
|
||||
|
|
@ -339,7 +493,11 @@ 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)
|
||||
version, mode(s), or flags; or reserved bits were set)
|
||||
- ``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
|
||||
namespace
|
||||
- ``ENOTDIR``: the file is unencrypted and is a regular file, not a
|
||||
directory
|
||||
- ``ENOTEMPTY``: the file is unencrypted and is a nonempty directory
|
||||
|
|
@ -358,25 +516,79 @@ FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors:
|
|||
Getting an encryption policy
|
||||
----------------------------
|
||||
|
||||
The FS_IOC_GET_ENCRYPTION_POLICY ioctl retrieves the :c:type:`struct
|
||||
fscrypt_policy`, if any, for a directory or regular file. See above
|
||||
for the struct definition. No additional permissions are required
|
||||
beyond the ability to open the file.
|
||||
Two ioctls are available to get a file's encryption policy:
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_POLICY can fail with the following errors:
|
||||
- `FS_IOC_GET_ENCRYPTION_POLICY_EX`_
|
||||
- `FS_IOC_GET_ENCRYPTION_POLICY`_
|
||||
|
||||
The extended (_EX) version of the ioctl is more general and is
|
||||
recommended to use when possible. However, on older kernels only the
|
||||
original ioctl is available. Applications should try the extended
|
||||
version, and if it fails with ENOTTY fall back to the original
|
||||
version.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_POLICY_EX
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_GET_ENCRYPTION_POLICY_EX ioctl retrieves the encryption
|
||||
policy, if any, for a directory or regular file. No additional
|
||||
permissions are required beyond the ability to open the file. It
|
||||
takes in a pointer to a :c:type:`struct fscrypt_get_policy_ex_arg`,
|
||||
defined as follows::
|
||||
|
||||
struct fscrypt_get_policy_ex_arg {
|
||||
__u64 policy_size; /* input/output */
|
||||
union {
|
||||
__u8 version;
|
||||
struct fscrypt_policy_v1 v1;
|
||||
struct fscrypt_policy_v2 v2;
|
||||
} policy; /* output */
|
||||
};
|
||||
|
||||
The caller must initialize ``policy_size`` to the size available for
|
||||
the policy struct, i.e. ``sizeof(arg.policy)``.
|
||||
|
||||
On success, the policy struct is returned in ``policy``, and its
|
||||
actual size is returned in ``policy_size``. ``policy.version`` should
|
||||
be checked to determine the version of policy returned. Note that the
|
||||
version code for the "v1" policy is actually 0 (FSCRYPT_POLICY_V1).
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_POLICY_EX can fail with the following errors:
|
||||
|
||||
- ``EINVAL``: the file is encrypted, but it uses an unrecognized
|
||||
encryption context format
|
||||
encryption policy version
|
||||
- ``ENODATA``: the file is not encrypted
|
||||
- ``ENOTTY``: this type of filesystem does not implement encryption
|
||||
- ``ENOTTY``: this type of filesystem does not implement encryption,
|
||||
or this kernel is too old to support FS_IOC_GET_ENCRYPTION_POLICY_EX
|
||||
(try FS_IOC_GET_ENCRYPTION_POLICY instead)
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with encryption
|
||||
support for this filesystem
|
||||
support for this filesystem, or the filesystem superblock has not
|
||||
had encryption enabled on it
|
||||
- ``EOVERFLOW``: the file is encrypted and uses a recognized
|
||||
encryption policy version, but the policy struct does not fit into
|
||||
the provided buffer
|
||||
|
||||
Note: if you only need to know whether a file is encrypted or not, on
|
||||
most filesystems it is also possible to use the FS_IOC_GETFLAGS ioctl
|
||||
and check for FS_ENCRYPT_FL, or to use the statx() system call and
|
||||
check for STATX_ATTR_ENCRYPTED in stx_attributes.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_POLICY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_GET_ENCRYPTION_POLICY ioctl can also retrieve the
|
||||
encryption policy, if any, for a directory or regular file. However,
|
||||
unlike `FS_IOC_GET_ENCRYPTION_POLICY_EX`_,
|
||||
FS_IOC_GET_ENCRYPTION_POLICY only supports the original policy
|
||||
version. It takes in a pointer directly to a :c:type:`struct
|
||||
fscrypt_policy_v1` rather than a :c:type:`struct
|
||||
fscrypt_get_policy_ex_arg`.
|
||||
|
||||
The error codes for FS_IOC_GET_ENCRYPTION_POLICY are the same as those
|
||||
for FS_IOC_GET_ENCRYPTION_POLICY_EX, except that
|
||||
FS_IOC_GET_ENCRYPTION_POLICY also returns ``EINVAL`` if the file is
|
||||
encrypted using a newer encryption policy version.
|
||||
|
||||
Getting the per-filesystem salt
|
||||
-------------------------------
|
||||
|
||||
|
|
@ -392,8 +604,115 @@ generate and manage any needed salt(s) in userspace.
|
|||
Adding keys
|
||||
-----------
|
||||
|
||||
To provide a master key, userspace must add it to an appropriate
|
||||
keyring using the add_key() system call (see:
|
||||
FS_IOC_ADD_ENCRYPTION_KEY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_ADD_ENCRYPTION_KEY ioctl adds a master encryption key to
|
||||
the filesystem, making all files on the filesystem which were
|
||||
encrypted using that key appear "unlocked", i.e. in plaintext form.
|
||||
It can be executed on any file or directory on the target filesystem,
|
||||
but using the filesystem's root directory is recommended. It takes in
|
||||
a pointer to a :c:type:`struct fscrypt_add_key_arg`, defined as
|
||||
follows::
|
||||
|
||||
struct fscrypt_add_key_arg {
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
__u32 raw_size;
|
||||
__u32 __reserved[9];
|
||||
__u8 raw[];
|
||||
};
|
||||
|
||||
#define FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR 1
|
||||
#define FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER 2
|
||||
|
||||
struct fscrypt_key_specifier {
|
||||
__u32 type; /* one of FSCRYPT_KEY_SPEC_TYPE_* */
|
||||
__u32 __reserved;
|
||||
union {
|
||||
__u8 __reserved[32]; /* reserve some extra space */
|
||||
__u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
|
||||
__u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
|
||||
} u;
|
||||
};
|
||||
|
||||
:c:type:`struct fscrypt_add_key_arg` must be zeroed, then initialized
|
||||
as follows:
|
||||
|
||||
- If the key is being added for use by v1 encryption policies, then
|
||||
``key_spec.type`` must contain FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR, and
|
||||
``key_spec.u.descriptor`` must contain the descriptor of the key
|
||||
being added, corresponding to the value in the
|
||||
``master_key_descriptor`` field of :c:type:`struct
|
||||
fscrypt_policy_v1`. To add this type of key, the calling process
|
||||
must have the CAP_SYS_ADMIN capability in the initial user
|
||||
namespace.
|
||||
|
||||
Alternatively, if the key is being added for use by v2 encryption
|
||||
policies, then ``key_spec.type`` must contain
|
||||
FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER, and ``key_spec.u.identifier`` is
|
||||
an *output* field which the kernel fills in with a cryptographic
|
||||
hash of the key. To add this type of key, the calling process does
|
||||
not need any privileges. However, the number of keys that can be
|
||||
added is limited by the user's quota for the keyrings service (see
|
||||
``Documentation/security/keys/core.rst``).
|
||||
|
||||
- ``raw_size`` must be the size of the ``raw`` key provided, in bytes.
|
||||
|
||||
- ``raw`` is a variable-length field which must contain the actual
|
||||
key, ``raw_size`` bytes long.
|
||||
|
||||
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
|
||||
removed by that user --- or by "root", if they use
|
||||
`FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS`_.
|
||||
|
||||
However, if another user has added the key, it may be desirable to
|
||||
prevent that other user from unexpectedly removing it. Therefore,
|
||||
FS_IOC_ADD_ENCRYPTION_KEY may also be used to add a v2 policy key
|
||||
*again*, even if it's already added by other user(s). In this case,
|
||||
FS_IOC_ADD_ENCRYPTION_KEY will just install a claim to the key for the
|
||||
current user, rather than actually add the key again (but the raw key
|
||||
must still be provided, as a proof of knowledge).
|
||||
|
||||
FS_IOC_ADD_ENCRYPTION_KEY returns 0 if either the key or a claim to
|
||||
the key was either added or already exists.
|
||||
|
||||
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
|
||||
- ``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
|
||||
- ``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
|
||||
had encryption enabled on it
|
||||
|
||||
Legacy method
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
For v1 encryption policies, a master encryption key can also be
|
||||
provided by adding it to a process-subscribed keyring, e.g. to a
|
||||
session keyring, or to a user keyring if the user keyring is linked
|
||||
into the session keyring.
|
||||
|
||||
This method is deprecated (and not supported for v2 encryption
|
||||
policies) for several reasons. First, it cannot be used in
|
||||
combination with FS_IOC_REMOVE_ENCRYPTION_KEY (see `Removing keys`_),
|
||||
so for removing a key a workaround such as keyctl_unlink() in
|
||||
combination with ``sync; echo 2 > /proc/sys/vm/drop_caches`` would
|
||||
have to be used. Second, it doesn't match the fact that the
|
||||
locked/unlocked status of encrypted files (i.e. whether they appear to
|
||||
be in plaintext form or in ciphertext form) is global. This mismatch
|
||||
has caused much confusion as well as real problems when processes
|
||||
running under different UIDs, such as a ``sudo`` command, need to
|
||||
access encrypted files.
|
||||
|
||||
Nevertheless, to add a key to one of the process-subscribed keyrings,
|
||||
the add_key() system call can be used (see:
|
||||
``Documentation/security/keys/core.rst``). The key type must be
|
||||
"logon"; keys of this type are kept in kernel memory and cannot be
|
||||
read back by userspace. The key description must be "fscrypt:"
|
||||
|
|
@ -401,12 +720,12 @@ followed by the 16-character lower case hex representation of the
|
|||
``master_key_descriptor`` that was set in the encryption policy. The
|
||||
key payload must conform to the following structure::
|
||||
|
||||
#define FS_MAX_KEY_SIZE 64
|
||||
#define FSCRYPT_MAX_KEY_SIZE 64
|
||||
|
||||
struct fscrypt_key {
|
||||
u32 mode;
|
||||
u8 raw[FS_MAX_KEY_SIZE];
|
||||
u32 size;
|
||||
__u32 mode;
|
||||
__u8 raw[FSCRYPT_MAX_KEY_SIZE];
|
||||
__u32 size;
|
||||
};
|
||||
|
||||
``mode`` is ignored; just set it to 0. The actual key is provided in
|
||||
|
|
@ -418,26 +737,194 @@ with a filesystem-specific prefix such as "ext4:". However, the
|
|||
filesystem-specific prefixes are deprecated and should not be used in
|
||||
new programs.
|
||||
|
||||
There are several different types of keyrings in which encryption keys
|
||||
may be placed, such as a session keyring, a user session keyring, or a
|
||||
user keyring. Each key must be placed in a keyring that is "attached"
|
||||
to all processes that might need to access files encrypted with it, in
|
||||
the sense that request_key() will find the key. Generally, if only
|
||||
processes belonging to a specific user need to access a given
|
||||
encrypted directory and no session keyring has been installed, then
|
||||
that directory's key should be placed in that user's user session
|
||||
keyring or user keyring. Otherwise, a session keyring should be
|
||||
installed if needed, and the key should be linked into that session
|
||||
keyring, or in a keyring linked into that session keyring.
|
||||
Removing keys
|
||||
-------------
|
||||
|
||||
Note: introducing the complex visibility semantics of keyrings here
|
||||
was arguably a mistake --- especially given that by design, after any
|
||||
process successfully opens an encrypted file (thereby setting up the
|
||||
per-file key), possessing the keyring key is not actually required for
|
||||
any process to read/write the file until its in-memory inode is
|
||||
evicted. In the future there probably should be a way to provide keys
|
||||
directly to the filesystem instead, which would make the intended
|
||||
semantics clearer.
|
||||
Two ioctls are available for removing a key that was added by
|
||||
`FS_IOC_ADD_ENCRYPTION_KEY`_:
|
||||
|
||||
- `FS_IOC_REMOVE_ENCRYPTION_KEY`_
|
||||
- `FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS`_
|
||||
|
||||
These two ioctls differ only in cases where v2 policy keys are added
|
||||
or removed by non-root users.
|
||||
|
||||
These ioctls don't work on keys that were added via the legacy
|
||||
process-subscribed keyrings mechanism.
|
||||
|
||||
Before using these ioctls, read the `Kernel memory compromise`_
|
||||
section for a discussion of the security goals and limitations of
|
||||
these ioctls.
|
||||
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_REMOVE_ENCRYPTION_KEY ioctl removes a claim to a master
|
||||
encryption key from the filesystem, and possibly removes the key
|
||||
itself. It can be executed on any file or directory on the target
|
||||
filesystem, but using the filesystem's root directory is recommended.
|
||||
It takes in a pointer to a :c:type:`struct fscrypt_remove_key_arg`,
|
||||
defined as follows::
|
||||
|
||||
struct fscrypt_remove_key_arg {
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
#define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY 0x00000001
|
||||
#define FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS 0x00000002
|
||||
__u32 removal_status_flags; /* output */
|
||||
__u32 __reserved[5];
|
||||
};
|
||||
|
||||
This structure must be zeroed, then initialized as follows:
|
||||
|
||||
- The key to remove is specified by ``key_spec``:
|
||||
|
||||
- To remove a key used by v1 encryption policies, set
|
||||
``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR and fill
|
||||
in ``key_spec.u.descriptor``. To remove this type of key, the
|
||||
calling process must have the CAP_SYS_ADMIN capability in the
|
||||
initial user namespace.
|
||||
|
||||
- To remove a key used by v2 encryption policies, set
|
||||
``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER and fill
|
||||
in ``key_spec.u.identifier``.
|
||||
|
||||
For v2 policy keys, this ioctl is usable by non-root users. However,
|
||||
to make this possible, it actually just removes the current user's
|
||||
claim to the key, undoing a single call to FS_IOC_ADD_ENCRYPTION_KEY.
|
||||
Only after all claims are removed is the key really removed.
|
||||
|
||||
For example, if FS_IOC_ADD_ENCRYPTION_KEY was called with uid 1000,
|
||||
then the key will be "claimed" by uid 1000, and
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY will only succeed as uid 1000. Or, if
|
||||
both uids 1000 and 2000 added the key, then for each uid
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY will only remove their own claim. Only
|
||||
once *both* are removed is the key really removed. (Think of it like
|
||||
unlinking a file that may have hard links.)
|
||||
|
||||
If FS_IOC_REMOVE_ENCRYPTION_KEY really removes the key, it will also
|
||||
try to "lock" all files that had been unlocked with the key. It won't
|
||||
lock files that are still in-use, so this ioctl is expected to be used
|
||||
in cooperation with userspace ensuring that none of the files are
|
||||
still open. However, if necessary, this ioctl can be executed again
|
||||
later to retry locking any remaining files.
|
||||
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY returns 0 if either the key was removed
|
||||
(but may still have files remaining to be locked), the user's claim to
|
||||
the key was removed, or the key was already removed but had files
|
||||
remaining to be the locked so the ioctl retried locking them. In any
|
||||
of these cases, ``removal_status_flags`` is filled in with the
|
||||
following informational status flags:
|
||||
|
||||
- ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY``: set if some file(s)
|
||||
are still in-use. Not guaranteed to be set in the case where only
|
||||
the user's claim to the key was removed.
|
||||
- ``FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS``: set if only the
|
||||
user's claim to the key was removed, not the key itself
|
||||
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY can fail with the following errors:
|
||||
|
||||
- ``EACCES``: The FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR key specifier type
|
||||
was specified, but the caller does not have the CAP_SYS_ADMIN
|
||||
capability in the initial user namespace
|
||||
- ``EINVAL``: invalid key specifier type, or reserved bits were set
|
||||
- ``ENOKEY``: the key object was not found at all, i.e. it was never
|
||||
added in the first place or was already fully removed including all
|
||||
files locked; or, the user does not have a claim to the key (but
|
||||
someone else does).
|
||||
- ``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
|
||||
had encryption enabled on it
|
||||
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS is exactly the same as
|
||||
`FS_IOC_REMOVE_ENCRYPTION_KEY`_, except that for v2 policy keys, the
|
||||
ALL_USERS version of the ioctl will remove all users' claims to the
|
||||
key, not just the current user's. I.e., the key itself will always be
|
||||
removed, no matter how many users have added it. This difference is
|
||||
only meaningful if non-root users are adding and removing keys.
|
||||
|
||||
Because of this, FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS also requires
|
||||
"root", namely the CAP_SYS_ADMIN capability in the initial user
|
||||
namespace. Otherwise it will fail with EACCES.
|
||||
|
||||
Getting key status
|
||||
------------------
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_KEY_STATUS
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The FS_IOC_GET_ENCRYPTION_KEY_STATUS ioctl retrieves the status of a
|
||||
master encryption key. It can be executed on any file or directory on
|
||||
the target filesystem, but using the filesystem's root directory is
|
||||
recommended. It takes in a pointer to a :c:type:`struct
|
||||
fscrypt_get_key_status_arg`, defined as follows::
|
||||
|
||||
struct fscrypt_get_key_status_arg {
|
||||
/* input */
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
__u32 __reserved[6];
|
||||
|
||||
/* output */
|
||||
#define FSCRYPT_KEY_STATUS_ABSENT 1
|
||||
#define FSCRYPT_KEY_STATUS_PRESENT 2
|
||||
#define FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED 3
|
||||
__u32 status;
|
||||
#define FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF 0x00000001
|
||||
__u32 status_flags;
|
||||
__u32 user_count;
|
||||
__u32 __out_reserved[13];
|
||||
};
|
||||
|
||||
The caller must zero all input fields, then fill in ``key_spec``:
|
||||
|
||||
- To get the status of a key for v1 encryption policies, set
|
||||
``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR and fill
|
||||
in ``key_spec.u.descriptor``.
|
||||
|
||||
- To get the status of a key for v2 encryption policies, set
|
||||
``key_spec.type`` to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER and fill
|
||||
in ``key_spec.u.identifier``.
|
||||
|
||||
On success, 0 is returned and the kernel fills in the output fields:
|
||||
|
||||
- ``status`` indicates whether the key is absent, present, or
|
||||
incompletely removed. Incompletely removed means that the master
|
||||
secret has been removed, but some files are still in use; i.e.,
|
||||
`FS_IOC_REMOVE_ENCRYPTION_KEY`_ returned 0 but set the informational
|
||||
status flag FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY.
|
||||
|
||||
- ``status_flags`` can contain the following flags:
|
||||
|
||||
- ``FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF`` indicates that the key
|
||||
has added by the current user. This is only set for keys
|
||||
identified by ``identifier`` rather than by ``descriptor``.
|
||||
|
||||
- ``user_count`` specifies the number of users who have added the key.
|
||||
This is only set for keys identified by ``identifier`` rather than
|
||||
by ``descriptor``.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_KEY_STATUS can fail with the following errors:
|
||||
|
||||
- ``EINVAL``: invalid key specifier type, or reserved bits were set
|
||||
- ``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
|
||||
had encryption enabled on it
|
||||
|
||||
Among other use cases, FS_IOC_GET_ENCRYPTION_KEY_STATUS can be useful
|
||||
for determining whether the key for a given encrypted directory needs
|
||||
to be added before prompting the user for the passphrase needed to
|
||||
derive the key.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_KEY_STATUS can only get the status of keys in
|
||||
the filesystem-level keyring, i.e. the keyring managed by
|
||||
`FS_IOC_ADD_ENCRYPTION_KEY`_ and `FS_IOC_REMOVE_ENCRYPTION_KEY`_. It
|
||||
cannot get the status of a key that has only been added for use by v1
|
||||
encryption policies using the legacy mechanism involving
|
||||
process-subscribed keyrings.
|
||||
|
||||
Access semantics
|
||||
================
|
||||
|
|
@ -500,7 +987,7 @@ Without the key
|
|||
|
||||
Some filesystem operations may be performed on encrypted regular
|
||||
files, directories, and symlinks even before their encryption key has
|
||||
been provided:
|
||||
been added, or after their encryption key has been removed:
|
||||
|
||||
- File metadata may be read, e.g. using stat().
|
||||
|
||||
|
|
@ -565,33 +1052,44 @@ Encryption context
|
|||
------------------
|
||||
|
||||
An encryption policy is represented on-disk by a :c:type:`struct
|
||||
fscrypt_context`. It is up to individual filesystems to decide where
|
||||
to store it, but normally it would be stored in a hidden extended
|
||||
attribute. It should *not* be exposed by the xattr-related system
|
||||
calls such as getxattr() and setxattr() because of the special
|
||||
semantics of the encryption xattr. (In particular, there would be
|
||||
much confusion if an encryption policy were to be added to or removed
|
||||
from anything other than an empty directory.) The struct is defined
|
||||
as follows::
|
||||
fscrypt_context_v1` or a :c:type:`struct fscrypt_context_v2`. It is
|
||||
up to individual filesystems to decide where to store it, but normally
|
||||
it would be stored in a hidden extended attribute. It should *not* be
|
||||
exposed by the xattr-related system calls such as getxattr() and
|
||||
setxattr() because of the special semantics of the encryption xattr.
|
||||
(In particular, there would be much confusion if an encryption policy
|
||||
were to be added to or removed from anything other than an empty
|
||||
directory.) These structs are defined as follows::
|
||||
|
||||
#define FS_KEY_DESCRIPTOR_SIZE 8
|
||||
#define FS_KEY_DERIVATION_NONCE_SIZE 16
|
||||
|
||||
struct fscrypt_context {
|
||||
u8 format;
|
||||
#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8
|
||||
struct fscrypt_context_v1 {
|
||||
u8 version;
|
||||
u8 contents_encryption_mode;
|
||||
u8 filenames_encryption_mode;
|
||||
u8 flags;
|
||||
u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
|
||||
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
};
|
||||
|
||||
Note that :c:type:`struct fscrypt_context` contains the same
|
||||
information as :c:type:`struct fscrypt_policy` (see `Setting an
|
||||
encryption policy`_), except that :c:type:`struct fscrypt_context`
|
||||
also contains a nonce. The nonce is randomly generated by the kernel
|
||||
and is used to derive the inode's encryption key as described in
|
||||
`Per-file keys`_.
|
||||
#define FSCRYPT_KEY_IDENTIFIER_SIZE 16
|
||||
struct fscrypt_context_v2 {
|
||||
u8 version;
|
||||
u8 contents_encryption_mode;
|
||||
u8 filenames_encryption_mode;
|
||||
u8 flags;
|
||||
u8 __reserved[4];
|
||||
u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
|
||||
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
};
|
||||
|
||||
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 and per-mode keys`_.
|
||||
|
||||
Data path changes
|
||||
-----------------
|
||||
|
|
|
|||
726
Documentation/filesystems/fsverity.rst
Normal file
726
Documentation/filesystems/fsverity.rst
Normal file
|
|
@ -0,0 +1,726 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _fsverity:
|
||||
|
||||
=======================================================
|
||||
fs-verity: read-only file-based authenticity protection
|
||||
=======================================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
fs-verity (``fs/verity/``) is a support layer that filesystems can
|
||||
hook into to support transparent integrity and authenticity protection
|
||||
of read-only files. Currently, it is supported by the ext4 and f2fs
|
||||
filesystems. Like fscrypt, not too much filesystem-specific code is
|
||||
needed to support fs-verity.
|
||||
|
||||
fs-verity is similar to `dm-verity
|
||||
<https://www.kernel.org/doc/Documentation/device-mapper/verity.txt>`_
|
||||
but works on files rather than block devices. On regular files on
|
||||
filesystems supporting fs-verity, userspace can execute an ioctl that
|
||||
causes the filesystem to build a Merkle tree for the file and persist
|
||||
it to a filesystem-specific location associated with the file.
|
||||
|
||||
After this, the file is made readonly, and all reads from the file are
|
||||
automatically verified against the file's Merkle tree. Reads of any
|
||||
corrupted data, including mmap reads, will fail.
|
||||
|
||||
Userspace can use another ioctl to retrieve the root hash (actually
|
||||
the "file measurement", which is a hash that includes the root hash)
|
||||
that fs-verity is enforcing for the file. This ioctl executes in
|
||||
constant time, regardless of the file size.
|
||||
|
||||
fs-verity is essentially a way to hash a file in constant time,
|
||||
subject to the caveat that reads which would violate the hash will
|
||||
fail at runtime.
|
||||
|
||||
Use cases
|
||||
=========
|
||||
|
||||
By itself, the base fs-verity feature only provides integrity
|
||||
protection, i.e. detection of accidental (non-malicious) corruption.
|
||||
|
||||
However, because fs-verity makes retrieving the file hash extremely
|
||||
efficient, it's primarily meant to be used as a tool to support
|
||||
authentication (detection of malicious modifications) or auditing
|
||||
(logging file hashes before use).
|
||||
|
||||
Trusted userspace code (e.g. operating system code running on a
|
||||
read-only partition that is itself authenticated by dm-verity) can
|
||||
authenticate the contents of an fs-verity file by using the
|
||||
`FS_IOC_MEASURE_VERITY`_ ioctl to retrieve its hash, then verifying a
|
||||
digital signature of it.
|
||||
|
||||
A standard file hash could be used instead of fs-verity. However,
|
||||
this is inefficient if the file is large and only a small portion may
|
||||
be accessed. This is often the case for Android application package
|
||||
(APK) files, for example. These typically contain many translations,
|
||||
classes, and other resources that are infrequently or even never
|
||||
accessed on a particular device. It would be slow and wasteful to
|
||||
read and hash the entire file before starting the application.
|
||||
|
||||
Unlike an ahead-of-time hash, fs-verity also re-verifies data each
|
||||
time it's paged in. This ensures that malicious disk firmware can't
|
||||
undetectably change the contents of the file at runtime.
|
||||
|
||||
fs-verity does not replace or obsolete dm-verity. dm-verity should
|
||||
still be used on read-only filesystems. fs-verity is for files that
|
||||
must live on a read-write filesystem because they are independently
|
||||
updated and potentially user-installed, so dm-verity cannot be used.
|
||||
|
||||
The base fs-verity feature is a hashing mechanism only; actually
|
||||
authenticating the files is up to userspace. However, to meet some
|
||||
users' needs, fs-verity optionally supports a simple signature
|
||||
verification mechanism where users can configure the kernel to require
|
||||
that all fs-verity files be signed by a key loaded into a keyring; see
|
||||
`Built-in signature verification`_. Support for fs-verity file hashes
|
||||
in IMA (Integrity Measurement Architecture) policies is also planned.
|
||||
|
||||
User API
|
||||
========
|
||||
|
||||
FS_IOC_ENABLE_VERITY
|
||||
--------------------
|
||||
|
||||
The FS_IOC_ENABLE_VERITY ioctl enables fs-verity on a file. It takes
|
||||
in a pointer to a :c:type:`struct fsverity_enable_arg`, defined as
|
||||
follows::
|
||||
|
||||
struct fsverity_enable_arg {
|
||||
__u32 version;
|
||||
__u32 hash_algorithm;
|
||||
__u32 block_size;
|
||||
__u32 salt_size;
|
||||
__u64 salt_ptr;
|
||||
__u32 sig_size;
|
||||
__u32 __reserved1;
|
||||
__u64 sig_ptr;
|
||||
__u64 __reserved2[11];
|
||||
};
|
||||
|
||||
This structure contains the parameters of the Merkle tree to build for
|
||||
the file, and optionally contains a signature. It must be initialized
|
||||
as follows:
|
||||
|
||||
- ``version`` must be 1.
|
||||
- ``hash_algorithm`` must be the identifier for the hash algorithm to
|
||||
use for the Merkle tree, such as FS_VERITY_HASH_ALG_SHA256. See
|
||||
``include/uapi/linux/fsverity.h`` for the list of possible values.
|
||||
- ``block_size`` must be the Merkle tree block size. Currently, this
|
||||
must be equal to the system page size, which is usually 4096 bytes.
|
||||
Other sizes may be supported in the future. This value is not
|
||||
necessarily the same as the filesystem block size.
|
||||
- ``salt_size`` is the size of the salt in bytes, or 0 if no salt is
|
||||
provided. The salt is a value that is prepended to every hashed
|
||||
block; it can be used to personalize the hashing for a particular
|
||||
file or device. Currently the maximum salt size is 32 bytes.
|
||||
- ``salt_ptr`` is the pointer to the salt, or NULL if no salt is
|
||||
provided.
|
||||
- ``sig_size`` is the size of the signature in bytes, or 0 if no
|
||||
signature is provided. Currently the signature is (somewhat
|
||||
arbitrarily) limited to 16128 bytes. See `Built-in signature
|
||||
verification`_ for more information.
|
||||
- ``sig_ptr`` is the pointer to the signature, or NULL if no
|
||||
signature is provided.
|
||||
- All reserved fields must be zeroed.
|
||||
|
||||
FS_IOC_ENABLE_VERITY causes the filesystem to build a Merkle tree for
|
||||
the file and persist it to a filesystem-specific location associated
|
||||
with the file, then mark the file as a verity file. This ioctl may
|
||||
take a long time to execute on large files, and it is interruptible by
|
||||
fatal signals.
|
||||
|
||||
FS_IOC_ENABLE_VERITY checks for write access to the inode. However,
|
||||
it must be executed on an O_RDONLY file descriptor and no processes
|
||||
can have the file open for writing. Attempts to open the file for
|
||||
writing while this ioctl is executing will fail with ETXTBSY. (This
|
||||
is necessary to guarantee that no writable file descriptors will exist
|
||||
after verity is enabled, and to guarantee that the file's contents are
|
||||
stable while the Merkle tree is being built over it.)
|
||||
|
||||
On success, FS_IOC_ENABLE_VERITY returns 0, and the file becomes a
|
||||
verity file. On failure (including the case of interruption by a
|
||||
fatal signal), no changes are made to the file.
|
||||
|
||||
FS_IOC_ENABLE_VERITY can fail with the following errors:
|
||||
|
||||
- ``EACCES``: the process does not have write access to the file
|
||||
- ``EBADMSG``: the signature is malformed
|
||||
- ``EBUSY``: this ioctl is already running on the file
|
||||
- ``EEXIST``: the file already has verity enabled
|
||||
- ``EFAULT``: the caller provided inaccessible memory
|
||||
- ``EINTR``: the operation was interrupted by a fatal signal
|
||||
- ``EINVAL``: unsupported version, hash algorithm, or block size; or
|
||||
reserved bits are set; or the file descriptor refers to neither a
|
||||
regular file nor a directory.
|
||||
- ``EISDIR``: the file descriptor refers to a directory
|
||||
- ``EKEYREJECTED``: the signature doesn't match the file
|
||||
- ``EMSGSIZE``: the salt or signature is too long
|
||||
- ``ENOKEY``: the fs-verity keyring doesn't contain the certificate
|
||||
needed to verify the signature
|
||||
- ``ENOPKG``: fs-verity recognizes the hash algorithm, but it's not
|
||||
available in the kernel's crypto API as currently configured (e.g.
|
||||
for SHA-512, missing CONFIG_CRYPTO_SHA512).
|
||||
- ``ENOTTY``: this type of filesystem does not implement fs-verity
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with fs-verity
|
||||
support; or the filesystem superblock has not had the 'verity'
|
||||
feature enabled on it; or the filesystem does not support fs-verity
|
||||
on this file. (See `Filesystem support`_.)
|
||||
- ``EPERM``: the file is append-only; or, a signature is required and
|
||||
one was not provided.
|
||||
- ``EROFS``: the filesystem is read-only
|
||||
- ``ETXTBSY``: someone has the file open for writing. This can be the
|
||||
caller's file descriptor, another open file descriptor, or the file
|
||||
reference held by a writable memory map.
|
||||
|
||||
FS_IOC_MEASURE_VERITY
|
||||
---------------------
|
||||
|
||||
The FS_IOC_MEASURE_VERITY ioctl retrieves the measurement of a verity
|
||||
file. The file measurement is a digest that cryptographically
|
||||
identifies the file contents that are being enforced on reads.
|
||||
|
||||
This ioctl takes in a pointer to a variable-length structure::
|
||||
|
||||
struct fsverity_digest {
|
||||
__u16 digest_algorithm;
|
||||
__u16 digest_size; /* input/output */
|
||||
__u8 digest[];
|
||||
};
|
||||
|
||||
``digest_size`` is an input/output field. On input, it must be
|
||||
initialized to the number of bytes allocated for the variable-length
|
||||
``digest`` field.
|
||||
|
||||
On success, 0 is returned and the kernel fills in the structure as
|
||||
follows:
|
||||
|
||||
- ``digest_algorithm`` will be the hash algorithm used for the file
|
||||
measurement. It will match ``fsverity_enable_arg::hash_algorithm``.
|
||||
- ``digest_size`` will be the size of the digest in bytes, e.g. 32
|
||||
for SHA-256. (This can be redundant with ``digest_algorithm``.)
|
||||
- ``digest`` will be the actual bytes of the digest.
|
||||
|
||||
FS_IOC_MEASURE_VERITY is guaranteed to execute in constant time,
|
||||
regardless of the size of the file.
|
||||
|
||||
FS_IOC_MEASURE_VERITY can fail with the following errors:
|
||||
|
||||
- ``EFAULT``: the caller provided inaccessible memory
|
||||
- ``ENODATA``: the file is not a verity file
|
||||
- ``ENOTTY``: this type of filesystem does not implement fs-verity
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with fs-verity
|
||||
support, or the filesystem superblock has not had the 'verity'
|
||||
feature enabled on it. (See `Filesystem support`_.)
|
||||
- ``EOVERFLOW``: the digest is longer than the specified
|
||||
``digest_size`` bytes. Try providing a larger buffer.
|
||||
|
||||
FS_IOC_GETFLAGS
|
||||
---------------
|
||||
|
||||
The existing ioctl FS_IOC_GETFLAGS (which isn't specific to fs-verity)
|
||||
can also be used to check whether a file has fs-verity enabled or not.
|
||||
To do so, check for FS_VERITY_FL (0x00100000) in the returned flags.
|
||||
|
||||
The verity flag is not settable via FS_IOC_SETFLAGS. You must use
|
||||
FS_IOC_ENABLE_VERITY instead, since parameters must be provided.
|
||||
|
||||
Accessing verity files
|
||||
======================
|
||||
|
||||
Applications can transparently access a verity file just like a
|
||||
non-verity one, with the following exceptions:
|
||||
|
||||
- Verity files are readonly. They cannot be opened for writing or
|
||||
truncate()d, even if the file mode bits allow it. Attempts to do
|
||||
one of these things will fail with EPERM. However, changes to
|
||||
metadata such as owner, mode, timestamps, and xattrs are still
|
||||
allowed, since these are not measured by fs-verity. Verity files
|
||||
can also still be renamed, deleted, and linked to.
|
||||
|
||||
- Direct I/O is not supported on verity files. Attempts to use direct
|
||||
I/O on such files will fall back to buffered I/O.
|
||||
|
||||
- DAX (Direct Access) is not supported on verity files, because this
|
||||
would circumvent the data verification.
|
||||
|
||||
- Reads of data that doesn't match the verity Merkle tree will fail
|
||||
with EIO (for read()) or SIGBUS (for mmap() reads).
|
||||
|
||||
- If the sysctl "fs.verity.require_signatures" is set to 1 and the
|
||||
file's verity measurement is not signed by a key in the fs-verity
|
||||
keyring, then opening the file will fail. See `Built-in signature
|
||||
verification`_.
|
||||
|
||||
Direct access to the Merkle tree is not supported. Therefore, if a
|
||||
verity file is copied, or is backed up and restored, then it will lose
|
||||
its "verity"-ness. fs-verity is primarily meant for files like
|
||||
executables that are managed by a package manager.
|
||||
|
||||
File measurement computation
|
||||
============================
|
||||
|
||||
This section describes how fs-verity hashes the file contents using a
|
||||
Merkle tree to produce the "file measurement" which cryptographically
|
||||
identifies the file contents. This algorithm is the same for all
|
||||
filesystems that support fs-verity.
|
||||
|
||||
Userspace only needs to be aware of this algorithm if it needs to
|
||||
compute the file measurement itself, e.g. in order to sign the file.
|
||||
|
||||
.. _fsverity_merkle_tree:
|
||||
|
||||
Merkle tree
|
||||
-----------
|
||||
|
||||
The file contents is divided into blocks, where the block size is
|
||||
configurable but is usually 4096 bytes. The end of the last block is
|
||||
zero-padded if needed. Each block is then hashed, producing the first
|
||||
level of hashes. Then, the hashes in this first level are grouped
|
||||
into 'blocksize'-byte blocks (zero-padding the ends as needed) and
|
||||
these blocks are hashed, producing the second level of hashes. This
|
||||
proceeds up the tree until only a single block remains. The hash of
|
||||
this block is the "Merkle tree root hash".
|
||||
|
||||
If the file fits in one block and is nonempty, then the "Merkle tree
|
||||
root hash" is simply the hash of the single data block. If the file
|
||||
is empty, then the "Merkle tree root hash" is all zeroes.
|
||||
|
||||
The "blocks" here are not necessarily the same as "filesystem blocks".
|
||||
|
||||
If a salt was specified, then it's zero-padded to the closest multiple
|
||||
of the input size of the hash algorithm's compression function, e.g.
|
||||
64 bytes for SHA-256 or 128 bytes for SHA-512. The padded salt is
|
||||
prepended to every data or Merkle tree block that is hashed.
|
||||
|
||||
The purpose of the block padding is to cause every hash to be taken
|
||||
over the same amount of data, which simplifies the implementation and
|
||||
keeps open more possibilities for hardware acceleration. The purpose
|
||||
of the salt padding is to make the salting "free" when the salted hash
|
||||
state is precomputed, then imported for each hash.
|
||||
|
||||
Example: in the recommended configuration of SHA-256 and 4K blocks,
|
||||
128 hash values fit in each block. Thus, each level of the Merkle
|
||||
tree is approximately 128 times smaller than the previous, and for
|
||||
large files the Merkle tree's size converges to approximately 1/127 of
|
||||
the original file size. However, for small files, the padding is
|
||||
significant, making the space overhead proportionally more.
|
||||
|
||||
.. _fsverity_descriptor:
|
||||
|
||||
fs-verity descriptor
|
||||
--------------------
|
||||
|
||||
By itself, the Merkle tree root hash is ambiguous. For example, it
|
||||
can't a distinguish a large file from a small second file whose data
|
||||
is exactly the top-level hash block of the first file. Ambiguities
|
||||
also arise from the convention of padding to the next block boundary.
|
||||
|
||||
To solve this problem, the verity file measurement is actually
|
||||
computed as a hash of the following structure, which contains the
|
||||
Merkle tree root hash as well as other fields such as the file size::
|
||||
|
||||
struct fsverity_descriptor {
|
||||
__u8 version; /* must be 1 */
|
||||
__u8 hash_algorithm; /* Merkle tree hash algorithm */
|
||||
__u8 log_blocksize; /* log2 of size of data and tree blocks */
|
||||
__u8 salt_size; /* size of salt in bytes; 0 if none */
|
||||
__le32 sig_size; /* must be 0 */
|
||||
__le64 data_size; /* size of file the Merkle tree is built over */
|
||||
__u8 root_hash[64]; /* Merkle tree root hash */
|
||||
__u8 salt[32]; /* salt prepended to each hashed block */
|
||||
__u8 __reserved[144]; /* must be 0's */
|
||||
};
|
||||
|
||||
Note that the ``sig_size`` field must be set to 0 for the purpose of
|
||||
computing the file measurement, even if a signature was provided (or
|
||||
will be provided) to `FS_IOC_ENABLE_VERITY`_.
|
||||
|
||||
Built-in signature verification
|
||||
===============================
|
||||
|
||||
With CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y, fs-verity supports putting
|
||||
a portion of an authentication policy (see `Use cases`_) in the
|
||||
kernel. Specifically, it adds support for:
|
||||
|
||||
1. At fs-verity module initialization time, a keyring ".fs-verity" is
|
||||
created. The root user can add trusted X.509 certificates to this
|
||||
keyring using the add_key() system call, then (when done)
|
||||
optionally use keyctl_restrict_keyring() to prevent additional
|
||||
certificates from being added.
|
||||
|
||||
2. `FS_IOC_ENABLE_VERITY`_ accepts a pointer to a PKCS#7 formatted
|
||||
detached signature in DER format of the file measurement. On
|
||||
success, this signature is persisted alongside the Merkle tree.
|
||||
Then, any time the file is opened, the kernel will verify the
|
||||
file's actual measurement against this signature, using the
|
||||
certificates in the ".fs-verity" keyring.
|
||||
|
||||
3. A new sysctl "fs.verity.require_signatures" is made available.
|
||||
When set to 1, the kernel requires that all verity files have a
|
||||
correctly signed file measurement as described in (2).
|
||||
|
||||
File measurements must be signed in the following format, which is
|
||||
similar to the structure used by `FS_IOC_MEASURE_VERITY`_::
|
||||
|
||||
struct fsverity_signed_digest {
|
||||
char magic[8]; /* must be "FSVerity" */
|
||||
__le16 digest_algorithm;
|
||||
__le16 digest_size;
|
||||
__u8 digest[];
|
||||
};
|
||||
|
||||
fs-verity's built-in signature verification support is meant as a
|
||||
relatively simple mechanism that can be used to provide some level of
|
||||
authenticity protection for verity files, as an alternative to doing
|
||||
the signature verification in userspace or using IMA-appraisal.
|
||||
However, with this mechanism, userspace programs still need to check
|
||||
that the verity bit is set, and there is no protection against verity
|
||||
files being swapped around.
|
||||
|
||||
Filesystem support
|
||||
==================
|
||||
|
||||
fs-verity is currently supported by the ext4 and f2fs filesystems.
|
||||
The CONFIG_FS_VERITY kconfig option must be enabled to use fs-verity
|
||||
on either filesystem.
|
||||
|
||||
``include/linux/fsverity.h`` declares the interface between the
|
||||
``fs/verity/`` support layer and filesystems. Briefly, filesystems
|
||||
must provide an ``fsverity_operations`` structure that provides
|
||||
methods to read and write the verity metadata to a filesystem-specific
|
||||
location, including the Merkle tree blocks and
|
||||
``fsverity_descriptor``. Filesystems must also call functions in
|
||||
``fs/verity/`` at certain times, such as when a file is opened or when
|
||||
pages have been read into the pagecache. (See `Verifying data`_.)
|
||||
|
||||
ext4
|
||||
----
|
||||
|
||||
ext4 supports fs-verity since Linux TODO and e2fsprogs v1.45.2.
|
||||
|
||||
To create verity files on an ext4 filesystem, the filesystem must have
|
||||
been formatted with ``-O verity`` or had ``tune2fs -O verity`` run on
|
||||
it. "verity" is an RO_COMPAT filesystem feature, so once set, old
|
||||
kernels will only be able to mount the filesystem readonly, and old
|
||||
versions of e2fsck will be unable to check the filesystem. Moreover,
|
||||
currently ext4 only supports mounting a filesystem with the "verity"
|
||||
feature when its block size is equal to PAGE_SIZE (often 4096 bytes).
|
||||
|
||||
ext4 sets the EXT4_VERITY_FL on-disk inode flag on verity files. It
|
||||
can only be set by `FS_IOC_ENABLE_VERITY`_, and it cannot be cleared.
|
||||
|
||||
ext4 also supports encryption, which can be used simultaneously with
|
||||
fs-verity. In this case, the plaintext data is verified rather than
|
||||
the ciphertext. This is necessary in order to make the file
|
||||
measurement meaningful, since every file is encrypted differently.
|
||||
|
||||
ext4 stores the verity metadata (Merkle tree and fsverity_descriptor)
|
||||
past the end of the file, starting at the first 64K boundary beyond
|
||||
i_size. This approach works because (a) verity files are readonly,
|
||||
and (b) pages fully beyond i_size aren't visible to userspace but can
|
||||
be read/written internally by ext4 with only some relatively small
|
||||
changes to ext4. This approach avoids having to depend on the
|
||||
EA_INODE feature and on rearchitecturing ext4's xattr support to
|
||||
support paging multi-gigabyte xattrs into memory, and to support
|
||||
encrypting xattrs. Note that the verity metadata *must* be encrypted
|
||||
when the file is, since it contains hashes of the plaintext data.
|
||||
|
||||
Currently, ext4 verity only supports the case where the Merkle tree
|
||||
block size, filesystem block size, and page size are all the same. It
|
||||
also only supports extent-based files.
|
||||
|
||||
f2fs
|
||||
----
|
||||
|
||||
f2fs supports fs-verity since Linux TODO and f2fs-tools v1.11.0.
|
||||
|
||||
To create verity files on an f2fs filesystem, the filesystem must have
|
||||
been formatted with ``-O verity``.
|
||||
|
||||
f2fs sets the FADVISE_VERITY_BIT on-disk inode flag on verity files.
|
||||
It can only be set by `FS_IOC_ENABLE_VERITY`_, and it cannot be
|
||||
cleared.
|
||||
|
||||
Like ext4, f2fs stores the verity metadata (Merkle tree and
|
||||
fsverity_descriptor) past the end of the file, starting at the first
|
||||
64K boundary beyond i_size. See explanation for ext4 above.
|
||||
Moreover, f2fs supports at most 4096 bytes of xattr entries per inode
|
||||
which wouldn't be enough for even a single Merkle tree block.
|
||||
|
||||
Currently, f2fs verity only supports a Merkle tree block size of 4096.
|
||||
Also, f2fs doesn't support enabling verity on files that currently
|
||||
have atomic or volatile writes pending.
|
||||
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
Verifying data
|
||||
--------------
|
||||
|
||||
fs-verity ensures that all reads of a verity file's data are verified,
|
||||
regardless of which syscall is used to do the read (e.g. mmap(),
|
||||
read(), pread()) and regardless of whether it's the first read or a
|
||||
later read (unless the later read can return cached data that was
|
||||
already verified). Below, we describe how filesystems implement this.
|
||||
|
||||
Pagecache
|
||||
~~~~~~~~~
|
||||
|
||||
For filesystems using Linux's pagecache, the ``->readpage()`` and
|
||||
``->readpages()`` methods must be modified to verify pages before they
|
||||
are marked Uptodate. Merely hooking ``->read_iter()`` would be
|
||||
insufficient, since ``->read_iter()`` is not used for memory maps.
|
||||
|
||||
Therefore, fs/verity/ provides a function fsverity_verify_page() which
|
||||
verifies a page that has been read into the pagecache of a verity
|
||||
inode, but is still locked and not Uptodate, so it's not yet readable
|
||||
by userspace. As needed to do the verification,
|
||||
fsverity_verify_page() will call back into the filesystem to read
|
||||
Merkle tree pages via fsverity_operations::read_merkle_tree_page().
|
||||
|
||||
fsverity_verify_page() returns false if verification failed; in this
|
||||
case, the filesystem must not set the page Uptodate. Following this,
|
||||
as per the usual Linux pagecache behavior, attempts by userspace to
|
||||
read() from the part of the file containing the page will fail with
|
||||
EIO, and accesses to the page within a memory map will raise SIGBUS.
|
||||
|
||||
fsverity_verify_page() currently only supports the case where the
|
||||
Merkle tree block size is equal to PAGE_SIZE (often 4096 bytes).
|
||||
|
||||
In principle, fsverity_verify_page() verifies the entire path in the
|
||||
Merkle tree from the data page to the root hash. However, for
|
||||
efficiency the filesystem may cache the hash pages. Therefore,
|
||||
fsverity_verify_page() only ascends the tree reading hash pages until
|
||||
an already-verified hash page is seen, as indicated by the PageChecked
|
||||
bit being set. It then verifies the path to that page.
|
||||
|
||||
This optimization, which is also used by dm-verity, results in
|
||||
excellent sequential read performance. This is because usually (e.g.
|
||||
127 in 128 times for 4K blocks and SHA-256) the hash page from the
|
||||
bottom level of the tree will already be cached and checked from
|
||||
reading a previous data page. However, random reads perform worse.
|
||||
|
||||
Block device based filesystems
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Block device based filesystems (e.g. ext4 and f2fs) in Linux also use
|
||||
the pagecache, so the above subsection applies too. However, they
|
||||
also usually read many pages from a file at once, grouped into a
|
||||
structure called a "bio". To make it easier for these types of
|
||||
filesystems to support fs-verity, fs/verity/ also provides a function
|
||||
fsverity_verify_bio() which verifies all pages in a bio.
|
||||
|
||||
ext4 and f2fs also support encryption. If a verity file is also
|
||||
encrypted, the pages must be decrypted before being verified. To
|
||||
support this, these filesystems allocate a "post-read context" for
|
||||
each bio and store it in ``->bi_private``::
|
||||
|
||||
struct bio_post_read_ctx {
|
||||
struct bio *bio;
|
||||
struct work_struct work;
|
||||
unsigned int cur_step;
|
||||
unsigned int enabled_steps;
|
||||
};
|
||||
|
||||
``enabled_steps`` is a bitmask that specifies whether decryption,
|
||||
verity, or both is enabled. After the bio completes, for each needed
|
||||
postprocessing step the filesystem enqueues the bio_post_read_ctx on a
|
||||
workqueue, and then the workqueue work does the decryption or
|
||||
verification. Finally, pages where no decryption or verity error
|
||||
occurred are marked Uptodate, and the pages are unlocked.
|
||||
|
||||
Files on ext4 and f2fs may contain holes. Normally, ``->readpages()``
|
||||
simply zeroes holes and sets the corresponding pages Uptodate; no bios
|
||||
are issued. To prevent this case from bypassing fs-verity, these
|
||||
filesystems use fsverity_verify_page() to verify hole pages.
|
||||
|
||||
ext4 and f2fs disable direct I/O on verity files, since otherwise
|
||||
direct I/O would bypass fs-verity. (They also do the same for
|
||||
encrypted files.)
|
||||
|
||||
Userspace utility
|
||||
=================
|
||||
|
||||
This document focuses on the kernel, but a userspace utility for
|
||||
fs-verity can be found at:
|
||||
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git
|
||||
|
||||
See the README.md file in the fsverity-utils source tree for details,
|
||||
including examples of setting up fs-verity protected files.
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
To test fs-verity, use xfstests. For example, using `kvm-xfstests
|
||||
<https://github.com/tytso/xfstests-bld/blob/master/Documentation/kvm-quickstart.md>`_::
|
||||
|
||||
kvm-xfstests -c ext4,f2fs -g verity
|
||||
|
||||
FAQ
|
||||
===
|
||||
|
||||
This section answers frequently asked questions about fs-verity that
|
||||
weren't already directly answered in other parts of this document.
|
||||
|
||||
:Q: Why isn't fs-verity part of IMA?
|
||||
:A: fs-verity and IMA (Integrity Measurement Architecture) have
|
||||
different focuses. fs-verity is a filesystem-level mechanism for
|
||||
hashing individual files using a Merkle tree. In contrast, IMA
|
||||
specifies a system-wide policy that specifies which files are
|
||||
hashed and what to do with those hashes, such as log them,
|
||||
authenticate them, or add them to a measurement list.
|
||||
|
||||
IMA is planned to support the fs-verity hashing mechanism as an
|
||||
alternative to doing full file hashes, for people who want the
|
||||
performance and security benefits of the Merkle tree based hash.
|
||||
But it doesn't make sense to force all uses of fs-verity to be
|
||||
through IMA. As a standalone filesystem feature, fs-verity
|
||||
already meets many users' needs, and it's testable like other
|
||||
filesystem features e.g. with xfstests.
|
||||
|
||||
:Q: Isn't fs-verity useless because the attacker can just modify the
|
||||
hashes in the Merkle tree, which is stored on-disk?
|
||||
:A: To verify the authenticity of an fs-verity file you must verify
|
||||
the authenticity of the "file measurement", which is basically the
|
||||
root hash of the Merkle tree. See `Use cases`_.
|
||||
|
||||
:Q: Isn't fs-verity useless because the attacker can just replace a
|
||||
verity file with a non-verity one?
|
||||
:A: See `Use cases`_. In the initial use case, it's really trusted
|
||||
userspace code that authenticates the files; fs-verity is just a
|
||||
tool to do this job efficiently and securely. The trusted
|
||||
userspace code will consider non-verity files to be inauthentic.
|
||||
|
||||
:Q: Why does the Merkle tree need to be stored on-disk? Couldn't you
|
||||
store just the root hash?
|
||||
:A: If the Merkle tree wasn't stored on-disk, then you'd have to
|
||||
compute the entire tree when the file is first accessed, even if
|
||||
just one byte is being read. This is a fundamental consequence of
|
||||
how Merkle tree hashing works. To verify a leaf node, you need to
|
||||
verify the whole path to the root hash, including the root node
|
||||
(the thing which the root hash is a hash of). But if the root
|
||||
node isn't stored on-disk, you have to compute it by hashing its
|
||||
children, and so on until you've actually hashed the entire file.
|
||||
|
||||
That defeats most of the point of doing a Merkle tree-based hash,
|
||||
since if you have to hash the whole file ahead of time anyway,
|
||||
then you could simply do sha256(file) instead. That would be much
|
||||
simpler, and a bit faster too.
|
||||
|
||||
It's true that an in-memory Merkle tree could still provide the
|
||||
advantage of verification on every read rather than just on the
|
||||
first read. However, it would be inefficient because every time a
|
||||
hash page gets evicted (you can't pin the entire Merkle tree into
|
||||
memory, since it may be very large), in order to restore it you
|
||||
again need to hash everything below it in the tree. This again
|
||||
defeats most of the point of doing a Merkle tree-based hash, since
|
||||
a single block read could trigger re-hashing gigabytes of data.
|
||||
|
||||
:Q: But couldn't you store just the leaf nodes and compute the rest?
|
||||
:A: See previous answer; this really just moves up one level, since
|
||||
one could alternatively interpret the data blocks as being the
|
||||
leaf nodes of the Merkle tree. It's true that the tree can be
|
||||
computed much faster if the leaf level is stored rather than just
|
||||
the data, but that's only because each level is less than 1% the
|
||||
size of the level below (assuming the recommended settings of
|
||||
SHA-256 and 4K blocks). For the exact same reason, by storing
|
||||
"just the leaf nodes" you'd already be storing over 99% of the
|
||||
tree, so you might as well simply store the whole tree.
|
||||
|
||||
:Q: Can the Merkle tree be built ahead of time, e.g. distributed as
|
||||
part of a package that is installed to many computers?
|
||||
:A: This isn't currently supported. It was part of the original
|
||||
design, but was removed to simplify the kernel UAPI and because it
|
||||
wasn't a critical use case. Files are usually installed once and
|
||||
used many times, and cryptographic hashing is somewhat fast on
|
||||
most modern processors.
|
||||
|
||||
:Q: Why doesn't fs-verity support writes?
|
||||
:A: Write support would be very difficult and would require a
|
||||
completely different design, so it's well outside the scope of
|
||||
fs-verity. Write support would require:
|
||||
|
||||
- A way to maintain consistency between the data and hashes,
|
||||
including all levels of hashes, since corruption after a crash
|
||||
(especially of potentially the entire file!) is unacceptable.
|
||||
The main options for solving this are data journalling,
|
||||
copy-on-write, and log-structured volume. But it's very hard to
|
||||
retrofit existing filesystems with new consistency mechanisms.
|
||||
Data journalling is available on ext4, but is very slow.
|
||||
|
||||
- Rebuilding the the Merkle tree after every write, which would be
|
||||
extremely inefficient. Alternatively, a different authenticated
|
||||
dictionary structure such as an "authenticated skiplist" could
|
||||
be used. However, this would be far more complex.
|
||||
|
||||
Compare it to dm-verity vs. dm-integrity. dm-verity is very
|
||||
simple: the kernel just verifies read-only data against a
|
||||
read-only Merkle tree. In contrast, dm-integrity supports writes
|
||||
but is slow, is much more complex, and doesn't actually support
|
||||
full-device authentication since it authenticates each sector
|
||||
independently, i.e. there is no "root hash". It doesn't really
|
||||
make sense for the same device-mapper target to support these two
|
||||
very different cases; the same applies to fs-verity.
|
||||
|
||||
:Q: Since verity files are immutable, why isn't the immutable bit set?
|
||||
:A: The existing "immutable" bit (FS_IMMUTABLE_FL) already has a
|
||||
specific set of semantics which not only make the file contents
|
||||
read-only, but also prevent the file from being deleted, renamed,
|
||||
linked to, or having its owner or mode changed. These extra
|
||||
properties are unwanted for fs-verity, so reusing the immutable
|
||||
bit isn't appropriate.
|
||||
|
||||
:Q: Why does the API use ioctls instead of setxattr() and getxattr()?
|
||||
:A: Abusing the xattr interface for basically arbitrary syscalls is
|
||||
heavily frowned upon by most of the Linux filesystem developers.
|
||||
An xattr should really just be an xattr on-disk, not an API to
|
||||
e.g. magically trigger construction of a Merkle tree.
|
||||
|
||||
:Q: Does fs-verity support remote filesystems?
|
||||
:A: Only ext4 and f2fs support is implemented currently, but in
|
||||
principle any filesystem that can store per-file verity metadata
|
||||
can support fs-verity, regardless of whether it's local or remote.
|
||||
Some filesystems may have fewer options of where to store the
|
||||
verity metadata; one possibility is to store it past the end of
|
||||
the file and "hide" it from userspace by manipulating i_size. The
|
||||
data verification functions provided by ``fs/verity/`` also assume
|
||||
that the filesystem uses the Linux pagecache, but both local and
|
||||
remote filesystems normally do so.
|
||||
|
||||
:Q: Why is anything filesystem-specific at all? Shouldn't fs-verity
|
||||
be implemented entirely at the VFS level?
|
||||
:A: There are many reasons why this is not possible or would be very
|
||||
difficult, including the following:
|
||||
|
||||
- To prevent bypassing verification, pages must not be marked
|
||||
Uptodate until they've been verified. Currently, each
|
||||
filesystem is responsible for marking pages Uptodate via
|
||||
``->readpages()``. Therefore, currently it's not possible for
|
||||
the VFS to do the verification on its own. Changing this would
|
||||
require significant changes to the VFS and all filesystems.
|
||||
|
||||
- It would require defining a filesystem-independent way to store
|
||||
the verity metadata. Extended attributes don't work for this
|
||||
because (a) the Merkle tree may be gigabytes, but many
|
||||
filesystems assume that all xattrs fit into a single 4K
|
||||
filesystem block, and (b) ext4 and f2fs encryption doesn't
|
||||
encrypt xattrs, yet the Merkle tree *must* be encrypted when the
|
||||
file contents are, because it stores hashes of the plaintext
|
||||
file contents.
|
||||
|
||||
So the verity metadata would have to be stored in an actual
|
||||
file. Using a separate file would be very ugly, since the
|
||||
metadata is fundamentally part of the file to be protected, and
|
||||
it could cause problems where users could delete the real file
|
||||
but not the metadata file or vice versa. On the other hand,
|
||||
having it be in the same file would break applications unless
|
||||
filesystems' notion of i_size were divorced from the VFS's,
|
||||
which would be complex and require changes to all filesystems.
|
||||
|
||||
- It's desirable that FS_IOC_ENABLE_VERITY uses the filesystem's
|
||||
transaction mechanism so that either the file ends up with
|
||||
verity enabled, or no changes were made. Allowing intermediate
|
||||
states to occur after a crash may cause problems.
|
||||
|
|
@ -359,3 +359,4 @@ encryption of files and directories.
|
|||
:maxdepth: 2
|
||||
|
||||
fscrypt
|
||||
fsverity
|
||||
|
|
|
|||
13
MAINTAINERS
13
MAINTAINERS
|
|
@ -5999,6 +5999,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt.git
|
|||
S: Supported
|
||||
F: fs/crypto/
|
||||
F: include/linux/fscrypt*.h
|
||||
F: include/uapi/linux/fscrypt.h
|
||||
F: Documentation/filesystems/fscrypt.rst
|
||||
|
||||
FSI-ATTACHED I2C DRIVER
|
||||
|
|
@ -6017,6 +6018,18 @@ S: Maintained
|
|||
F: fs/notify/
|
||||
F: include/linux/fsnotify*.h
|
||||
|
||||
FSVERITY: READ-ONLY FILE-BASED AUTHENTICITY PROTECTION
|
||||
M: Eric Biggers <ebiggers@kernel.org>
|
||||
M: Theodore Y. Ts'o <tytso@mit.edu>
|
||||
L: linux-fscrypt@vger.kernel.org
|
||||
Q: https://patchwork.kernel.org/project/linux-fscrypt/list/
|
||||
T: git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git fsverity
|
||||
S: Supported
|
||||
F: fs/verity/
|
||||
F: include/linux/fsverity.h
|
||||
F: include/uapi/linux/fsverity.h
|
||||
F: Documentation/filesystems/fsverity.rst
|
||||
|
||||
FUJITSU LAPTOP EXTRAS
|
||||
M: Jonathan Woithe <jwoithe@just42.net>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -396,7 +396,6 @@ CONFIG_HARDENED_USERCOPY=y
|
|||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_CRYPTO_ADIANTUM=y
|
||||
CONFIG_CRYPTO_MD4=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_LZ4=y
|
||||
CONFIG_CRYPTO_ZSTD=y
|
||||
CONFIG_CRYPTO_ANSI_CPRNG=y
|
||||
|
|
|
|||
|
|
@ -333,7 +333,6 @@ CONFIG_SECURITY_NETWORK=y
|
|||
CONFIG_HARDENED_USERCOPY=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_CRYPTO_ADIANTUM=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_LZ4=y
|
||||
CONFIG_CRYPTO_ZSTD=y
|
||||
CONFIG_CRYPTO_ANSI_CPRNG=y
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ config MANDATORY_FILE_LOCKING
|
|||
|
||||
source "fs/crypto/Kconfig"
|
||||
|
||||
source "fs/verity/Kconfig"
|
||||
|
||||
source "fs/notify/Kconfig"
|
||||
|
||||
source "fs/quota/Kconfig"
|
||||
|
|
@ -314,5 +316,6 @@ endif # NETWORK_FILESYSTEMS
|
|||
|
||||
source "fs/nls/Kconfig"
|
||||
source "fs/dlm/Kconfig"
|
||||
source "fs/unicode/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
|
|||
obj-$(CONFIG_AIO) += aio.o
|
||||
obj-$(CONFIG_FS_DAX) += dax.o
|
||||
obj-$(CONFIG_FS_ENCRYPTION) += crypto/
|
||||
obj-$(CONFIG_FS_VERITY) += verity/
|
||||
obj-$(CONFIG_FILE_LOCKING) += locks.o
|
||||
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
|
||||
obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
|
||||
|
|
@ -91,6 +92,7 @@ obj-$(CONFIG_EXPORTFS) += exportfs/
|
|||
obj-$(CONFIG_NFSD) += nfsd/
|
||||
obj-$(CONFIG_LOCKD) += lockd/
|
||||
obj-$(CONFIG_NLS) += nls/
|
||||
obj-$(CONFIG_UNICODE) += unicode/
|
||||
obj-$(CONFIG_SYSV_FS) += sysv/
|
||||
obj-$(CONFIG_CIFS) += cifs/
|
||||
obj-$(CONFIG_HPFS_FS) += hpfs/
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ config FS_ENCRYPTION
|
|||
select CRYPTO_ECB
|
||||
select CRYPTO_XTS
|
||||
select CRYPTO_CTS
|
||||
select CRYPTO_SHA512
|
||||
select CRYPTO_HMAC
|
||||
select KEYS
|
||||
help
|
||||
Enable encryption of files and directories. This
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
|
||||
|
||||
fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o
|
||||
fscrypto-y := crypto.o \
|
||||
fname.o \
|
||||
hkdf.o \
|
||||
hooks.o \
|
||||
keyring.o \
|
||||
keysetup.o \
|
||||
keysetup_v1.o \
|
||||
policy.o
|
||||
|
||||
fscrypto-$(CONFIG_BLOCK) += bio.o
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
|
|||
memset(iv, 0, ci->ci_mode->ivsize);
|
||||
iv->lblk_num = cpu_to_le64(lblk_num);
|
||||
|
||||
if (ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY)
|
||||
if (fscrypt_is_direct_key_policy(&ci->ci_policy))
|
||||
memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
|
||||
|
||||
if (ci->ci_essiv_tfm != NULL)
|
||||
|
|
@ -187,10 +187,8 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
|
|||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res) {
|
||||
fscrypt_err(inode->i_sb,
|
||||
"%scryption failed for inode %lu, block %llu: %d",
|
||||
(rw == FS_DECRYPT ? "de" : "en"),
|
||||
inode->i_ino, lblk_num, res);
|
||||
fscrypt_err(inode, "%scryption failed for block %llu: %d",
|
||||
(rw == FS_DECRYPT ? "De" : "En"), lblk_num, res);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -452,7 +450,7 @@ fail:
|
|||
return res;
|
||||
}
|
||||
|
||||
void fscrypt_msg(struct super_block *sb, const char *level,
|
||||
void fscrypt_msg(const struct inode *inode, const char *level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||
|
|
@ -466,8 +464,9 @@ void fscrypt_msg(struct super_block *sb, const char *level,
|
|||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
if (sb)
|
||||
printk("%sfscrypt (%s): %pV\n", level, sb->s_id, &vaf);
|
||||
if (inode)
|
||||
printk("%sfscrypt (%s, inode %lu): %pV\n",
|
||||
level, inode->i_sb->s_id, inode->i_ino, &vaf);
|
||||
else
|
||||
printk("%sfscrypt: %pV\n", level, &vaf);
|
||||
va_end(args);
|
||||
|
|
@ -478,6 +477,8 @@ void fscrypt_msg(struct super_block *sb, const char *level,
|
|||
*/
|
||||
static int __init fscrypt_init(void)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
/*
|
||||
* Use an unbound workqueue to allow bios to be decrypted in parallel
|
||||
* even when they happen to complete on the same CPU. This sacrifices
|
||||
|
|
@ -500,31 +501,19 @@ static int __init fscrypt_init(void)
|
|||
if (!fscrypt_info_cachep)
|
||||
goto fail_free_ctx;
|
||||
|
||||
err = fscrypt_init_keyring();
|
||||
if (err)
|
||||
goto fail_free_info;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_info:
|
||||
kmem_cache_destroy(fscrypt_info_cachep);
|
||||
fail_free_ctx:
|
||||
kmem_cache_destroy(fscrypt_ctx_cachep);
|
||||
fail_free_queue:
|
||||
destroy_workqueue(fscrypt_read_workqueue);
|
||||
fail:
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
module_init(fscrypt_init)
|
||||
|
||||
/**
|
||||
* fscrypt_exit() - Shutdown the fs encryption system
|
||||
*/
|
||||
static void __exit fscrypt_exit(void)
|
||||
{
|
||||
fscrypt_destroy();
|
||||
|
||||
if (fscrypt_read_workqueue)
|
||||
destroy_workqueue(fscrypt_read_workqueue);
|
||||
kmem_cache_destroy(fscrypt_ctx_cachep);
|
||||
kmem_cache_destroy(fscrypt_info_cachep);
|
||||
|
||||
fscrypt_essiv_cleanup();
|
||||
}
|
||||
module_exit(fscrypt_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
late_initcall(fscrypt_init)
|
||||
|
|
|
|||
|
|
@ -71,9 +71,7 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
|||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
fscrypt_err(inode->i_sb,
|
||||
"Filename encryption failed for inode %lu: %d",
|
||||
inode->i_ino, res);
|
||||
fscrypt_err(inode, "Filename encryption failed: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -117,9 +115,7 @@ static int fname_decrypt(struct inode *inode,
|
|||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
fscrypt_err(inode->i_sb,
|
||||
"Filename decryption failed for inode %lu: %d",
|
||||
inode->i_ino, res);
|
||||
fscrypt_err(inode, "Filename decryption failed: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -127,44 +123,45 @@ static int fname_decrypt(struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *lookup_table =
|
||||
static const char lookup_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
|
||||
|
||||
#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
|
||||
|
||||
/**
|
||||
* digest_encode() -
|
||||
* base64_encode() -
|
||||
*
|
||||
* Encodes the input digest using characters from the set [a-zA-Z0-9_+].
|
||||
* Encodes the input string using characters from the set [A-Za-z0-9+,].
|
||||
* The encoded string is roughly 4/3 times the size of the input string.
|
||||
*
|
||||
* Return: length of the encoded string
|
||||
*/
|
||||
static int digest_encode(const char *src, int len, char *dst)
|
||||
static int base64_encode(const u8 *src, int len, char *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
int i, bits = 0, ac = 0;
|
||||
char *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
ac += (((unsigned char) src[i]) << bits);
|
||||
for (i = 0; i < len; i++) {
|
||||
ac += src[i] << bits;
|
||||
bits += 8;
|
||||
do {
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
ac >>= 6;
|
||||
bits -= 6;
|
||||
} while (bits >= 6);
|
||||
i++;
|
||||
}
|
||||
if (bits)
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
return cp - dst;
|
||||
}
|
||||
|
||||
static int digest_decode(const char *src, int len, char *dst)
|
||||
static int base64_decode(const char *src, int len, u8 *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
int i, bits = 0, ac = 0;
|
||||
const char *p;
|
||||
char *cp = dst;
|
||||
u8 *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
for (i = 0; i < len; i++) {
|
||||
p = strchr(lookup_table, src[i]);
|
||||
if (p == NULL || src[i] == 0)
|
||||
return -2;
|
||||
|
|
@ -175,7 +172,6 @@ static int digest_decode(const char *src, int len, char *dst)
|
|||
ac >>= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ac)
|
||||
return -1;
|
||||
|
|
@ -185,8 +181,9 @@ static int digest_decode(const char *src, int len, char *dst)
|
|||
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
||||
u32 max_len, u32 *encrypted_len_ret)
|
||||
{
|
||||
int padding = 4 << (inode->i_crypt_info->ci_flags &
|
||||
FS_POLICY_FLAGS_PAD_MASK);
|
||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
int padding = 4 << (fscrypt_policy_flags(&ci->ci_policy) &
|
||||
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
||||
u32 encrypted_len;
|
||||
|
||||
if (orig_len > max_len)
|
||||
|
|
@ -272,7 +269,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
|
|||
return fname_decrypt(inode, iname, oname);
|
||||
|
||||
if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
|
||||
oname->len = digest_encode(iname->name, iname->len,
|
||||
oname->len = base64_encode(iname->name, iname->len,
|
||||
oname->name);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -287,7 +284,7 @@ int fscrypt_fname_disk_to_usr(struct inode *inode,
|
|||
FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
|
||||
FSCRYPT_FNAME_DIGEST_SIZE);
|
||||
oname->name[0] = '_';
|
||||
oname->len = 1 + digest_encode((const char *)&digested_name,
|
||||
oname->len = 1 + base64_encode((const u8 *)&digested_name,
|
||||
sizeof(digested_name), oname->name + 1);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -380,8 +377,8 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
if (fname->crypto_buf.name == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = digest_decode(iname->name + digested, iname->len - digested,
|
||||
fname->crypto_buf.name);
|
||||
ret = base64_decode(iname->name + digested, iname->len - digested,
|
||||
fname->crypto_buf.name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOENT;
|
||||
goto errout;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@
|
|||
*
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
*
|
||||
* This contains encryption key functions.
|
||||
*
|
||||
* Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
|
||||
* Originally written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar.
|
||||
* Heavily modified since then.
|
||||
*/
|
||||
|
||||
#ifndef _FSCRYPT_PRIVATE_H
|
||||
|
|
@ -15,30 +14,133 @@
|
|||
#include <linux/fscrypt.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
/* Encryption parameters */
|
||||
#define CONST_STRLEN(str) (sizeof(str) - 1)
|
||||
|
||||
#define FS_KEY_DERIVATION_NONCE_SIZE 16
|
||||
|
||||
/**
|
||||
* Encryption context for inode
|
||||
*
|
||||
* Protector format:
|
||||
* 1 byte: Protector format (1 = this version)
|
||||
* 1 byte: File contents encryption mode
|
||||
* 1 byte: File names encryption mode
|
||||
* 1 byte: Flags
|
||||
* 8 bytes: Master Key descriptor
|
||||
* 16 bytes: Encryption Key derivation nonce
|
||||
*/
|
||||
struct fscrypt_context {
|
||||
u8 format;
|
||||
#define FSCRYPT_MIN_KEY_SIZE 16
|
||||
|
||||
#define FSCRYPT_CONTEXT_V1 1
|
||||
#define FSCRYPT_CONTEXT_V2 2
|
||||
|
||||
struct fscrypt_context_v1 {
|
||||
u8 version; /* FSCRYPT_CONTEXT_V1 */
|
||||
u8 contents_encryption_mode;
|
||||
u8 filenames_encryption_mode;
|
||||
u8 flags;
|
||||
u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
|
||||
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
} __packed;
|
||||
};
|
||||
|
||||
#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
|
||||
struct fscrypt_context_v2 {
|
||||
u8 version; /* FSCRYPT_CONTEXT_V2 */
|
||||
u8 contents_encryption_mode;
|
||||
u8 filenames_encryption_mode;
|
||||
u8 flags;
|
||||
u8 __reserved[4];
|
||||
u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
|
||||
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* fscrypt_context - the encryption context of an inode
|
||||
*
|
||||
* This is the on-disk equivalent of an fscrypt_policy, stored alongside each
|
||||
* encrypted file usually in a hidden extended attribute. It contains the
|
||||
* fields from the fscrypt_policy, in order to identify the encryption algorithm
|
||||
* and key with which the file is encrypted. It also contains a nonce that was
|
||||
* randomly generated by fscrypt itself; this is used as KDF input or as a tweak
|
||||
* to cause different files to be encrypted differently.
|
||||
*/
|
||||
union fscrypt_context {
|
||||
u8 version;
|
||||
struct fscrypt_context_v1 v1;
|
||||
struct fscrypt_context_v2 v2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the size expected for the given fscrypt_context based on its version
|
||||
* number, or 0 if the context version is unrecognized.
|
||||
*/
|
||||
static inline int fscrypt_context_size(const union fscrypt_context *ctx)
|
||||
{
|
||||
switch (ctx->version) {
|
||||
case FSCRYPT_CONTEXT_V1:
|
||||
BUILD_BUG_ON(sizeof(ctx->v1) != 28);
|
||||
return sizeof(ctx->v1);
|
||||
case FSCRYPT_CONTEXT_V2:
|
||||
BUILD_BUG_ON(sizeof(ctx->v2) != 40);
|
||||
return sizeof(ctx->v2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef fscrypt_policy
|
||||
union fscrypt_policy {
|
||||
u8 version;
|
||||
struct fscrypt_policy_v1 v1;
|
||||
struct fscrypt_policy_v2 v2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the size expected for the given fscrypt_policy based on its version
|
||||
* number, or 0 if the policy version is unrecognized.
|
||||
*/
|
||||
static inline int fscrypt_policy_size(const union fscrypt_policy *policy)
|
||||
{
|
||||
switch (policy->version) {
|
||||
case FSCRYPT_POLICY_V1:
|
||||
return sizeof(policy->v1);
|
||||
case FSCRYPT_POLICY_V2:
|
||||
return sizeof(policy->v2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the contents encryption mode of a valid encryption policy */
|
||||
static inline u8
|
||||
fscrypt_policy_contents_mode(const union fscrypt_policy *policy)
|
||||
{
|
||||
switch (policy->version) {
|
||||
case FSCRYPT_POLICY_V1:
|
||||
return policy->v1.contents_encryption_mode;
|
||||
case FSCRYPT_POLICY_V2:
|
||||
return policy->v2.contents_encryption_mode;
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Return the filenames encryption mode of a valid encryption policy */
|
||||
static inline u8
|
||||
fscrypt_policy_fnames_mode(const union fscrypt_policy *policy)
|
||||
{
|
||||
switch (policy->version) {
|
||||
case FSCRYPT_POLICY_V1:
|
||||
return policy->v1.filenames_encryption_mode;
|
||||
case FSCRYPT_POLICY_V2:
|
||||
return policy->v2.filenames_encryption_mode;
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Return the flags (FSCRYPT_POLICY_FLAG*) of a valid encryption policy */
|
||||
static inline u8
|
||||
fscrypt_policy_flags(const union fscrypt_policy *policy)
|
||||
{
|
||||
switch (policy->version) {
|
||||
case FSCRYPT_POLICY_V1:
|
||||
return policy->v1.flags;
|
||||
case FSCRYPT_POLICY_V2:
|
||||
return policy->v2.flags;
|
||||
}
|
||||
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
|
||||
|
|
@ -68,23 +170,37 @@ struct fscrypt_info {
|
|||
struct crypto_cipher *ci_essiv_tfm;
|
||||
|
||||
/*
|
||||
* Encryption mode used for this inode. It corresponds to either
|
||||
* ci_data_mode or ci_filename_mode, depending on the inode type.
|
||||
* Encryption mode used for this inode. It corresponds to either the
|
||||
* contents or filenames encryption mode, depending on the inode type.
|
||||
*/
|
||||
struct fscrypt_mode *ci_mode;
|
||||
|
||||
/*
|
||||
* If non-NULL, then this inode uses a master key directly rather than a
|
||||
* derived key, and ci_ctfm will equal ci_master_key->mk_ctfm.
|
||||
* Otherwise, this inode uses a derived key.
|
||||
*/
|
||||
struct fscrypt_master_key *ci_master_key;
|
||||
/* Back-pointer to the inode */
|
||||
struct inode *ci_inode;
|
||||
|
||||
/* fields from the fscrypt_context */
|
||||
u8 ci_data_mode;
|
||||
u8 ci_filename_mode;
|
||||
u8 ci_flags;
|
||||
u8 ci_master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
/*
|
||||
* The master key with which this inode was unlocked (decrypted). This
|
||||
* will be NULL if the master key was found in a process-subscribed
|
||||
* keyring rather than in the filesystem-level keyring.
|
||||
*/
|
||||
struct key *ci_master_key;
|
||||
|
||||
/*
|
||||
* Link in list of inodes that were unlocked with the master key.
|
||||
* Only used when ->ci_master_key is set.
|
||||
*/
|
||||
struct list_head ci_master_key_link;
|
||||
|
||||
/*
|
||||
* If non-NULL, then encryption is done using the master key directly
|
||||
* and ci_ctfm will equal ci_direct_key->dk_ctfm.
|
||||
*/
|
||||
struct fscrypt_direct_key *ci_direct_key;
|
||||
|
||||
/* The encryption policy used by this inode */
|
||||
union fscrypt_policy ci_policy;
|
||||
|
||||
/* This inode's nonce, copied from the fscrypt_context */
|
||||
u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
};
|
||||
|
||||
|
|
@ -98,16 +214,16 @@ typedef enum {
|
|||
static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
u32 filenames_mode)
|
||||
{
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
|
||||
if (contents_mode == FSCRYPT_MODE_AES_128_CBC &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_128_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
|
||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||
filenames_mode == FSCRYPT_MODE_AES_256_CTS)
|
||||
return true;
|
||||
|
||||
if (contents_mode == FS_ENCRYPTION_MODE_ADIANTUM &&
|
||||
filenames_mode == FS_ENCRYPTION_MODE_ADIANTUM)
|
||||
if (contents_mode == FSCRYPT_MODE_ADIANTUM &&
|
||||
filenames_mode == FSCRYPT_MODE_ADIANTUM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -125,12 +241,12 @@ 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(struct super_block *sb, const char *level, const char *fmt, ...);
|
||||
fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...);
|
||||
|
||||
#define fscrypt_warn(sb, fmt, ...) \
|
||||
fscrypt_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
|
||||
#define fscrypt_err(sb, fmt, ...) \
|
||||
fscrypt_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
|
||||
#define fscrypt_warn(inode, fmt, ...) \
|
||||
fscrypt_msg((inode), KERN_WARNING, fmt, ##__VA_ARGS__)
|
||||
#define fscrypt_err(inode, fmt, ...) \
|
||||
fscrypt_msg((inode), KERN_ERR, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define FSCRYPT_MAX_IV_SIZE 32
|
||||
|
||||
|
|
@ -155,7 +271,172 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
|
|||
u32 orig_len, u32 max_len,
|
||||
u32 *encrypted_len_ret);
|
||||
|
||||
/* keyinfo.c */
|
||||
/* hkdf.c */
|
||||
|
||||
struct fscrypt_hkdf {
|
||||
struct crypto_shash *hmac_tfm;
|
||||
};
|
||||
|
||||
extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
|
||||
unsigned int master_key_size);
|
||||
|
||||
/*
|
||||
* The list of contexts in which fscrypt uses HKDF. These values are used as
|
||||
* the first byte of the HKDF application-specific info string to guarantee that
|
||||
* info strings are never repeated between contexts. This ensures that all HKDF
|
||||
* outputs are unique and cryptographically isolated, i.e. knowledge of one
|
||||
* output doesn't reveal another.
|
||||
*/
|
||||
#define HKDF_CONTEXT_KEY_IDENTIFIER 1
|
||||
#define HKDF_CONTEXT_PER_FILE_KEY 2
|
||||
#define HKDF_CONTEXT_PER_MODE_KEY 3
|
||||
|
||||
extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context,
|
||||
const u8 *info, unsigned int infolen,
|
||||
u8 *okm, unsigned int okmlen);
|
||||
|
||||
extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
|
||||
|
||||
/* keyring.c */
|
||||
|
||||
/*
|
||||
* fscrypt_master_key_secret - secret key material of an in-use master key
|
||||
*/
|
||||
struct fscrypt_master_key_secret {
|
||||
|
||||
/*
|
||||
* For v2 policy keys: HKDF context keyed by this master key.
|
||||
* For v1 policy keys: not set (hkdf.hmac_tfm == NULL).
|
||||
*/
|
||||
struct fscrypt_hkdf hkdf;
|
||||
|
||||
/* Size of the raw key in bytes. Set even if ->raw isn't set. */
|
||||
u32 size;
|
||||
|
||||
/* For v1 policy keys: the raw key. Wiped for v2 policy keys. */
|
||||
u8 raw[FSCRYPT_MAX_KEY_SIZE];
|
||||
|
||||
} __randomize_layout;
|
||||
|
||||
/*
|
||||
* fscrypt_master_key - an in-use master key
|
||||
*
|
||||
* This represents a master encryption key which has been added to the
|
||||
* filesystem and can be used to "unlock" the encrypted files which were
|
||||
* encrypted with it.
|
||||
*/
|
||||
struct fscrypt_master_key {
|
||||
|
||||
/*
|
||||
* The secret key material. After FS_IOC_REMOVE_ENCRYPTION_KEY is
|
||||
* executed, this is wiped and no new inodes can be unlocked with this
|
||||
* key; however, there may still be inodes in ->mk_decrypted_inodes
|
||||
* which could not be evicted. As long as some inodes still remain,
|
||||
* FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or
|
||||
* FS_IOC_ADD_ENCRYPTION_KEY can add the secret again.
|
||||
*
|
||||
* Locking: protected by key->sem (outer) and mk_secret_sem (inner).
|
||||
* The reason for two locks is that key->sem also protects modifying
|
||||
* mk_users, which ranks it above the semaphore for the keyring key
|
||||
* type, which is in turn above page faults (via keyring_read). But
|
||||
* sometimes filesystems call fscrypt_get_encryption_info() from within
|
||||
* a transaction, which ranks it below page faults. So we need a
|
||||
* separate lock which protects mk_secret but not also mk_users.
|
||||
*/
|
||||
struct fscrypt_master_key_secret mk_secret;
|
||||
struct rw_semaphore mk_secret_sem;
|
||||
|
||||
/*
|
||||
* For v1 policy keys: an arbitrary key descriptor which was assigned by
|
||||
* userspace (->descriptor).
|
||||
*
|
||||
* For v2 policy keys: a cryptographic hash of this key (->identifier).
|
||||
*/
|
||||
struct fscrypt_key_specifier mk_spec;
|
||||
|
||||
/*
|
||||
* Keyring which contains a key of type 'key_type_fscrypt_user' for each
|
||||
* user who has added this key. Normally each key will be added by just
|
||||
* one user, but it's possible that multiple users share a key, and in
|
||||
* that case we need to keep track of those users so that one user can't
|
||||
* remove the key before the others want it removed too.
|
||||
*
|
||||
* This is NULL for v1 policy keys; those can only be added by root.
|
||||
*
|
||||
* Locking: in addition to this keyrings own semaphore, this is
|
||||
* protected by the master key's key->sem, so we can do atomic
|
||||
* search+insert. It can also be searched without taking any locks, but
|
||||
* in that case the returned key may have already been removed.
|
||||
*/
|
||||
struct key *mk_users;
|
||||
|
||||
/*
|
||||
* Length of ->mk_decrypted_inodes, plus one if mk_secret is present.
|
||||
* Once this goes to 0, the master key is removed from ->s_master_keys.
|
||||
* The 'struct fscrypt_master_key' will continue to live as long as the
|
||||
* 'struct key' whose payload it is, but we won't let this reference
|
||||
* count rise again.
|
||||
*/
|
||||
refcount_t mk_refcount;
|
||||
|
||||
/*
|
||||
* List of inodes that were unlocked using this key. This allows the
|
||||
* inodes to be evicted efficiently if the key is removed.
|
||||
*/
|
||||
struct list_head mk_decrypted_inodes;
|
||||
spinlock_t mk_decrypted_inodes_lock;
|
||||
|
||||
/* Per-mode tfms for DIRECT_KEY policies, allocated on-demand */
|
||||
struct crypto_skcipher *mk_mode_keys[__FSCRYPT_MODE_MAX + 1];
|
||||
|
||||
} __randomize_layout;
|
||||
|
||||
static inline bool
|
||||
is_master_key_secret_present(const struct fscrypt_master_key_secret *secret)
|
||||
{
|
||||
/*
|
||||
* The READ_ONCE() is only necessary for fscrypt_drop_inode() and
|
||||
* fscrypt_key_describe(). These run in atomic context, so they can't
|
||||
* take ->mk_secret_sem and thus 'secret' can change concurrently which
|
||||
* would be a data race. But they only need to know whether the secret
|
||||
* *was* present at the time of check, so READ_ONCE() suffices.
|
||||
*/
|
||||
return READ_ONCE(secret->size) != 0;
|
||||
}
|
||||
|
||||
static inline const char *master_key_spec_type(
|
||||
const struct fscrypt_key_specifier *spec)
|
||||
{
|
||||
switch (spec->type) {
|
||||
case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
|
||||
return "descriptor";
|
||||
case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
|
||||
return "identifier";
|
||||
}
|
||||
return "[unknown]";
|
||||
}
|
||||
|
||||
static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
|
||||
{
|
||||
switch (spec->type) {
|
||||
case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
|
||||
return FSCRYPT_KEY_DESCRIPTOR_SIZE;
|
||||
case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
|
||||
return FSCRYPT_KEY_IDENTIFIER_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern struct key *
|
||||
fscrypt_find_master_key(struct super_block *sb,
|
||||
const struct fscrypt_key_specifier *mk_spec);
|
||||
|
||||
extern int fscrypt_verify_key_added(struct super_block *sb,
|
||||
const u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]);
|
||||
|
||||
extern int __init fscrypt_init_keyring(void);
|
||||
|
||||
/* keysetup.c */
|
||||
|
||||
struct fscrypt_mode {
|
||||
const char *friendly_name;
|
||||
|
|
@ -166,6 +447,36 @@ struct fscrypt_mode {
|
|||
bool needs_essiv;
|
||||
};
|
||||
|
||||
extern void __exit fscrypt_essiv_cleanup(void);
|
||||
static inline bool
|
||||
fscrypt_mode_supports_direct_key(const struct fscrypt_mode *mode)
|
||||
{
|
||||
return mode->ivsize >= offsetofend(union fscrypt_iv, nonce);
|
||||
}
|
||||
|
||||
extern struct crypto_skcipher *
|
||||
fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
|
||||
const struct inode *inode);
|
||||
|
||||
extern int fscrypt_set_derived_key(struct fscrypt_info *ci,
|
||||
const u8 *derived_key);
|
||||
|
||||
/* keysetup_v1.c */
|
||||
|
||||
extern void fscrypt_put_direct_key(struct fscrypt_direct_key *dk);
|
||||
|
||||
extern int fscrypt_setup_v1_file_key(struct fscrypt_info *ci,
|
||||
const u8 *raw_master_key);
|
||||
|
||||
extern int fscrypt_setup_v1_file_key_via_subscribed_keyrings(
|
||||
struct fscrypt_info *ci);
|
||||
/* policy.c */
|
||||
|
||||
extern bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
|
||||
const union fscrypt_policy *policy2);
|
||||
extern bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
|
||||
const struct inode *inode);
|
||||
extern int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
|
||||
const union fscrypt_context *ctx_u,
|
||||
int ctx_size);
|
||||
|
||||
#endif /* _FSCRYPT_PRIVATE_H */
|
||||
|
|
|
|||
183
fs/crypto/hkdf.c
Normal file
183
fs/crypto/hkdf.c
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Implementation of HKDF ("HMAC-based Extract-and-Expand Key Derivation
|
||||
* Function"), aka RFC 5869. See also the original paper (Krawczyk 2010):
|
||||
* "Cryptographic Extraction and Key Derivation: The HKDF Scheme".
|
||||
*
|
||||
* This is used to derive keys from the fscrypt master keys.
|
||||
*
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha.h>
|
||||
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
/*
|
||||
* HKDF supports any unkeyed cryptographic hash algorithm, but fscrypt uses
|
||||
* SHA-512 because it is reasonably secure and efficient; and since it produces
|
||||
* a 64-byte digest, deriving an AES-256-XTS key preserves all 64 bytes of
|
||||
* entropy from the master key and requires only one iteration of HKDF-Expand.
|
||||
*/
|
||||
#define HKDF_HMAC_ALG "hmac(sha512)"
|
||||
#define HKDF_HASHLEN SHA512_DIGEST_SIZE
|
||||
|
||||
/*
|
||||
* HKDF consists of two steps:
|
||||
*
|
||||
* 1. HKDF-Extract: extract a pseudorandom key of length HKDF_HASHLEN bytes from
|
||||
* the input keying material and optional salt.
|
||||
* 2. HKDF-Expand: expand the pseudorandom key into output keying material of
|
||||
* any length, parameterized by an application-specific info string.
|
||||
*
|
||||
* HKDF-Extract can be skipped if the input is already a pseudorandom key of
|
||||
* length HKDF_HASHLEN bytes. However, cipher modes other than AES-256-XTS take
|
||||
* shorter keys, and we don't want to force users of those modes to provide
|
||||
* unnecessarily long master keys. Thus fscrypt still does HKDF-Extract. No
|
||||
* salt is used, since fscrypt master keys should already be pseudorandom and
|
||||
* there's no way to persist a random salt per master key from kernel mode.
|
||||
*/
|
||||
|
||||
/* HKDF-Extract (RFC 5869 section 2.2), unsalted */
|
||||
static int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm,
|
||||
unsigned int ikmlen, u8 prk[HKDF_HASHLEN])
|
||||
{
|
||||
static const u8 default_salt[HKDF_HASHLEN];
|
||||
SHASH_DESC_ON_STACK(desc, hmac_tfm);
|
||||
int err;
|
||||
|
||||
err = crypto_shash_setkey(hmac_tfm, default_salt, HKDF_HASHLEN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
desc->tfm = hmac_tfm;
|
||||
desc->flags = 0;
|
||||
err = crypto_shash_digest(desc, ikm, ikmlen, prk);
|
||||
shash_desc_zero(desc);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute HKDF-Extract using the given master key as the input keying material,
|
||||
* and prepare an HMAC transform object keyed by the resulting pseudorandom key.
|
||||
*
|
||||
* Afterwards, the keyed HMAC transform object can be used for HKDF-Expand many
|
||||
* times without having to recompute HKDF-Extract each time.
|
||||
*/
|
||||
int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
|
||||
unsigned int master_key_size)
|
||||
{
|
||||
struct crypto_shash *hmac_tfm;
|
||||
u8 prk[HKDF_HASHLEN];
|
||||
int err;
|
||||
|
||||
hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, 0);
|
||||
if (IS_ERR(hmac_tfm)) {
|
||||
fscrypt_err(NULL, "Error allocating " HKDF_HMAC_ALG ": %ld",
|
||||
PTR_ERR(hmac_tfm));
|
||||
return PTR_ERR(hmac_tfm);
|
||||
}
|
||||
|
||||
if (WARN_ON(crypto_shash_digestsize(hmac_tfm) != sizeof(prk))) {
|
||||
err = -EINVAL;
|
||||
goto err_free_tfm;
|
||||
}
|
||||
|
||||
err = hkdf_extract(hmac_tfm, master_key, master_key_size, prk);
|
||||
if (err)
|
||||
goto err_free_tfm;
|
||||
|
||||
err = crypto_shash_setkey(hmac_tfm, prk, sizeof(prk));
|
||||
if (err)
|
||||
goto err_free_tfm;
|
||||
|
||||
hkdf->hmac_tfm = hmac_tfm;
|
||||
goto out;
|
||||
|
||||
err_free_tfm:
|
||||
crypto_free_shash(hmac_tfm);
|
||||
out:
|
||||
memzero_explicit(prk, sizeof(prk));
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* HKDF-Expand (RFC 5869 section 2.3). This expands the pseudorandom key, which
|
||||
* was already keyed into 'hkdf->hmac_tfm' by fscrypt_init_hkdf(), into 'okmlen'
|
||||
* bytes of output keying material parameterized by the application-specific
|
||||
* 'info' of length 'infolen' bytes, prefixed by "fscrypt\0" and the 'context'
|
||||
* byte. This is thread-safe and may be called by multiple threads in parallel.
|
||||
*
|
||||
* ('context' isn't part of the HKDF specification; it's just a prefix fscrypt
|
||||
* 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,
|
||||
const u8 *info, unsigned int infolen,
|
||||
u8 *okm, unsigned int okmlen)
|
||||
{
|
||||
SHASH_DESC_ON_STACK(desc, hkdf->hmac_tfm);
|
||||
u8 prefix[9];
|
||||
unsigned int i;
|
||||
int err;
|
||||
const u8 *prev = NULL;
|
||||
u8 counter = 1;
|
||||
u8 tmp[HKDF_HASHLEN];
|
||||
|
||||
if (WARN_ON(okmlen > 255 * HKDF_HASHLEN))
|
||||
return -EINVAL;
|
||||
|
||||
desc->tfm = hkdf->hmac_tfm;
|
||||
desc->flags = 0;
|
||||
|
||||
memcpy(prefix, "fscrypt\0", 8);
|
||||
prefix[8] = context;
|
||||
|
||||
for (i = 0; i < okmlen; i += HKDF_HASHLEN) {
|
||||
|
||||
err = crypto_shash_init(desc);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (prev) {
|
||||
err = crypto_shash_update(desc, prev, HKDF_HASHLEN);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = crypto_shash_update(desc, prefix, sizeof(prefix));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = crypto_shash_update(desc, info, infolen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
BUILD_BUG_ON(sizeof(counter) != 1);
|
||||
if (okmlen - i < HKDF_HASHLEN) {
|
||||
err = crypto_shash_finup(desc, &counter, 1, tmp);
|
||||
if (err)
|
||||
goto out;
|
||||
memcpy(&okm[i], tmp, okmlen - i);
|
||||
memzero_explicit(tmp, sizeof(tmp));
|
||||
} else {
|
||||
err = crypto_shash_finup(desc, &counter, 1, &okm[i]);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
counter++;
|
||||
prev = &okm[i];
|
||||
}
|
||||
err = 0;
|
||||
out:
|
||||
if (unlikely(err))
|
||||
memzero_explicit(okm, okmlen); /* so caller doesn't need to */
|
||||
shash_desc_zero(desc);
|
||||
return err;
|
||||
}
|
||||
|
||||
void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf)
|
||||
{
|
||||
crypto_free_shash(hkdf->hmac_tfm);
|
||||
}
|
||||
|
|
@ -38,9 +38,9 @@ int fscrypt_file_open(struct inode *inode, struct file *filp)
|
|||
dir = dget_parent(file_dentry(filp));
|
||||
if (IS_ENCRYPTED(d_inode(dir)) &&
|
||||
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
|
||||
fscrypt_warn(inode->i_sb,
|
||||
"inconsistent encryption contexts: %lu/%lu",
|
||||
d_inode(dir)->i_ino, inode->i_ino);
|
||||
fscrypt_warn(inode,
|
||||
"Inconsistent encryption context (parent directory: %lu)",
|
||||
d_inode(dir)->i_ino);
|
||||
err = -EPERM;
|
||||
}
|
||||
dput(dir);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue