1 /* 2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation 3 * 4 * Authors: 5 * Serge Hallyn <serue@us.ibm.com> 6 * Reiner Sailer <sailer@watson.ibm.com> 7 * Mimi Zohar <zohar@us.ibm.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation, version 2 of the 12 * License. 13 * 14 * File: ima_queue.c 15 * Implements queues that store template measurements and 16 * maintains aggregate over the stored measurements 17 * in the pre-configured TPM PCR (if available). 18 * The measurement list is append-only. No entry is 19 * ever removed or changed during the boot-cycle. 20 */ 21 #include <linux/module.h> 22 #include <linux/rculist.h> 23 #include "ima.h" 24 25 LIST_HEAD(ima_measurements); /* list of all measurements */ 26 27 /* key: inode (before secure-hashing a file) */ 28 struct ima_h_table ima_htable = { 29 .len = ATOMIC_LONG_INIT(0), 30 .violations = ATOMIC_LONG_INIT(0), 31 .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT 32 }; 33 34 /* mutex protects atomicity of extending measurement list 35 * and extending the TPM PCR aggregate. Since tpm_extend can take 36 * long (and the tpm driver uses a mutex), we can't use the spinlock. 37 */ 38 static DEFINE_MUTEX(ima_extend_list_mutex); 39 40 /* lookup up the digest value in the hash table, and return the entry */ 41 static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value) 42 { 43 struct ima_queue_entry *qe, *ret = NULL; 44 unsigned int key; 45 struct hlist_node *pos; 46 int rc; 47 48 key = ima_hash_key(digest_value); 49 rcu_read_lock(); 50 hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) { 51 rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE); 52 if (rc == 0) { 53 ret = qe; 54 break; 55 } 56 } 57 rcu_read_unlock(); 58 return ret; 59 } 60 61 /* ima_add_template_entry helper function: 62 * - Add template entry to measurement list and hash table. 63 * 64 * (Called with ima_extend_list_mutex held.) 65 */ 66 static int ima_add_digest_entry(struct ima_template_entry *entry) 67 { 68 struct ima_queue_entry *qe; 69 unsigned int key; 70 71 qe = kmalloc(sizeof(*qe), GFP_KERNEL); 72 if (qe == NULL) { 73 pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); 74 return -ENOMEM; 75 } 76 qe->entry = entry; 77 78 INIT_LIST_HEAD(&qe->later); 79 list_add_tail_rcu(&qe->later, &ima_measurements); 80 81 atomic_long_inc(&ima_htable.len); 82 key = ima_hash_key(entry->digest); 83 hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); 84 return 0; 85 } 86 87 static int ima_pcr_extend(const u8 *hash) 88 { 89 int result = 0; 90 91 if (!ima_used_chip) 92 return result; 93 94 result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); 95 if (result != 0) 96 pr_err("Error Communicating to TPM chip\n"); 97 return result; 98 } 99 100 /* Add template entry to the measurement list and hash table, 101 * and extend the pcr. 102 */ 103 int ima_add_template_entry(struct ima_template_entry *entry, int violation, 104 const char *op, struct inode *inode) 105 { 106 u8 digest[IMA_DIGEST_SIZE]; 107 const char *audit_cause = "hash_added"; 108 int audit_info = 1; 109 int result = 0; 110 111 mutex_lock(&ima_extend_list_mutex); 112 if (!violation) { 113 memcpy(digest, entry->digest, sizeof digest); 114 if (ima_lookup_digest_entry(digest)) { 115 audit_cause = "hash_exists"; 116 goto out; 117 } 118 } 119 120 result = ima_add_digest_entry(entry); 121 if (result < 0) { 122 audit_cause = "ENOMEM"; 123 audit_info = 0; 124 goto out; 125 } 126 127 if (violation) /* invalidate pcr */ 128 memset(digest, 0xff, sizeof digest); 129 130 result = ima_pcr_extend(digest); 131 if (result != 0) { 132 audit_cause = "TPM error"; 133 audit_info = 0; 134 } 135 out: 136 mutex_unlock(&ima_extend_list_mutex); 137 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, 138 entry->template.file_name, 139 op, audit_cause, result, audit_info); 140 return result; 141 } 142