2019-07-22 09:26:23 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
2020-11-13 14:19:15 -07:00
|
|
|
* Verification of builtin signatures
|
2019-07-22 09:26:23 -07:00
|
|
|
*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*/
|
|
|
|
|
fsverity: improve documentation for builtin signature support
fsverity builtin signatures (CONFIG_FS_VERITY_BUILTIN_SIGNATURES) aren't
the only way to do signatures with fsverity, and they have some major
limitations. Yet, more users have tried to use them, e.g. recently by
https://github.com/ostreedev/ostree/pull/2640. In most cases this seems
to be because users aren't sufficiently familiar with the limitations of
this feature and what the alternatives are.
Therefore, make some updates to the documentation to try to clarify the
properties of this feature and nudge users in the right direction.
Note that the Integrity Policy Enforcement (IPE) LSM, which is not yet
upstream, is planned to use the builtin signatures. (This differs from
IMA, which uses its own signature mechanism.) For that reason, my
earlier patch "fsverity: mark builtin signatures as deprecated"
(https://lore.kernel.org/r/20221208033548.122704-1-ebiggers@kernel.org),
which marked builtin signatures as "deprecated", was controversial.
This patch therefore stops short of marking the feature as deprecated.
I've also revised the language to focus on better explaining the feature
and what its alternatives are.
Link: https://lore.kernel.org/r/20230620041937.5809-1-ebiggers@kernel.org
Reviewed-by: Colin Walters <walters@verbum.org>
Reviewed-by: Luca Boccassi <bluca@debian.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2023-06-19 21:19:37 -07:00
|
|
|
/*
|
|
|
|
* This file implements verification of fs-verity builtin signatures. Please
|
|
|
|
* take great care before using this feature. It is not the only way to do
|
|
|
|
* signatures with fs-verity, and the alternatives (such as userspace signature
|
|
|
|
* verification, and IMA appraisal) can be much better. For details about the
|
|
|
|
* limitations of this feature, see Documentation/filesystems/fsverity.rst.
|
|
|
|
*/
|
|
|
|
|
2019-07-22 09:26:23 -07:00
|
|
|
#include "fsverity_private.h"
|
|
|
|
|
|
|
|
#include <linux/cred.h>
|
|
|
|
#include <linux/key.h>
|
2024-08-02 23:08:29 -07:00
|
|
|
#include <linux/security.h>
|
2019-07-22 09:26:23 -07:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/verification.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* /proc/sys/fs/verity/require_signatures
|
|
|
|
* If 1, all verity files must have a valid builtin signature.
|
|
|
|
*/
|
2023-07-05 14:27:43 -07:00
|
|
|
int fsverity_require_signatures;
|
2019-07-22 09:26:23 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Keyring that contains the trusted X.509 certificates.
|
|
|
|
*
|
|
|
|
* Only root (kuid=0) can modify this. Also, root may use
|
|
|
|
* keyctl_restrict_keyring() to prevent any more additions.
|
|
|
|
*/
|
|
|
|
static struct key *fsverity_keyring;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fsverity_verify_signature() - check a verity file's signature
|
2020-05-11 12:21:17 -07:00
|
|
|
* @vi: the file's fsverity_info
|
2021-01-15 11:18:15 -07:00
|
|
|
* @signature: the file's built-in signature
|
|
|
|
* @sig_size: size of signature in bytes, or 0 if no signature
|
2019-07-22 09:26:23 -07:00
|
|
|
*
|
2021-01-15 11:18:15 -07:00
|
|
|
* If the file includes a signature of its fs-verity file digest, verify it
|
2024-08-02 23:08:29 -07:00
|
|
|
* against the certificates in the fs-verity keyring. Note that signatures
|
|
|
|
* are verified regardless of the state of the 'fsverity_require_signatures'
|
|
|
|
* variable and the LSM subsystem relies on this behavior to help enforce
|
|
|
|
* file integrity policies. Please discuss changes with the LSM list
|
|
|
|
* (thank you!).
|
2019-07-22 09:26:23 -07:00
|
|
|
*
|
|
|
|
* Return: 0 on success (signature valid or not required); -errno on failure
|
|
|
|
*/
|
|
|
|
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
|
|
|
{
|
|
|
|
const struct inode *inode = vi->inode;
|
|
|
|
const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
|
2020-11-13 14:19:16 -07:00
|
|
|
struct fsverity_formatted_digest *d;
|
2019-07-22 09:26:23 -07:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (sig_size == 0) {
|
|
|
|
if (fsverity_require_signatures) {
|
|
|
|
fsverity_err(inode,
|
|
|
|
"require_signatures=1, rejecting unsigned file!");
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-01 21:03:53 -07:00
|
|
|
if (fsverity_keyring->keys.nr_leaves_on_tree == 0) {
|
|
|
|
/*
|
|
|
|
* The ".fs-verity" keyring is empty, due to builtin signatures
|
|
|
|
* being supported by the kernel but not actually being used.
|
|
|
|
* In this case, verify_pkcs7_signature() would always return an
|
|
|
|
* error, usually ENOKEY. It could also be EBADMSG if the
|
|
|
|
* PKCS#7 is malformed, but that isn't very important to
|
|
|
|
* distinguish. So, just skip to ENOKEY to avoid the attack
|
|
|
|
* surface of the PKCS#7 parser, which would otherwise be
|
|
|
|
* reachable by any task able to execute FS_IOC_ENABLE_VERITY.
|
|
|
|
*/
|
|
|
|
fsverity_err(inode,
|
|
|
|
"fs-verity keyring is empty, rejecting signed file!");
|
|
|
|
return -ENOKEY;
|
|
|
|
}
|
|
|
|
|
2019-07-22 09:26:23 -07:00
|
|
|
d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
|
|
|
|
if (!d)
|
|
|
|
return -ENOMEM;
|
|
|
|
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);
|
2020-11-13 14:19:17 -07:00
|
|
|
memcpy(d->digest, vi->file_digest, hash_alg->digest_size);
|
2019-07-22 09:26:23 -07:00
|
|
|
|
|
|
|
err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
|
2021-01-15 11:18:15 -07:00
|
|
|
signature, sig_size, fsverity_keyring,
|
2019-07-22 09:26:23 -07:00
|
|
|
VERIFYING_UNSPECIFIED_SIGNATURE,
|
|
|
|
NULL, NULL);
|
|
|
|
kfree(d);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
if (err == -ENOKEY)
|
|
|
|
fsverity_err(inode,
|
|
|
|
"File's signing cert isn't in the fs-verity keyring");
|
|
|
|
else if (err == -EKEYREJECTED)
|
|
|
|
fsverity_err(inode, "Incorrect file signature");
|
|
|
|
else if (err == -EBADMSG)
|
|
|
|
fsverity_err(inode, "Malformed file signature");
|
|
|
|
else
|
|
|
|
fsverity_err(inode, "Error %d verifying file signature",
|
|
|
|
err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-08-02 23:08:29 -07:00
|
|
|
err = security_inode_setintegrity(inode,
|
|
|
|
LSM_INT_FSVERITY_BUILTINSIG_VALID,
|
|
|
|
signature,
|
|
|
|
sig_size);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
fsverity_err(inode, "Error %d exposing file signature to LSMs",
|
|
|
|
err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-07-22 09:26:23 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-05 14:27:42 -07:00
|
|
|
void __init fsverity_init_signature(void)
|
2019-07-22 09:26:23 -07:00
|
|
|
{
|
2023-07-05 14:27:42 -07:00
|
|
|
fsverity_keyring =
|
|
|
|
keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
|
|
|
|
current_cred(), KEY_POS_SEARCH |
|
2019-07-22 09:26:23 -07:00
|
|
|
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
|
|
|
|
KEY_USR_SEARCH | KEY_USR_SETATTR,
|
2023-07-05 14:27:42 -07:00
|
|
|
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
|
|
|
if (IS_ERR(fsverity_keyring))
|
|
|
|
panic("failed to allocate \".fs-verity\" keyring");
|
2019-07-22 09:26:23 -07:00
|
|
|
}
|