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#include <linux/hck/lite_hck_code_sign.h> 15 16/* 17 * /proc/sys/fs/verity/require_signatures 18 * If 1, all verity files must have a valid builtin signature. 19 */ 20static int fsverity_require_signatures; 21 22/* 23 * Keyring that contains the trusted X.509 certificates. 24 * 25 * Only root (kuid=0) can modify this. Also, root may use 26 * keyctl_restrict_keyring() to prevent any more additions. 27 */ 28static struct key *fsverity_keyring; 29 30#ifdef CONFIG_SECURITY_CODE_SIGN 31 32void fsverity_set_cert_type(struct fsverity_info *vi, 33 int cert_type) 34{ 35 vi->cert_type = cert_type; 36} 37 38int fsverity_get_cert_type(const struct inode *inode) 39{ 40 return fsverity_get_info(inode)->cert_type; 41} 42 43#else /* !CONFIG_SECURITY_CODE_SIGN */ 44 45static void inline fsverity_set_cert_type(struct fsverity_info *verity_info, 46 int cert_type) 47{ 48} 49 50#endif 51 52static inline int fsverity_verify_certchain(struct fsverity_info *vi, 53 const void *raw_pkcs7, size_t pkcs7_len) 54{ 55 int ret = 0; 56 57 CALL_HCK_LITE_HOOK(code_sign_verify_certchain_lhck, 58 raw_pkcs7, pkcs7_len, &vi->fcs_info, &ret); 59 if (ret > 0) { 60 fsverity_set_cert_type(vi, ret); 61 ret = 0; 62 } 63 64 return ret; 65} 66 67/** 68 * fsverity_verify_signature() - check a verity file's signature 69 * @vi: the file's fsverity_info 70 * @desc: the file's fsverity_descriptor 71 * @desc_size: size of @desc 72 * 73 * If the file's fs-verity descriptor includes a signature of the file 74 * measurement, verify it against the certificates in the fs-verity keyring. 75 * 76 * Return: 0 on success (signature valid or not required); -errno on failure 77 */ 78int fsverity_verify_signature(struct fsverity_info *vi, 79 const struct fsverity_descriptor *desc, 80 size_t desc_size) 81{ 82 const struct inode *inode = vi->inode; 83 const struct fsverity_hash_alg *hash_alg = vi->tree_params.hash_alg; 84 const u32 sig_size = le32_to_cpu(desc->sig_size); 85 struct fsverity_signed_digest *d; 86 int err; 87 88 if (sig_size == 0) { 89 if (fsverity_require_signatures) { 90 fsverity_err(inode, 91 "require_signatures=1, rejecting unsigned file!"); 92 return -EPERM; 93 } 94 return 0; 95 } 96 97 if (sig_size > desc_size - sizeof(*desc)) { 98 fsverity_err(inode, "Signature overflows verity descriptor"); 99 return -EBADMSG; 100 } 101 102 if (fsverity_keyring->keys.nr_leaves_on_tree == 0) { 103 /* 104 * The ".fs-verity" keyring is empty, due to builtin signatures 105 * being supported by the kernel but not actually being used. 106 * In this case, verify_pkcs7_signature() would always return an 107 * error, usually ENOKEY. It could also be EBADMSG if the 108 * PKCS#7 is malformed, but that isn't very important to 109 * distinguish. So, just skip to ENOKEY to avoid the attack 110 * surface of the PKCS#7 parser, which would otherwise be 111 * reachable by any task able to execute FS_IOC_ENABLE_VERITY. 112 */ 113 fsverity_err(inode, 114 "fs-verity keyring is empty, rejecting signed file!"); 115 return -ENOKEY; 116 } 117 118 d = kzalloc(sizeof(*d) + hash_alg->digest_size, GFP_KERNEL); 119 if (!d) 120 return -ENOMEM; 121 memcpy(d->magic, "FSVerity", 8); 122 d->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs); 123 d->digest_size = cpu_to_le16(hash_alg->digest_size); 124 memcpy(d->digest, vi->measurement, hash_alg->digest_size); 125 126 err = fsverity_verify_certchain(vi, desc->signature, sig_size); 127 if (err) { 128 fsverity_err(inode, "verify cert chain failed, err = %d", err); 129 return err; 130 } 131 pr_debug("verify cert chain success\n"); 132 133 err = verify_pkcs7_signature(d, sizeof(*d) + hash_alg->digest_size, 134 desc->signature, sig_size, 135 fsverity_keyring, 136 VERIFYING_UNSPECIFIED_SIGNATURE, 137 NULL, NULL); 138 kfree(d); 139 140 if (err) { 141 if (err == -ENOKEY) 142 fsverity_err(inode, 143 "File's signing cert isn't in the fs-verity keyring"); 144 else if (err == -EKEYREJECTED) 145 fsverity_err(inode, "Incorrect file signature"); 146 else if (err == -EBADMSG) 147 fsverity_err(inode, "Malformed file signature"); 148 else 149 fsverity_err(inode, "Error %d verifying file signature", 150 err); 151 return err; 152 } 153 154 pr_debug("Valid signature for file measurement %s:%*phN\n", 155 hash_alg->name, hash_alg->digest_size, vi->measurement); 156 return 0; 157} 158 159#ifdef CONFIG_SYSCTL 160static struct ctl_table_header *fsverity_sysctl_header; 161 162static const struct ctl_path fsverity_sysctl_path[] = { 163 { .procname = "fs", }, 164 { .procname = "verity", }, 165 { } 166}; 167 168static struct ctl_table fsverity_sysctl_table[] = { 169 { 170 .procname = "require_signatures", 171 .data = &fsverity_require_signatures, 172 .maxlen = sizeof(int), 173 .mode = 0644, 174 .proc_handler = proc_dointvec_minmax, 175 .extra1 = SYSCTL_ZERO, 176 .extra2 = SYSCTL_ONE, 177 }, 178 { } 179}; 180 181static int __init fsverity_sysctl_init(void) 182{ 183 fsverity_sysctl_header = register_sysctl_paths(fsverity_sysctl_path, 184 fsverity_sysctl_table); 185 if (!fsverity_sysctl_header) { 186 pr_err("sysctl registration failed!\n"); 187 return -ENOMEM; 188 } 189 return 0; 190} 191#else /* !CONFIG_SYSCTL */ 192static inline int __init fsverity_sysctl_init(void) 193{ 194 return 0; 195} 196#endif /* !CONFIG_SYSCTL */ 197 198int __init fsverity_init_signature(void) 199{ 200 struct key *ring; 201 int err; 202 203 ring = keyring_alloc(".fs-verity", KUIDT_INIT(0), KGIDT_INIT(0), 204 current_cred(), KEY_POS_SEARCH | 205 KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | 206 KEY_USR_SEARCH | KEY_USR_SETATTR, 207 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); 208 if (IS_ERR(ring)) 209 return PTR_ERR(ring); 210 211 err = fsverity_sysctl_init(); 212 if (err) 213 goto err_put_ring; 214 215 fsverity_keyring = ring; 216 return 0; 217 218err_put_ring: 219 key_put(ring); 220 return err; 221} 222