Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ima: provide support for arbitrary hash algorithms

In preparation of supporting more hash algorithms with larger hash sizes
needed for signature verification, this patch replaces the 20 byte sized
digest, with a more flexible structure. The new structure includes the
hash algorithm, digest size, and digest.

Changelog:
- recalculate filedata hash for the measurement list, if the signature
hash digest size is greater than 20 bytes.
- use generic HASH_ALGO_
- make ima_calc_file_hash static
- scripts lindent and checkpatch fixes

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>

authored by

Dmitry Kasatkin and committed by
Mimi Zohar
c7c8bb23 3fe78ca2

+100 -35
-2
crypto/asymmetric_keys/x509_parser.h
··· 21 21 char *authority; /* Authority key fingerprint as hex */ 22 22 struct tm valid_from; 23 23 struct tm valid_to; 24 - enum pkey_algo pkey_algo : 8; /* Public key algorithm */ 25 - enum hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ 26 24 const void *tbs; /* Signed data */ 27 25 unsigned tbs_size; /* Size of signed data */ 28 26 unsigned raw_sig_size; /* Size of sigature */
+2 -1
crypto/asymmetric_keys/x509_public_key.c
··· 213 213 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, 214 214 cert->valid_to.tm_mday, cert->valid_to.tm_hour, 215 215 cert->valid_to.tm_min, cert->valid_to.tm_sec); 216 - pr_devel("Cert Signature: %s\n", 216 + pr_devel("Cert Signature: %s + %s\n", 217 + pkey_algo_name[cert->sig.pkey_algo], 217 218 hash_algo_name[cert->sig.pkey_hash_algo]); 218 219 219 220 if (!cert->fingerprint) {
+1
security/integrity/ima/Kconfig
··· 9 9 select CRYPTO_HMAC 10 10 select CRYPTO_MD5 11 11 select CRYPTO_SHA1 12 + select CRYPTO_HASH_INFO 12 13 select TCG_TPM if HAS_IOMEM && !UML 13 14 select TCG_TIS if TCG_TPM && X86 14 15 select TCG_IBMVTPM if TCG_TPM && PPC64
+4 -3
security/integrity/ima/ima.h
··· 39 39 /* set during initialization */ 40 40 extern int ima_initialized; 41 41 extern int ima_used_chip; 42 - extern char *ima_hash; 42 + extern int ima_hash_algo; 43 43 extern int ima_appraise; 44 44 45 45 /* IMA inode template definition */ ··· 70 70 int ima_inode_alloc(struct inode *inode); 71 71 int ima_add_template_entry(struct ima_template_entry *entry, int violation, 72 72 const char *op, struct inode *inode); 73 - int ima_calc_file_hash(struct file *file, char *digest); 74 - int ima_calc_buffer_hash(const void *data, int len, char *digest); 73 + int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash); 74 + int ima_calc_buffer_hash(const void *data, int len, 75 + struct ima_digest_data *hash); 75 76 int ima_calc_boot_aggregate(char *digest); 76 77 void ima_add_violation(struct inode *inode, const unsigned char *filename, 77 78 const char *op, const char *cause);
+24 -8
security/integrity/ima/ima_api.c
··· 44 44 const char *op = "add_template_measure"; 45 45 const char *audit_cause = "hashing_error"; 46 46 int result; 47 + struct ima_digest_data hash; 47 48 48 49 memset(entry->digest, 0, sizeof(entry->digest)); 49 50 entry->template_name = IMA_TEMPLATE_NAME; ··· 52 51 53 52 if (!violation) { 54 53 result = ima_calc_buffer_hash(&entry->template, 55 - entry->template_len, 56 - entry->digest); 54 + entry->template_len, &hash); 57 55 if (result < 0) { 58 56 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, 59 57 entry->template_name, op, 60 58 audit_cause, result, 0); 61 59 return result; 62 60 } 61 + memcpy(entry->digest, hash.digest, hash.length); 63 62 } 64 63 result = ima_add_template_entry(entry, violation, op, inode); 65 64 return result; ··· 148 147 if (!(iint->flags & IMA_COLLECTED)) { 149 148 u64 i_version = file_inode(file)->i_version; 150 149 151 - iint->ima_xattr.type = IMA_XATTR_DIGEST; 152 - result = ima_calc_file_hash(file, iint->ima_xattr.digest); 150 + /* use default hash algorithm */ 151 + iint->ima_hash.algo = ima_hash_algo; 152 + result = ima_calc_file_hash(file, &iint->ima_hash); 153 153 if (!result) { 154 154 iint->version = i_version; 155 155 iint->flags |= IMA_COLLECTED; ··· 198 196 return; 199 197 } 200 198 memset(&entry->template, 0, sizeof(entry->template)); 201 - memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE); 199 + if (iint->ima_hash.algo != ima_hash_algo) { 200 + struct ima_digest_data hash; 201 + 202 + hash.algo = ima_hash_algo; 203 + result = ima_calc_file_hash(file, &hash); 204 + if (result) 205 + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, 206 + filename, "collect_data", "failed", 207 + result, 0); 208 + else 209 + memcpy(entry->template.digest, hash.digest, 210 + hash.length); 211 + } else 212 + memcpy(entry->template.digest, iint->ima_hash.digest, 213 + iint->ima_hash.length); 202 214 strcpy(entry->template.file_name, 203 215 (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? 204 216 file->f_dentry->d_name.name : filename); ··· 228 212 const unsigned char *filename) 229 213 { 230 214 struct audit_buffer *ab; 231 - char hash[(IMA_DIGEST_SIZE * 2) + 1]; 215 + char hash[(iint->ima_hash.length * 2) + 1]; 232 216 int i; 233 217 234 218 if (iint->flags & IMA_AUDITED) 235 219 return; 236 220 237 - for (i = 0; i < IMA_DIGEST_SIZE; i++) 238 - hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]); 221 + for (i = 0; i < iint->ima_hash.length; i++) 222 + hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]); 239 223 hash[i * 2] = '\0'; 240 224 241 225 ab = audit_log_start(current->audit_context, GFP_KERNEL,
+12 -8
security/integrity/ima/ima_appraise.c
··· 43 43 } 44 44 45 45 static int ima_fix_xattr(struct dentry *dentry, 46 - struct integrity_iint_cache *iint) 46 + struct integrity_iint_cache *iint) 47 47 { 48 - iint->ima_xattr.type = IMA_XATTR_DIGEST; 48 + iint->ima_hash.type = IMA_XATTR_DIGEST; 49 49 return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 50 - (u8 *)&iint->ima_xattr, 51 - sizeof(iint->ima_xattr), 0); 50 + &iint->ima_hash.type, 51 + 1 + iint->ima_hash.length, 0); 52 52 } 53 53 54 54 /* Return specific func appraised cached result */ ··· 159 159 status = INTEGRITY_FAIL; 160 160 break; 161 161 } 162 - rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, 163 - IMA_DIGEST_SIZE); 162 + if (rc - 1 == iint->ima_hash.length) 163 + rc = memcmp(xattr_value->digest, 164 + iint->ima_hash.digest, 165 + iint->ima_hash.length); 166 + else 167 + rc = -EINVAL; 164 168 if (rc) { 165 169 cause = "invalid-hash"; 166 170 status = INTEGRITY_FAIL; ··· 176 172 iint->flags |= IMA_DIGSIG; 177 173 rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, 178 174 xattr_value->digest, rc - 1, 179 - iint->ima_xattr.digest, 180 - IMA_DIGEST_SIZE); 175 + iint->ima_hash.digest, 176 + iint->ima_hash.length); 181 177 if (rc == -EOPNOTSUPP) { 182 178 status = INTEGRITY_UNKNOWN; 183 179 } else if (rc) {
+41 -8
security/integrity/ima/ima_crypto.c
··· 20 20 #include <linux/err.h> 21 21 #include <linux/slab.h> 22 22 #include <crypto/hash.h> 23 + #include <crypto/hash_info.h> 23 24 #include "ima.h" 24 25 25 26 static struct crypto_shash *ima_shash_tfm; ··· 29 28 { 30 29 long rc; 31 30 32 - ima_shash_tfm = crypto_alloc_shash(ima_hash, 0, 0); 31 + ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0); 33 32 if (IS_ERR(ima_shash_tfm)) { 34 33 rc = PTR_ERR(ima_shash_tfm); 35 - pr_err("Can not allocate %s (reason: %ld)\n", ima_hash, rc); 34 + pr_err("Can not allocate %s (reason: %ld)\n", 35 + hash_algo_name[ima_hash_algo], rc); 36 36 return rc; 37 37 } 38 38 return 0; ··· 42 40 /* 43 41 * Calculate the MD5/SHA1 file digest 44 42 */ 45 - int ima_calc_file_hash(struct file *file, char *digest) 43 + static int ima_calc_file_hash_tfm(struct file *file, 44 + struct ima_digest_data *hash, 45 + struct crypto_shash *tfm) 46 46 { 47 47 loff_t i_size, offset = 0; 48 48 char *rbuf; 49 49 int rc, read = 0; 50 50 struct { 51 51 struct shash_desc shash; 52 - char ctx[crypto_shash_descsize(ima_shash_tfm)]; 52 + char ctx[crypto_shash_descsize(tfm)]; 53 53 } desc; 54 54 55 - desc.shash.tfm = ima_shash_tfm; 55 + desc.shash.tfm = tfm; 56 56 desc.shash.flags = 0; 57 57 58 58 rc = crypto_shash_init(&desc.shash); ··· 89 85 } 90 86 kfree(rbuf); 91 87 if (!rc) 92 - rc = crypto_shash_final(&desc.shash, digest); 88 + rc = crypto_shash_final(&desc.shash, hash->digest); 93 89 if (read) 94 90 file->f_mode &= ~FMODE_READ; 95 91 out: 96 92 return rc; 97 93 } 98 94 95 + int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) 96 + { 97 + struct crypto_shash *tfm = ima_shash_tfm; 98 + int rc; 99 + 100 + if (hash->algo != ima_hash_algo && hash->algo < HASH_ALGO__LAST) { 101 + tfm = crypto_alloc_shash(hash_algo_name[hash->algo], 0, 0); 102 + if (IS_ERR(tfm)) { 103 + rc = PTR_ERR(tfm); 104 + pr_err("Can not allocate %s (reason: %d)\n", 105 + hash_algo_name[hash->algo], rc); 106 + return rc; 107 + } 108 + } 109 + 110 + hash->length = crypto_shash_digestsize(tfm); 111 + 112 + rc = ima_calc_file_hash_tfm(file, hash, tfm); 113 + 114 + if (tfm != ima_shash_tfm) 115 + crypto_free_shash(tfm); 116 + 117 + return rc; 118 + } 119 + 99 120 /* 100 121 * Calculate the hash of a given buffer 101 122 */ 102 - int ima_calc_buffer_hash(const void *data, int len, char *digest) 123 + int ima_calc_buffer_hash(const void *buf, int len, struct ima_digest_data *hash) 103 124 { 104 125 struct { 105 126 struct shash_desc shash; ··· 134 105 desc.shash.tfm = ima_shash_tfm; 135 106 desc.shash.flags = 0; 136 107 137 - return crypto_shash_digest(&desc.shash, data, len, digest); 108 + /* this function uses default algo */ 109 + hash->algo = ima_hash_algo; 110 + hash->length = crypto_shash_digestsize(ima_shash_tfm); 111 + 112 + return crypto_shash_digest(&desc.shash, buf, len, hash->digest); 138 113 } 139 114 140 115 static void __init ima_pcrread(int idx, u8 *pcr)
+4 -2
security/integrity/ima/ima_main.c
··· 24 24 #include <linux/slab.h> 25 25 #include <linux/xattr.h> 26 26 #include <linux/ima.h> 27 + #include <crypto/hash_info.h> 27 28 28 29 #include "ima.h" 29 30 ··· 36 35 int ima_appraise; 37 36 #endif 38 37 39 - char *ima_hash = "sha1"; 38 + int ima_hash_algo = HASH_ALGO_SHA1; 39 + 40 40 static int __init hash_setup(char *str) 41 41 { 42 42 if (strncmp(str, "md5", 3) == 0) 43 - ima_hash = "md5"; 43 + ima_hash_algo = HASH_ALGO_MD5; 44 44 return 1; 45 45 } 46 46 __setup("ima_hash=", hash_setup);
+12 -3
security/integrity/integrity.h
··· 59 59 struct evm_ima_xattr_data { 60 60 u8 type; 61 61 u8 digest[SHA1_DIGEST_SIZE]; 62 - } __attribute__((packed)); 62 + } __packed; 63 + 64 + #define IMA_MAX_DIGEST_SIZE 64 65 + 66 + struct ima_digest_data { 67 + u8 algo; 68 + u8 length; 69 + u8 type; 70 + u8 digest[IMA_MAX_DIGEST_SIZE]; 71 + } __packed; 63 72 64 73 /* integrity data associated with an inode */ 65 74 struct integrity_iint_cache { 66 - struct rb_node rb_node; /* rooted in integrity_iint_tree */ 75 + struct rb_node rb_node; /* rooted in integrity_iint_tree */ 67 76 struct inode *inode; /* back pointer to inode in question */ 68 77 u64 version; /* track inode changes */ 69 78 unsigned long flags; 70 - struct evm_ima_xattr_data ima_xattr; 71 79 enum integrity_status ima_file_status:4; 72 80 enum integrity_status ima_mmap_status:4; 73 81 enum integrity_status ima_bprm_status:4; 74 82 enum integrity_status ima_module_status:4; 75 83 enum integrity_status evm_status:4; 84 + struct ima_digest_data ima_hash; 76 85 }; 77 86 78 87 /* rbtree tree calls to lookup, insert, delete