cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

signature.c (3927B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Verification of builtin signatures
      4 *
      5 * Copyright 2019 Google LLC
      6 */
      7
      8#include "fsverity_private.h"
      9
     10#include <linux/cred.h>
     11#include <linux/key.h>
     12#include <linux/slab.h>
     13#include <linux/verification.h>
     14
     15/*
     16 * /proc/sys/fs/verity/require_signatures
     17 * If 1, all verity files must have a valid builtin signature.
     18 */
     19static int fsverity_require_signatures;
     20
     21/*
     22 * Keyring that contains the trusted X.509 certificates.
     23 *
     24 * Only root (kuid=0) can modify this.  Also, root may use
     25 * keyctl_restrict_keyring() to prevent any more additions.
     26 */
     27static struct key *fsverity_keyring;
     28
     29/**
     30 * fsverity_verify_signature() - check a verity file's signature
     31 * @vi: the file's fsverity_info
     32 * @signature: the file's built-in signature
     33 * @sig_size: size of signature in bytes, or 0 if no signature
     34 *
     35 * If the file includes a signature of its fs-verity file digest, verify it
     36 * against the certificates in the fs-verity keyring.
     37 *
     38 * Return: 0 on success (signature valid or not required); -errno on failure
     39 */
     40int fsverity_verify_signature(const struct fsverity_info *vi,
     41			      const u8 *signature, size_t sig_size)
     42{
     43	const struct inode *inode = vi->inode;
     44	const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
     45	struct fsverity_formatted_digest *d;
     46	int err;
     47
     48	if (sig_size == 0) {
     49		if (fsverity_require_signatures) {
     50			fsverity_err(inode,
     51				     "require_signatures=1, rejecting unsigned file!");
     52			return -EPERM;
     53		}
     54		return 0;
     55	}
     56
     57	d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
     58	if (!d)
     59		return -ENOMEM;
     60	memcpy(d->magic, "FSVerity", 8);
     61	d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
     62	d->digest_size = cpu_to_le16(hash_alg->digest_size);
     63	memcpy(d->digest, vi->file_digest, hash_alg->digest_size);
     64
     65	err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
     66				     signature, sig_size, fsverity_keyring,
     67				     VERIFYING_UNSPECIFIED_SIGNATURE,
     68				     NULL, NULL);
     69	kfree(d);
     70
     71	if (err) {
     72		if (err == -ENOKEY)
     73			fsverity_err(inode,
     74				     "File's signing cert isn't in the fs-verity keyring");
     75		else if (err == -EKEYREJECTED)
     76			fsverity_err(inode, "Incorrect file signature");
     77		else if (err == -EBADMSG)
     78			fsverity_err(inode, "Malformed file signature");
     79		else
     80			fsverity_err(inode, "Error %d verifying file signature",
     81				     err);
     82		return err;
     83	}
     84
     85	pr_debug("Valid signature for file digest %s:%*phN\n",
     86		 hash_alg->name, hash_alg->digest_size, vi->file_digest);
     87	return 0;
     88}
     89
     90#ifdef CONFIG_SYSCTL
     91static struct ctl_table_header *fsverity_sysctl_header;
     92
     93static const struct ctl_path fsverity_sysctl_path[] = {
     94	{ .procname = "fs", },
     95	{ .procname = "verity", },
     96	{ }
     97};
     98
     99static struct ctl_table fsverity_sysctl_table[] = {
    100	{
    101		.procname       = "require_signatures",
    102		.data           = &fsverity_require_signatures,
    103		.maxlen         = sizeof(int),
    104		.mode           = 0644,
    105		.proc_handler   = proc_dointvec_minmax,
    106		.extra1         = SYSCTL_ZERO,
    107		.extra2         = SYSCTL_ONE,
    108	},
    109	{ }
    110};
    111
    112static int __init fsverity_sysctl_init(void)
    113{
    114	fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path,
    115						       fsverity_sysctl_table);
    116	if (!fsverity_sysctl_header) {
    117		pr_err("sysctl registration failed!\n");
    118		return -ENOMEM;
    119	}
    120	return 0;
    121}
    122#else /* !CONFIG_SYSCTL */
    123static inline int __init fsverity_sysctl_init(void)
    124{
    125	return 0;
    126}
    127#endif /* !CONFIG_SYSCTL */
    128
    129int __init fsverity_init_signature(void)
    130{
    131	struct key *ring;
    132	int err;
    133
    134	ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
    135			     current_cred(), KEY_POS_SEARCH |
    136				KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
    137				KEY_USR_SEARCH | KEY_USR_SETATTR,
    138			     KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
    139	if (IS_ERR(ring))
    140		return PTR_ERR(ring);
    141
    142	err = fsverity_sysctl_init();
    143	if (err)
    144		goto err_put_ring;
    145
    146	fsverity_keyring = ring;
    147	return 0;
    148
    149err_put_ring:
    150	key_put(ring);
    151	return err;
    152}