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 <linux/slab.h> 24 #include "ima.h" 25 26 LIST_HEAD(ima_measurements); /* list of all measurements */ 27 28 /* key: inode (before secure-hashing a file) */ 29 struct ima_h_table ima_htable = { 30 .len = ATOMIC_LONG_INIT(0), 31 .violations = ATOMIC_LONG_INIT(0), 32 .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT 33 }; 34 35 /* mutex protects atomicity of extending measurement list 36 * and extending the TPM PCR aggregate. Since tpm_extend can take 37 * long (and the tpm driver uses a mutex), we can't use the spinlock. 38 */ 39 static DEFINE_MUTEX(ima_extend_list_mutex); 40 41 /* lookup up the digest value in the hash table, and return the entry */ 42 static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value) 43 { 44 struct ima_queue_entry *qe, *ret = NULL; 45 unsigned int key; 46 struct hlist_node *pos; 47 int rc; 48 49 key = ima_hash_key(digest_value); 50 rcu_read_lock(); 51 hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) { 52 rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE); 53 if (rc == 0) { 54 ret = qe; 55 break; 56 } 57 } 58 rcu_read_unlock(); 59 return ret; 60 } 61 62 /* ima_add_template_entry helper function: 63 * - Add template entry to measurement list and hash table. 64 * 65 * (Called with ima_extend_list_mutex held.) 66 */ 67 static int ima_add_digest_entry(struct ima_template_entry *entry) 68 { 69 struct ima_queue_entry *qe; 70 unsigned int key; 71 72 qe = kmalloc(sizeof(*qe), GFP_KERNEL); 73 if (qe == NULL) { 74 pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n"); 75 return -ENOMEM; 76 } 77 qe->entry = entry; 78 79 INIT_LIST_HEAD(&qe->later); 80 list_add_tail_rcu(&qe->later, &ima_measurements); 81 82 atomic_long_inc(&ima_htable.len); 83 key = ima_hash_key(entry->digest); 84 hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); 85 return 0; 86 } 87 88 static int ima_pcr_extend(const u8 *hash) 89 { 90 int result = 0; 91 92 if (!ima_used_chip) 93 return result; 94 95 result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); 96 if (result != 0) 97 pr_err("IMA: Error Communicating to TPM chip\n"); 98 return result; 99 } 100 101 /* Add template entry to the measurement list and hash table, 102 * and extend the pcr. 103 */ 104 int ima_add_template_entry(struct ima_template_entry *entry, int violation, 105 const char *op, struct inode *inode) 106 { 107 u8 digest[IMA_DIGEST_SIZE]; 108 const char *audit_cause = "hash_added"; 109 int audit_info = 1; 110 int result = 0; 111 112 mutex_lock(&ima_extend_list_mutex); 113 if (!violation) { 114 memcpy(digest, entry->digest, sizeof digest); 115 if (ima_lookup_digest_entry(digest)) { 116 audit_cause = "hash_exists"; 117 goto out; 118 } 119 } 120 121 result = ima_add_digest_entry(entry); 122 if (result < 0) { 123 audit_cause = "ENOMEM"; 124 audit_info = 0; 125 goto out; 126 } 127 128 if (violation) /* invalidate pcr */ 129 memset(digest, 0xff, sizeof digest); 130 131 result = ima_pcr_extend(digest); 132 if (result != 0) { 133 audit_cause = "TPM error"; 134 audit_info = 0; 135 } 136 out: 137 mutex_unlock(&ima_extend_list_mutex); 138 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, 139 entry->template.file_name, 140 op, audit_cause, result, audit_info); 141 return result; 142 } 143