1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * IMA support for appraising module-style appended signatures. 4 * 5 * Copyright (C) 2019 IBM Corporation 6 * 7 * Author: 8 * Thiago Jung Bauermann <bauerman@linux.ibm.com> 9 */ 10 11 #include <linux/types.h> 12 #include <linux/module_signature.h> 13 #include <keys/asymmetric-type.h> 14 #include <crypto/pkcs7.h> 15 16 #include "ima.h" 17 18 struct modsig { 19 struct pkcs7_message *pkcs7_msg; 20 21 enum hash_algo hash_algo; 22 23 /* This digest will go in the 'd-modsig' field of the IMA template. */ 24 const u8 *digest; 25 u32 digest_size; 26 27 /* 28 * This is what will go to the measurement list if the template requires 29 * storing the signature. 30 */ 31 int raw_pkcs7_len; 32 u8 raw_pkcs7[] __counted_by(raw_pkcs7_len); 33 }; 34 35 /* 36 * ima_read_modsig - Read modsig from buf. 37 * 38 * Return: 0 on success, error code otherwise. 39 */ 40 int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, 41 struct modsig **modsig) 42 { 43 const size_t marker_len = strlen(MODULE_SIG_STRING); 44 const struct module_signature *sig; 45 struct modsig *hdr; 46 size_t sig_len; 47 const void *p; 48 int rc; 49 50 if (buf_len <= marker_len + sizeof(*sig)) 51 return -ENOENT; 52 53 p = buf + buf_len - marker_len; 54 if (memcmp(p, MODULE_SIG_STRING, marker_len)) 55 return -ENOENT; 56 57 buf_len -= marker_len; 58 sig = (const struct module_signature *)(p - sizeof(*sig)); 59 60 rc = mod_check_sig(sig, buf_len, func_tokens[func]); 61 if (rc) 62 return rc; 63 64 sig_len = be32_to_cpu(sig->sig_len); 65 buf_len -= sig_len + sizeof(*sig); 66 67 /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */ 68 hdr = kzalloc(struct_size(hdr, raw_pkcs7, sig_len), GFP_KERNEL); 69 if (!hdr) 70 return -ENOMEM; 71 72 hdr->raw_pkcs7_len = sig_len; 73 hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len); 74 if (IS_ERR(hdr->pkcs7_msg)) { 75 rc = PTR_ERR(hdr->pkcs7_msg); 76 kfree(hdr); 77 return rc; 78 } 79 80 memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len); 81 82 /* We don't know the hash algorithm yet. */ 83 hdr->hash_algo = HASH_ALGO__LAST; 84 85 *modsig = hdr; 86 87 return 0; 88 } 89 90 /** 91 * ima_collect_modsig - Calculate the file hash without the appended signature. 92 * @modsig: parsed module signature 93 * @buf: data to verify the signature on 94 * @size: data size 95 * 96 * Since the modsig is part of the file contents, the hash used in its signature 97 * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code 98 * calculates a separate one for signature verification. 99 */ 100 void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size) 101 { 102 int rc; 103 104 /* 105 * Provide the file contents (minus the appended sig) so that the PKCS7 106 * code can calculate the file hash. 107 */ 108 size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) + 109 sizeof(struct module_signature); 110 rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size); 111 if (rc) 112 return; 113 114 /* Ask the PKCS7 code to calculate the file hash. */ 115 rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest, 116 &modsig->digest_size, &modsig->hash_algo); 117 } 118 119 int ima_modsig_verify(struct key *keyring, const struct modsig *modsig) 120 { 121 return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring, 122 VERIFYING_MODULE_SIGNATURE, NULL, NULL); 123 } 124 125 int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo, 126 const u8 **digest, u32 *digest_size) 127 { 128 *algo = modsig->hash_algo; 129 *digest = modsig->digest; 130 *digest_size = modsig->digest_size; 131 132 return 0; 133 } 134 135 int ima_get_raw_modsig(const struct modsig *modsig, const void **data, 136 u32 *data_len) 137 { 138 *data = &modsig->raw_pkcs7; 139 *data_len = modsig->raw_pkcs7_len; 140 141 return 0; 142 } 143 144 void ima_free_modsig(struct modsig *modsig) 145 { 146 if (!modsig) 147 return; 148 149 pkcs7_free_message(modsig->pkcs7_msg); 150 kfree(modsig); 151 } 152
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.