Skip to content

Commit

Permalink
Merge tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fsc…
Browse files Browse the repository at this point in the history
…rypt/fscrypt

Pull fsverity updates from Eric Biggers:
 "Some cleanups for fs-verity:

   - Rename some names that have been causing confusion

   - Move structs needed for file signing to the UAPI header"

* tag 'fsverity-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
  fs-verity: move structs needed for file signing to UAPI header
  fs-verity: rename "file measurement" to "file digest"
  fs-verity: rename fsverity_signed_digest to fsverity_formatted_digest
  fs-verity: remove filenames from file comments
  • Loading branch information
torvalds committed Dec 14, 2020
2 parents 7c7fdaf + bde4933 commit 51895d5
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 101 deletions.
68 changes: 32 additions & 36 deletions Documentation/filesystems/fsverity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ 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.
the "fs-verity file digest", which is a hash that includes the Merkle
tree 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
Expand Down Expand Up @@ -177,9 +177,10 @@ FS_IOC_ENABLE_VERITY can fail with the following errors:
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.
The FS_IOC_MEASURE_VERITY ioctl retrieves the digest of a verity file.
The fs-verity file digest is a cryptographic digest that identifies
the file contents that are being enforced on reads; it is computed via
a Merkle tree and is different from a traditional full-file digest.

This ioctl takes in a pointer to a variable-length structure::

Expand All @@ -197,7 +198,7 @@ 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. 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.
Expand Down Expand Up @@ -257,25 +258,24 @@ non-verity one, with the following exceptions:
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`_.
file 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
============================
File digest 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.
Merkle tree to produce the digest 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.
compute fs-verity file digests itself, e.g. in order to sign files.

.. _fsverity_merkle_tree:

Expand Down Expand Up @@ -325,26 +325,22 @@ 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::
To solve this problem, the fs-verity file digest 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 */
__le32 __reserved_0x04; /* 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
===============================

Expand All @@ -359,20 +355,20 @@ kernel. Specifically, it adds support for:
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.
detached signature in DER format of the file's fs-verity digest.
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.
file's actual digest 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).
correctly signed digest 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`_::
fs-verity file digests must be signed in the following format, which
is similar to the structure used by `FS_IOC_MEASURE_VERITY`_::

struct fsverity_signed_digest {
struct fsverity_formatted_digest {
char magic[8]; /* must be "FSVerity" */
__le16 digest_algorithm;
__le16 digest_size;
Expand Down Expand Up @@ -421,8 +417,8 @@ 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.
the ciphertext. This is necessary in order to make the fs-verity file
digest 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
Expand Down Expand Up @@ -592,8 +588,8 @@ weren't already directly answered in other parts of this document.
: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`_.
the authenticity of the "fs-verity file digest", which
incorporates 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?
Expand Down
8 changes: 4 additions & 4 deletions fs/verity/enable.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/enable.c: ioctl to enable verity on a file
* Ioctl to enable verity on a file
*
* Copyright 2019 Google LLC
*/
Expand Down Expand Up @@ -398,9 +398,9 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
* Some pages of the file may have been evicted from pagecache after
* being used in the Merkle tree construction, then read into pagecache
* again by another process reading from the file concurrently. Since
* these pages didn't undergo verification against the file measurement
* which fs-verity now claims to be enforcing, we have to wipe the
* pagecache to ensure that all future reads are verified.
* these pages didn't undergo verification against the file digest which
* fs-verity now claims to be enforcing, we have to wipe the pagecache
* to ensure that all future reads are verified.
*/
filemap_write_and_wait(inode->i_mapping);
invalidate_inode_pages2(inode->i_mapping);
Expand Down
36 changes: 3 additions & 33 deletions fs/verity/fsverity_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,52 +67,22 @@ struct merkle_tree_params {
* When a verity file is first opened, an instance of this struct is allocated
* and stored in ->i_verity_info; it remains until the inode is evicted. It
* caches information about the Merkle tree that's needed to efficiently verify
* data read from the file. It also caches the file measurement. The Merkle
* tree pages themselves are not cached here, but the filesystem may cache them.
* data read from the file. It also caches the file digest. The Merkle tree
* pages themselves are not cached here, but the filesystem may cache them.
*/
struct fsverity_info {
struct merkle_tree_params tree_params;
u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE];
u8 measurement[FS_VERITY_MAX_DIGEST_SIZE];
u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE];
const struct inode *inode;
};

/*
* Merkle tree properties. The file measurement is the hash of this structure
* excluding the signature and with the sig_size field set to 0.
*/
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; /* size of signature in bytes; 0 if none */
__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 */
__u8 signature[]; /* optional PKCS#7 signature */
};

/* Arbitrary limit to bound the kmalloc() size. Can be changed. */
#define FS_VERITY_MAX_DESCRIPTOR_SIZE 16384

#define FS_VERITY_MAX_SIGNATURE_SIZE (FS_VERITY_MAX_DESCRIPTOR_SIZE - \
sizeof(struct fsverity_descriptor))

/*
* Format in which verity file measurements are signed. This is the same as
* 'struct fsverity_digest', except here some magic bytes are prepended to
* provide some context about what is being signed in case the same key is used
* for non-fsverity purposes, and here the fields have fixed endianness.
*/
struct fsverity_signed_digest {
char magic[8]; /* must be "FSVerity" */
__le16 digest_algorithm;
__le16 digest_size;
__u8 digest[];
};

/* hash_algs.c */

extern struct fsverity_hash_alg fsverity_hash_algs[];
Expand Down
2 changes: 1 addition & 1 deletion fs/verity/hash_algs.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/hash_algs.c: fs-verity hash algorithms
* fs-verity hash algorithms
*
* Copyright 2019 Google LLC
*/
Expand Down
2 changes: 1 addition & 1 deletion fs/verity/init.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/init.c: fs-verity module initialization and logging
* fs-verity module initialization and logging
*
* Copyright 2019 Google LLC
*/
Expand Down
12 changes: 6 additions & 6 deletions fs/verity/measure.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/measure.c: ioctl to get a verity file's measurement
* Ioctl to get a verity file's digest
*
* Copyright 2019 Google LLC
*/
Expand All @@ -10,12 +10,12 @@
#include <linux/uaccess.h>

/**
* fsverity_ioctl_measure() - get a verity file's measurement
* @filp: file to get measurement of
* fsverity_ioctl_measure() - get a verity file's digest
* @filp: file to get digest of
* @_uarg: user pointer to fsverity_digest
*
* Retrieve the file measurement that the kernel is enforcing for reads from a
* verity file. See the "FS_IOC_MEASURE_VERITY" section of
* Retrieve the file digest that the kernel is enforcing for reads from a verity
* file. See the "FS_IOC_MEASURE_VERITY" section of
* Documentation/filesystems/fsverity.rst for the documentation.
*
* Return: 0 on success, -errno on failure
Expand Down Expand Up @@ -51,7 +51,7 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
if (copy_to_user(uarg, &arg, sizeof(arg)))
return -EFAULT;

if (copy_to_user(uarg->digest, vi->measurement, hash_alg->digest_size))
if (copy_to_user(uarg->digest, vi->file_digest, hash_alg->digest_size))
return -EFAULT;

return 0;
Expand Down
24 changes: 12 additions & 12 deletions fs/verity/open.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/open.c: opening fs-verity files
* Opening fs-verity files
*
* Copyright 2019 Google LLC
*/
Expand Down Expand Up @@ -124,18 +124,18 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
}

/*
* Compute the file measurement by hashing the fsverity_descriptor excluding the
* Compute the file digest by hashing the fsverity_descriptor excluding the
* signature and with the sig_size field set to 0.
*/
static int compute_file_measurement(struct fsverity_hash_alg *hash_alg,
struct fsverity_descriptor *desc,
u8 *measurement)
static int compute_file_digest(struct fsverity_hash_alg *hash_alg,
struct fsverity_descriptor *desc,
u8 *file_digest)
{
__le32 sig_size = desc->sig_size;
int err;

desc->sig_size = 0;
err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), measurement);
err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest);
desc->sig_size = sig_size;

return err;
Expand Down Expand Up @@ -199,15 +199,15 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode,

memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size);

err = compute_file_measurement(vi->tree_params.hash_alg, desc,
vi->measurement);
err = compute_file_digest(vi->tree_params.hash_alg, desc,
vi->file_digest);
if (err) {
fsverity_err(inode, "Error %d computing file measurement", err);
fsverity_err(inode, "Error %d computing file digest", err);
goto out;
}
pr_debug("Computed file measurement: %s:%*phN\n",
pr_debug("Computed file digest: %s:%*phN\n",
vi->tree_params.hash_alg->name,
vi->tree_params.digest_size, vi->measurement);
vi->tree_params.digest_size, vi->file_digest);

err = fsverity_verify_signature(vi, desc, desc_size);
out:
Expand Down Expand Up @@ -354,7 +354,7 @@ int __init fsverity_init_info_cache(void)
{
fsverity_info_cachep = KMEM_CACHE_USERCOPY(fsverity_info,
SLAB_RECLAIM_ACCOUNT,
measurement);
file_digest);
if (!fsverity_info_cachep)
return -ENOMEM;
return 0;
Expand Down
14 changes: 7 additions & 7 deletions fs/verity/signature.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/signature.c: verification of builtin signatures
* Verification of builtin signatures
*
* Copyright 2019 Google LLC
*/
Expand Down Expand Up @@ -32,8 +32,8 @@ static struct key *fsverity_keyring;
* @desc: the file's fsverity_descriptor
* @desc_size: size of @desc
*
* If the file's fs-verity descriptor includes a signature of the file
* measurement, verify it against the certificates in the fs-verity keyring.
* If the file's fs-verity descriptor includes a signature of the file digest,
* verify it against the certificates in the fs-verity keyring.
*
* Return: 0 on success (signature valid or not required); -errno on failure
*/
Expand All @@ -44,7 +44,7 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
const struct inode *inode = vi->inode;
const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
const u32 sig_size = le32_to_cpu(desc->sig_size);
struct fsverity_signed_digest *d;
struct fsverity_formatted_digest *d;
int err;

if (sig_size == 0) {
Expand All @@ -67,7 +67,7 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
memcpy(d->magic, "FSVerity", 8);
d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
d->digest_size = cpu_to_le16(hash_alg->digest_size);
memcpy(d->digest, vi->measurement, hash_alg->digest_size);
memcpy(d->digest, vi->file_digest, hash_alg->digest_size);

err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
desc->signature, sig_size,
Expand All @@ -90,8 +90,8 @@ int fsverity_verify_signature(const struct fsverity_info *vi,
return err;
}

pr_debug("Valid signature for file measurement %s:%*phN\n",
hash_alg->name, hash_alg->digest_size, vi->measurement);
pr_debug("Valid signature for file digest %s:%*phN\n",
hash_alg->name, hash_alg->digest_size, vi->file_digest);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/verity/verify.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* fs/verity/verify.c: data verification functions, i.e. hooks for ->readpages()
* Data verification functions, i.e. hooks for ->readpages()
*
* Copyright 2019 Google LLC
*/
Expand Down
Loading

0 comments on commit 51895d5

Please sign in to comment.