1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2019 Microsoft Corporation. 4 * 5 * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com> 6 * 7 */ 8 #include <linux/device-mapper.h> 9 #include <linux/verification.h> 10 #include <linux/key.h> 11 #include <keys/user-type.h> 12 #include <linux/module.h> 13 #include "dm-verity.h" 14 #include "dm-verity-verify-sig.h" 15 16 #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s 17 18 static struct key *dm_verity_keyring; 19 20 static bool dm_verity_keyring_unsealed __ro_after_init; 21 module_param_named(keyring_unsealed, dm_verity_keyring_unsealed, bool, 0444); 22 MODULE_PARM_DESC(keyring_unsealed, "Leave the dm-verity keyring unsealed"); 23 24 static bool require_signatures; 25 module_param(require_signatures, bool, 0444); 26 MODULE_PARM_DESC(require_signatures, 27 "Verify the roothash of dm-verity hash tree"); 28 29 #define DM_VERITY_IS_SIG_FORCE_ENABLED() \ 30 (require_signatures != false) 31 32 bool verity_verify_is_sig_opt_arg(const char *arg_name) 33 { 34 return (!strcasecmp(arg_name, 35 DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY)); 36 } 37 38 static int verity_verify_get_sig_from_key(const char *key_desc, 39 struct dm_verity_sig_opts *sig_opts) 40 { 41 struct key *key; 42 const struct user_key_payload *ukp; 43 int ret = 0; 44 45 key = request_key(&key_type_user, 46 key_desc, NULL); 47 if (IS_ERR(key)) 48 return PTR_ERR(key); 49 50 down_read(&key->sem); 51 52 ukp = user_key_payload_locked(key); 53 if (!ukp) { 54 ret = -EKEYREVOKED; 55 goto end; 56 } 57 58 sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL); 59 if (!sig_opts->sig) { 60 ret = -ENOMEM; 61 goto end; 62 } 63 sig_opts->sig_size = ukp->datalen; 64 65 memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size); 66 67 end: 68 up_read(&key->sem); 69 key_put(key); 70 71 return ret; 72 } 73 74 int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, 75 struct dm_verity *v, 76 struct dm_verity_sig_opts *sig_opts, 77 unsigned int *argc, 78 const char *arg_name) 79 { 80 struct dm_target *ti = v->ti; 81 int ret; 82 const char *sig_key = NULL; 83 84 if (v->signature_key_desc) { 85 ti->error = DM_VERITY_VERIFY_ERR("root_hash_sig_key_desc already specified"); 86 return -EINVAL; 87 } 88 89 if (!*argc) { 90 ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); 91 return -EINVAL; 92 } 93 94 sig_key = dm_shift_arg(as); 95 (*argc)--; 96 97 ret = verity_verify_get_sig_from_key(sig_key, sig_opts); 98 if (ret < 0) { 99 ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); 100 return ret; 101 } 102 103 v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); 104 if (!v->signature_key_desc) { 105 ti->error = DM_VERITY_VERIFY_ERR("Could not allocate memory for signature key"); 106 return -ENOMEM; 107 } 108 109 return 0; 110 } 111 112 /* 113 * verify_verify_roothash - Verify the root hash of the verity hash device 114 * using builtin trusted keys. 115 * 116 * @root_hash: For verity, the roothash/data to be verified. 117 * @root_hash_len: Size of the roothash/data to be verified. 118 * @sig_data: The trusted signature that verifies the roothash/data. 119 * @sig_len: Size of the signature. 120 * 121 */ 122 int verity_verify_root_hash(const void *root_hash, size_t root_hash_len, 123 const void *sig_data, size_t sig_len) 124 { 125 int ret; 126 127 if (!root_hash || root_hash_len == 0) 128 return -EINVAL; 129 130 if (!sig_data || sig_len == 0) { 131 if (DM_VERITY_IS_SIG_FORCE_ENABLED()) 132 return -ENOKEY; 133 else 134 return 0; 135 } 136 137 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 138 sig_len, 139 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING 140 VERIFY_USE_SECONDARY_KEYRING, 141 #else 142 NULL, 143 #endif 144 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 145 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING 146 if (ret == -ENOKEY || ret == -EKEYREJECTED) 147 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 148 sig_len, 149 VERIFY_USE_PLATFORM_KEYRING, 150 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 151 #endif 152 153 if (ret != -ENOKEY && ret != -EKEYREJECTED) 154 return ret; 155 156 if (dm_verity_keyring->keys.nr_leaves_on_tree && 157 dm_verity_keyring->restrict_link) 158 ret = verify_pkcs7_signature(root_hash, root_hash_len, 159 sig_data, sig_len, 160 dm_verity_keyring, 161 VERIFYING_UNSPECIFIED_SIGNATURE, 162 NULL, NULL); 163 164 return ret; 165 } 166 167 void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) 168 { 169 kfree(sig_opts->sig); 170 sig_opts->sig = NULL; 171 sig_opts->sig_size = 0; 172 } 173 174 int __init dm_verity_verify_sig_init(void) 175 { 176 dm_verity_keyring = keyring_alloc(".dm-verity", 177 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 178 current_cred(), 179 KEY_POS_SEARCH | 180 KEY_USR_VIEW | KEY_USR_READ | 181 KEY_USR_WRITE | KEY_USR_SEARCH | 182 KEY_USR_SETATTR, 183 KEY_ALLOC_NOT_IN_QUOTA, 184 NULL, NULL); 185 if (IS_ERR(dm_verity_keyring)) 186 panic("dm-verity can't allocate keyring\n"); 187 188 if (!dm_verity_keyring_unsealed && 189 keyring_restrict(make_key_ref(dm_verity_keyring, true), NULL, NULL)) 190 panic("dm-verity can't seal keyring\n"); 191 192 return 0; 193 } 194 195 void dm_verity_verify_sig_exit(void) 196 { 197 key_revoke(dm_verity_keyring); 198 key_put(dm_verity_keyring); 199 } 200