2019-07-22 09:26:21 -07:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
|
|
* fs-verity: read-only file-based authenticity protection
|
|
|
|
*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _FSVERITY_PRIVATE_H
|
|
|
|
#define _FSVERITY_PRIVATE_H
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) "fs-verity: " fmt
|
|
|
|
|
2019-07-22 09:26:22 -07:00
|
|
|
#include <linux/fsverity.h>
|
2019-07-22 09:26:21 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Implementation limit: maximum depth of the Merkle tree. For now 8 is plenty;
|
|
|
|
* it's enough for over U64_MAX bytes of data using SHA-256 and 4K blocks.
|
|
|
|
*/
|
|
|
|
#define FS_VERITY_MAX_LEVELS 8
|
|
|
|
|
|
|
|
/* A hash algorithm supported by fs-verity */
|
|
|
|
struct fsverity_hash_alg {
|
fsverity: use shash API instead of ahash API
The "ahash" API, like the other scatterlist-based crypto APIs such as
"skcipher", comes with some well-known limitations. First, it can't
easily be used with vmalloc addresses. Second, the request struct can't
be allocated on the stack. This adds complexity and a possible failure
point that needs to be worked around, e.g. using a mempool.
The only benefit of ahash over "shash" is that ahash is needed to access
traditional memory-to-memory crypto accelerators, i.e. drivers/crypto/.
However, this style of crypto acceleration has largely fallen out of
favor and been superseded by CPU-based acceleration or inline crypto
engines. Also, ahash needs to be used asynchronously to take full
advantage of such hardware, but fs/verity/ has never done this.
On all systems that aren't actually using one of these ahash-only crypto
accelerators, ahash just adds unnecessary overhead as it sits between
the user and the underlying shash algorithms.
Also, XFS is planned to cache fsverity Merkle tree blocks in the
existing XFS buffer cache. As a result, it will be possible for a
single Merkle tree block to be split across discontiguous pages
(https://lore.kernel.org/r/20230405233753.GU3223426@dread.disaster.area).
This data will need to be hashed. It is easiest to work with a vmapped
address in this case. However, ahash is incompatible with this.
Therefore, let's convert fs/verity/ from ahash to shash. This
simplifies the code, and it should also slightly improve performance for
everyone who wasn't actually using one of these ahash-only crypto
accelerators, i.e. almost everyone (or maybe even everyone)!
Link: https://lore.kernel.org/r/20230516052306.99600-1-ebiggers@kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2023-05-15 22:12:16 -07:00
|
|
|
struct crypto_shash *tfm; /* hash tfm, allocated on demand */
|
2019-07-22 09:26:21 -07:00
|
|
|
const char *name; /* crypto API name, e.g. sha256 */
|
|
|
|
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
|
|
|
|
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
|
2022-11-28 21:51:39 -07:00
|
|
|
/*
|
|
|
|
* The HASH_ALGO_* constant for this algorithm. This is different from
|
|
|
|
* FS_VERITY_HASH_ALG_*, which uses a different numbering scheme.
|
|
|
|
*/
|
|
|
|
enum hash_algo algo_id;
|
2019-07-22 09:26:21 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
|
|
|
|
struct merkle_tree_params {
|
2023-06-03 19:23:48 -07:00
|
|
|
const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */
|
2019-07-22 09:26:21 -07:00
|
|
|
const u8 *hashstate; /* initial hash state or NULL */
|
|
|
|
unsigned int digest_size; /* same as hash_alg->digest_size */
|
|
|
|
unsigned int block_size; /* size of data and tree blocks */
|
|
|
|
unsigned int hashes_per_block; /* number of hashes per tree block */
|
2022-12-23 13:36:33 -07:00
|
|
|
unsigned int blocks_per_page; /* PAGE_SIZE / block_size */
|
2022-12-23 13:36:30 -07:00
|
|
|
u8 log_digestsize; /* log2(digest_size) */
|
|
|
|
u8 log_blocksize; /* log2(block_size) */
|
|
|
|
u8 log_arity; /* log2(hashes_per_block) */
|
2022-12-23 13:36:33 -07:00
|
|
|
u8 log_blocks_per_page; /* log2(blocks_per_page) */
|
2019-07-22 09:26:21 -07:00
|
|
|
unsigned int num_levels; /* number of levels in Merkle tree */
|
|
|
|
u64 tree_size; /* Merkle tree size in bytes */
|
2022-12-23 13:36:29 -07:00
|
|
|
unsigned long tree_pages; /* Merkle tree size in pages */
|
2019-07-22 09:26:21 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Starting block index for each tree level, ordered from leaf level (0)
|
|
|
|
* to root level ('num_levels - 1')
|
|
|
|
*/
|
2022-12-23 13:36:28 -07:00
|
|
|
unsigned long level_start[FS_VERITY_MAX_LEVELS];
|
2019-07-22 09:26:21 -07:00
|
|
|
};
|
|
|
|
|
2020-05-11 12:21:17 -07:00
|
|
|
/*
|
2019-07-22 09:26:22 -07:00
|
|
|
* fsverity_info - cached verity metadata for an inode
|
|
|
|
*
|
|
|
|
* 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
|
2020-11-13 14:19:17 -07:00
|
|
|
* 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.
|
2019-07-22 09:26:22 -07:00
|
|
|
*/
|
|
|
|
struct fsverity_info {
|
|
|
|
struct merkle_tree_params tree_params;
|
|
|
|
u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE];
|
2020-11-13 14:19:17 -07:00
|
|
|
u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE];
|
2019-07-22 09:26:22 -07:00
|
|
|
const struct inode *inode;
|
2022-12-23 13:36:33 -07:00
|
|
|
unsigned long *hash_block_verified;
|
2019-07-22 09:26:22 -07:00
|
|
|
};
|
|
|
|
|
2019-07-22 09:26:23 -07:00
|
|
|
#define FS_VERITY_MAX_SIGNATURE_SIZE (FS_VERITY_MAX_DESCRIPTOR_SIZE - \
|
|
|
|
sizeof(struct fsverity_descriptor))
|
|
|
|
|
2019-07-22 09:26:21 -07:00
|
|
|
/* hash_algs.c */
|
|
|
|
|
|
|
|
extern struct fsverity_hash_alg fsverity_hash_algs[];
|
|
|
|
|
2023-06-03 19:23:48 -07:00
|
|
|
const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode,
|
|
|
|
unsigned int num);
|
|
|
|
const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg,
|
2019-07-22 09:26:21 -07:00
|
|
|
const u8 *salt, size_t salt_size);
|
2022-12-23 13:36:32 -07:00
|
|
|
int fsverity_hash_block(const struct merkle_tree_params *params,
|
fsverity: use shash API instead of ahash API
The "ahash" API, like the other scatterlist-based crypto APIs such as
"skcipher", comes with some well-known limitations. First, it can't
easily be used with vmalloc addresses. Second, the request struct can't
be allocated on the stack. This adds complexity and a possible failure
point that needs to be worked around, e.g. using a mempool.
The only benefit of ahash over "shash" is that ahash is needed to access
traditional memory-to-memory crypto accelerators, i.e. drivers/crypto/.
However, this style of crypto acceleration has largely fallen out of
favor and been superseded by CPU-based acceleration or inline crypto
engines. Also, ahash needs to be used asynchronously to take full
advantage of such hardware, but fs/verity/ has never done this.
On all systems that aren't actually using one of these ahash-only crypto
accelerators, ahash just adds unnecessary overhead as it sits between
the user and the underlying shash algorithms.
Also, XFS is planned to cache fsverity Merkle tree blocks in the
existing XFS buffer cache. As a result, it will be possible for a
single Merkle tree block to be split across discontiguous pages
(https://lore.kernel.org/r/20230405233753.GU3223426@dread.disaster.area).
This data will need to be hashed. It is easiest to work with a vmapped
address in this case. However, ahash is incompatible with this.
Therefore, let's convert fs/verity/ from ahash to shash. This
simplifies the code, and it should also slightly improve performance for
everyone who wasn't actually using one of these ahash-only crypto
accelerators, i.e. almost everyone (or maybe even everyone)!
Link: https://lore.kernel.org/r/20230516052306.99600-1-ebiggers@kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2023-05-15 22:12:16 -07:00
|
|
|
const struct inode *inode, const void *data, u8 *out);
|
2023-06-03 19:23:48 -07:00
|
|
|
int fsverity_hash_buffer(const struct fsverity_hash_alg *alg,
|
2019-07-22 09:26:21 -07:00
|
|
|
const void *data, size_t size, u8 *out);
|
|
|
|
void __init fsverity_check_hash_algs(void);
|
|
|
|
|
|
|
|
/* init.c */
|
|
|
|
|
2020-05-11 12:21:18 -07:00
|
|
|
void __printf(3, 4) __cold
|
2019-07-22 09:26:21 -07:00
|
|
|
fsverity_msg(const struct inode *inode, const char *level,
|
|
|
|
const char *fmt, ...);
|
|
|
|
|
|
|
|
#define fsverity_warn(inode, fmt, ...) \
|
|
|
|
fsverity_msg((inode), KERN_WARNING, fmt, ##__VA_ARGS__)
|
|
|
|
#define fsverity_err(inode, fmt, ...) \
|
|
|
|
fsverity_msg((inode), KERN_ERR, fmt, ##__VA_ARGS__)
|
|
|
|
|
2023-11-29 16:44:13 -07:00
|
|
|
/* measure.c */
|
|
|
|
|
|
|
|
#ifdef CONFIG_BPF_SYSCALL
|
|
|
|
void __init fsverity_init_bpf(void);
|
|
|
|
#else
|
|
|
|
static inline void fsverity_init_bpf(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-07-22 09:26:22 -07:00
|
|
|
/* open.c */
|
|
|
|
|
|
|
|
int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
|
|
|
const struct inode *inode,
|
|
|
|
unsigned int hash_algorithm,
|
|
|
|
unsigned int log_blocksize,
|
|
|
|
const u8 *salt, size_t salt_size);
|
|
|
|
|
|
|
|
struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
2022-05-18 06:22:56 -07:00
|
|
|
struct fsverity_descriptor *desc);
|
2019-07-22 09:26:22 -07:00
|
|
|
|
|
|
|
void fsverity_set_info(struct inode *inode, struct fsverity_info *vi);
|
|
|
|
|
|
|
|
void fsverity_free_info(struct fsverity_info *vi);
|
|
|
|
|
2021-01-15 11:18:14 -07:00
|
|
|
int fsverity_get_descriptor(struct inode *inode,
|
2022-05-18 06:22:56 -07:00
|
|
|
struct fsverity_descriptor **desc_ret);
|
2021-01-15 11:18:14 -07:00
|
|
|
|
2023-07-05 14:27:42 -07:00
|
|
|
void __init fsverity_init_info_cache(void);
|
2019-07-22 09:26:22 -07:00
|
|
|
|
2019-07-22 09:26:23 -07:00
|
|
|
/* signature.c */
|
|
|
|
|
|
|
|
#ifdef CONFIG_FS_VERITY_BUILTIN_SIGNATURES
|
2023-07-05 14:27:43 -07:00
|
|
|
extern int fsverity_require_signatures;
|
2019-07-22 09:26:23 -07:00
|
|
|
int fsverity_verify_signature(const struct fsverity_info *vi,
|
2021-01-15 11:18:15 -07:00
|
|
|
const u8 *signature, size_t sig_size);
|
2019-07-22 09:26:23 -07:00
|
|
|
|
2023-07-05 14:27:42 -07:00
|
|
|
void __init fsverity_init_signature(void);
|
2019-07-22 09:26:23 -07:00
|
|
|
#else /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
|
|
|
|
static inline int
|
|
|
|
fsverity_verify_signature(const struct fsverity_info *vi,
|
2021-01-15 11:18:15 -07:00
|
|
|
const u8 *signature, size_t sig_size)
|
2019-07-22 09:26:23 -07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-05 14:27:42 -07:00
|
|
|
static inline void fsverity_init_signature(void)
|
2019-07-22 09:26:23 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_FS_VERITY_BUILTIN_SIGNATURES */
|
|
|
|
|
2019-07-22 09:26:22 -07:00
|
|
|
/* verify.c */
|
|
|
|
|
2023-07-05 14:27:42 -07:00
|
|
|
void __init fsverity_init_workqueue(void);
|
2019-07-22 09:26:22 -07:00
|
|
|
|
2019-07-22 09:26:21 -07:00
|
|
|
#endif /* _FSVERITY_PRIVATE_H */
|