63b140889d
* tag '5.12-rc1-4.19' of https://kernel.googlesource.com/pub/scm/linux/kernel/git/jaegeuk/f2fs-stable: fs-verity: support reading signature with ioctl fs-verity: support reading descriptor with ioctl fs-verity: support reading Merkle tree with ioctl fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl fs-verity: don't pass whole descriptor to fsverity_verify_signature() fs-verity: factor out fsverity_get_descriptor() f2fs: remove FAULT_ALLOC_BIO f2fs: use blkdev_issue_flush in __submit_flush_wait f2fs: remove a few bd_part checks 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 fs-verity: use smp_load_acquire() for ->i_verity_info Documentation: f2fs: fix typo s/automaic/automatic f2fs: give a warning only for readonly partition f2fs: don't grab superblock freeze for flush/ckpt thread f2fs: add ckpt_thread_ioprio sysfs node f2fs: introduce checkpoint_merge mount option f2fs: relocate inline conversion from mmap() to mkwrite() f2fs: fix a wrong condition in __submit_bio f2fs: remove unnecessary initialization in xattr.c f2fs: fix to avoid inconsistent quota data f2fs: flush data when enabling checkpoint back f2fs: deprecate f2fs_trace_io f2fs: remove unused stat_{inc, dec}_atomic_write f2fs: introduce sb_status sysfs node f2fs: fix to use per-inode maxbytes f2fs: compress: fix potential deadlock libfs: unexport generic_ci_d_compare() and generic_ci_d_hash() f2fs: fix to set/clear I_LINKABLE under i_lock f2fs: fix null page reference in redirty_blocks f2fs: clean up post-read processing f2fs: trival cleanup in move_data_block() f2fs: fix out-of-repair __setattr_copy() f2fs: fix to tag FIEMAP_EXTENT_MERGED in f2fs_fiemap() f2fs: introduce a new per-sb directory in sysfs f2fs: compress: support compress level f2fs: compress: deny setting unsupported compress algorithm f2fs: relocate f2fs_precache_extents() f2fs: enforce the immutable flag on open files f2fs: enhance to update i_mode and acl atomically in f2fs_setattr() f2fs: fix to set inode->i_mode correctly for posix_acl_update_mode f2fs: Replace expression with offsetof() f2fs: handle unallocated section and zone on pinned/atgc Change-Id: I88c2467fb263f9ddfda6eda8ba16037c433db8f2 Signed-off-by: UtsavBalar1231 <utsavbalar1231@gmail.com> Conflicts: fs/ext4/ioctl.c fs/f2fs/data.c fs/f2fs/file.c fs/verity/signature.c include/uapi/linux/fsverity.h
188 lines
5.0 KiB
C
188 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Verification of builtin signatures
|
|
*
|
|
* Copyright 2019 Google LLC
|
|
*/
|
|
|
|
#include "fsverity_private.h"
|
|
|
|
#include <linux/cred.h>
|
|
#include <linux/key.h>
|
|
#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.
|
|
*/
|
|
static int fsverity_require_signatures;
|
|
|
|
/*
|
|
* 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
|
|
* @vi: the file's fsverity_info
|
|
* @signature: the file's built-in signature
|
|
* @sig_size: size of signature in bytes, or 0 if no signature
|
|
*
|
|
* If the file includes a signature of its fs-verity file digest, verify it
|
|
* against the certificates in the fs-verity keyring.
|
|
*
|
|
* Return: 0 on success (signature valid or not required); -errno on failure
|
|
*/
|
|
int fsverity_verify_signature(const struct fsverity_info *vi,
|
|
const u8 *signature, size_t sig_size)
|
|
{
|
|
unsigned int digest_algorithm =
|
|
vi->tree_params.hash_alg - fsverity_hash_algs;
|
|
|
|
return __fsverity_verify_signature(vi->inode, signature, sig_size,
|
|
vi->file_digest, digest_algorithm);
|
|
}
|
|
|
|
/**
|
|
* __fsverity_verify_signature() - check a verity file's signature
|
|
* @inode: the file's inode
|
|
* @signature: the file's signature
|
|
* @sig_size: size of @signature. Can be 0 if there is no signature
|
|
* @file_digest: the file's digest
|
|
* @digest_algorithm: the digest algorithm used
|
|
*
|
|
* Takes the file's digest and optional signature and verifies the signature
|
|
* against the digest and the fs-verity keyring if appropriate
|
|
*
|
|
* Return: 0 on success (signature valid or not required); -errno on failure
|
|
*/
|
|
int __fsverity_verify_signature(const struct inode *inode, const u8 *signature,
|
|
u32 sig_size, const u8 *file_digest,
|
|
unsigned int digest_algorithm)
|
|
{
|
|
struct fsverity_formatted_digest *d;
|
|
struct fsverity_hash_alg *hash_alg = fsverity_get_hash_alg(inode,
|
|
digest_algorithm);
|
|
int err;
|
|
|
|
if (IS_ERR(hash_alg))
|
|
return PTR_ERR(hash_alg);
|
|
|
|
if (sig_size == 0) {
|
|
if (fsverity_require_signatures) {
|
|
fsverity_err(inode,
|
|
"require_signatures=1, rejecting unsigned file!");
|
|
return -EPERM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
memcpy(d->digest, file_digest, hash_alg->digest_size);
|
|
|
|
err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
|
|
signature, sig_size, fsverity_keyring,
|
|
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;
|
|
}
|
|
|
|
pr_debug("Valid signature for file digest %s:%*phN\n",
|
|
hash_alg->name, hash_alg->digest_size, file_digest);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(__fsverity_verify_signature);
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
static struct ctl_table_header *fsverity_sysctl_header;
|
|
|
|
static const struct ctl_path fsverity_sysctl_path[] = {
|
|
{ .procname = "fs", },
|
|
{ .procname = "verity", },
|
|
{ }
|
|
};
|
|
|
|
/* shared constants to be used in various sysctls */
|
|
static int sysctl_vals[] = { 0, 1, INT_MAX };
|
|
|
|
#define SYSCTL_ZERO ((void *)&sysctl_vals[0])
|
|
#define SYSCTL_ONE ((void *)&sysctl_vals[1])
|
|
#define SYSCTL_INT_MAX ((void *)&sysctl_vals[2])
|
|
|
|
static struct ctl_table fsverity_sysctl_table[] = {
|
|
{
|
|
.procname = "require_signatures",
|
|
.data = &fsverity_require_signatures,
|
|
.maxlen = sizeof(int),
|
|
.mode = 0644,
|
|
.proc_handler = proc_dointvec_minmax,
|
|
.extra1 = SYSCTL_ZERO,
|
|
.extra2 = SYSCTL_ONE,
|
|
},
|
|
{ }
|
|
};
|
|
|
|
static int __init fsverity_sysctl_init(void)
|
|
{
|
|
fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path,
|
|
fsverity_sysctl_table);
|
|
if (!fsverity_sysctl_header) {
|
|
pr_err("sysctl registration failed!\n");
|
|
return -ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
#else /* !CONFIG_SYSCTL */
|
|
static inline int __init fsverity_sysctl_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* !CONFIG_SYSCTL */
|
|
|
|
int __init fsverity_init_signature(void)
|
|
{
|
|
struct key *ring;
|
|
int err;
|
|
|
|
ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
|
|
current_cred(), KEY_POS_SEARCH |
|
|
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
|
|
KEY_USR_SEARCH | KEY_USR_SETATTR,
|
|
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
|
if (IS_ERR(ring))
|
|
return PTR_ERR(ring);
|
|
|
|
err = fsverity_sysctl_init();
|
|
if (err)
|
|
goto err_put_ring;
|
|
|
|
fsverity_keyring = ring;
|
|
return 0;
|
|
|
|
err_put_ring:
|
|
key_put(ring);
|
|
return err;
|
|
}
|