Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * fs/verity/signature.c: 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 * @desc: the file's fsverity_descriptor
 33 * @desc_size: size of @desc
 34 *
 35 * If the file's fs-verity descriptor includes a signature of the file
 36 * measurement, verify it 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 struct fsverity_descriptor *desc,
 42			      size_t desc_size)
 43{
 44	const struct inode *inode = vi->inode;
 45	const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg;
 46	const u32 sig_size = le32_to_cpu(desc->sig_size);
 47	struct fsverity_signed_digest *d;
 48	int err;
 49
 50	if (sig_size == 0) {
 51		if (fsverity_require_signatures) {
 52			fsverity_err(inode,
 53				     "require_signatures=1, rejecting unsigned file!");
 54			return -EPERM;
 55		}
 56		return 0;
 57	}
 58
 59	if (sig_size > desc_size - sizeof(*desc)) {
 60		fsverity_err(inode, "Signature overflows verity descriptor");
 61		return -EBADMSG;
 62	}
 63
 64	d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
 65	if (!d)
 66		return -ENOMEM;
 67	memcpy(d->magic, "FSVerity", 8);
 68	d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
 69	d->digest_size = cpu_to_le16(hash_alg->digest_size);
 70	memcpy(d->digest, vi->measurement, hash_alg->digest_size);
 71
 72	err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
 73				     desc->signature, sig_size,
 74				     fsverity_keyring,
 75				     VERIFYING_UNSPECIFIED_SIGNATURE,
 76				     NULL, NULL);
 77	kfree(d);
 78
 79	if (err) {
 80		if (err == -ENOKEY)
 81			fsverity_err(inode,
 82				     "File's signing cert isn't in the fs-verity keyring");
 83		else if (err == -EKEYREJECTED)
 84			fsverity_err(inode, "Incorrect file signature");
 85		else if (err == -EBADMSG)
 86			fsverity_err(inode, "Malformed file signature");
 87		else
 88			fsverity_err(inode, "Error %d verifying file signature",
 89				     err);
 90		return err;
 91	}
 92
 93	pr_debug("Valid signature for file measurement %s:%*phN\n",
 94		 hash_alg->name, hash_alg->digest_size, vi->measurement);
 95	return 0;
 96}
 97
 98#ifdef CONFIG_SYSCTL
 99static struct ctl_table_header *fsverity_sysctl_header;
100
101static const struct ctl_path fsverity_sysctl_path[] = {
102	{ .procname = "fs", },
103	{ .procname = "verity", },
104	{ }
105};
106
107static struct ctl_table fsverity_sysctl_table[] = {
108	{
109		.procname       = "require_signatures",
110		.data           = &fsverity_require_signatures,
111		.maxlen         = sizeof(int),
112		.mode           = 0644,
113		.proc_handler   = proc_dointvec_minmax,
114		.extra1         = SYSCTL_ZERO,
115		.extra2         = SYSCTL_ONE,
116	},
117	{ }
118};
119
120static int __init fsverity_sysctl_init(void)
121{
122	fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path,
123						       fsverity_sysctl_table);
124	if (!fsverity_sysctl_header) {
125		pr_err("sysctl registration failed!\n");
126		return -ENOMEM;
127	}
128	return 0;
129}
130#else /* !CONFIG_SYSCTL */
131static inline int __init fsverity_sysctl_init(void)
132{
133	return 0;
134}
135#endif /* !CONFIG_SYSCTL */
136
137int __init fsverity_init_signature(void)
138{
139	struct key *ring;
140	int err;
141
142	ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
143			     current_cred(), KEY_POS_SEARCH |
144				KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
145				KEY_USR_SEARCH | KEY_USR_SETATTR,
146			     KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
147	if (IS_ERR(ring))
148		return PTR_ERR(ring);
149
150	err = fsverity_sysctl_init();
151	if (err)
152		goto err_put_ring;
153
154	fsverity_keyring = ring;
155	return 0;
156
157err_put_ring:
158	key_put(ring);
159	return err;
160}