• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
19 static 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  */
27 static 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  */
fsverity_verify_signature(const struct fsverity_info * vi,const struct fsverity_descriptor * desc,size_t desc_size)40 int 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 	if (fsverity_keyring->keys.nr_leaves_on_tree == 0) {
65 		/*
66 		 * The ".fs-verity" keyring is empty, due to builtin signatures
67 		 * being supported by the kernel but not actually being used.
68 		 * In this case, verify_pkcs7_signature() would always return an
69 		 * error, usually ENOKEY.  It could also be EBADMSG if the
70 		 * PKCS#7 is malformed, but that isn't very important to
71 		 * distinguish.  So, just skip to ENOKEY to avoid the attack
72 		 * surface of the PKCS#7 parser, which would otherwise be
73 		 * reachable by any task able to execute FS_IOC_ENABLE_VERITY.
74 		 */
75 		fsverity_err(inode,
76 			     "fs-verity keyring is empty, rejecting signed file!");
77 		return -ENOKEY;
78 	}
79 
80 	d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL);
81 	if (!d)
82 		return -ENOMEM;
83 	memcpy(d->magic, "FSVerity", 8);
84 	d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs);
85 	d->digest_size = cpu_to_le16(hash_alg->digest_size);
86 	memcpy(d->digest, vi->measurement, hash_alg->digest_size);
87 
88 	err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size,
89 				     desc->signature, sig_size,
90 				     fsverity_keyring,
91 				     VERIFYING_UNSPECIFIED_SIGNATURE,
92 				     NULL, NULL);
93 	kfree(d);
94 
95 	if (err) {
96 		if (err == -ENOKEY)
97 			fsverity_err(inode,
98 				     "File's signing cert isn't in the fs-verity keyring");
99 		else if (err == -EKEYREJECTED)
100 			fsverity_err(inode, "Incorrect file signature");
101 		else if (err == -EBADMSG)
102 			fsverity_err(inode, "Malformed file signature");
103 		else
104 			fsverity_err(inode, "Error %d verifying file signature",
105 				     err);
106 		return err;
107 	}
108 
109 	pr_debug("Valid signature for file measurement %s:%*phN\n",
110 		 hash_alg->name, hash_alg->digest_size, vi->measurement);
111 	return 0;
112 }
113 
114 #ifdef CONFIG_SYSCTL
115 static struct ctl_table_header *fsverity_sysctl_header;
116 
117 static const struct ctl_path fsverity_sysctl_path[] = {
118 	{ .procname = "fs", },
119 	{ .procname = "verity", },
120 	{ }
121 };
122 
123 static struct ctl_table fsverity_sysctl_table[] = {
124 	{
125 		.procname       = "require_signatures",
126 		.data           = &fsverity_require_signatures,
127 		.maxlen         = sizeof(int),
128 		.mode           = 0644,
129 		.proc_handler   = proc_dointvec_minmax,
130 		.extra1         = SYSCTL_ZERO,
131 		.extra2         = SYSCTL_ONE,
132 	},
133 	{ }
134 };
135 
fsverity_sysctl_init(void)136 static int __init fsverity_sysctl_init(void)
137 {
138 	fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path,
139 						       fsverity_sysctl_table);
140 	if (!fsverity_sysctl_header) {
141 		pr_err("sysctl registration failed!\n");
142 		return -ENOMEM;
143 	}
144 	return 0;
145 }
146 #else /* !CONFIG_SYSCTL */
fsverity_sysctl_init(void)147 static inline int __init fsverity_sysctl_init(void)
148 {
149 	return 0;
150 }
151 #endif /* !CONFIG_SYSCTL */
152 
fsverity_init_signature(void)153 int __init fsverity_init_signature(void)
154 {
155 	struct key *ring;
156 	int err;
157 
158 	ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0),
159 			     current_cred(), KEY_POS_SEARCH |
160 				KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE |
161 				KEY_USR_SEARCH | KEY_USR_SETATTR,
162 			     KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
163 	if (IS_ERR(ring))
164 		return PTR_ERR(ring);
165 
166 	err = fsverity_sysctl_init();
167 	if (err)
168 		goto err_put_ring;
169 
170 	fsverity_keyring = ring;
171 	return 0;
172 
173 err_put_ring:
174 	key_put(ring);
175 	return err;
176 }
177