aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima
diff options
context:
space:
mode:
authorMimi Zohar <zohar@linux.vnet.ibm.com>2009-02-04 09:06:58 -0500
committerJames Morris <jmorris@namei.org>2009-02-05 17:05:30 -0500
commit3323eec921efd815178a23107ab63588c605c0b2 (patch)
treebc9e9714ac4881ebc515c1bd155674c52c356d6a /security/integrity/ima
parent6146f0d5e47ca4047ffded0fb79b6c25359b386c (diff)
integrity: IMA as an integrity service provider
IMA provides hardware (TPM) based measurement and attestation for file measurements. As the Trusted Computing (TPM) model requires, IMA measures all files before they are accessed in any way (on the integrity_bprm_check, integrity_path_check and integrity_file_mmap hooks), and commits the measurements to the TPM. Once added to the TPM, measurements can not be removed. In addition, IMA maintains a list of these file measurements, which can be used to validate the aggregate value stored in the TPM. The TPM can sign these measurements, and thus the system can prove, to itself and to a third party, the system's integrity in a way that cannot be circumvented by malicious or compromised software. - alloc ima_template_entry before calling ima_store_template() - log ima_add_boot_aggregate() failure - removed unused IMA_TEMPLATE_NAME_LEN - replaced hard coded string length with #define name Signed-off-by: Mimi Zohar <zohar@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/Kconfig49
-rw-r--r--security/integrity/ima/Makefile9
-rw-r--r--security/integrity/ima/ima.h135
-rw-r--r--security/integrity/ima/ima_api.c190
-rw-r--r--security/integrity/ima/ima_audit.c78
-rw-r--r--security/integrity/ima/ima_crypto.c140
-rw-r--r--security/integrity/ima/ima_iint.c185
-rw-r--r--security/integrity/ima/ima_init.c90
-rw-r--r--security/integrity/ima/ima_main.c280
-rw-r--r--security/integrity/ima/ima_policy.c126
-rw-r--r--security/integrity/ima/ima_queue.c140
11 files changed, 1422 insertions, 0 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
new file mode 100644
index 000000000000..2a761c8ac996
--- /dev/null
+++ b/security/integrity/ima/Kconfig
@@ -0,0 +1,49 @@
1# IBM Integrity Measurement Architecture
2#
3config IMA
4 bool "Integrity Measurement Architecture(IMA)"
5 depends on ACPI
6 select SECURITYFS
7 select CRYPTO
8 select CRYPTO_HMAC
9 select CRYPTO_MD5
10 select CRYPTO_SHA1
11 select TCG_TPM
12 select TCG_TIS
13 help
14 The Trusted Computing Group(TCG) runtime Integrity
15 Measurement Architecture(IMA) maintains a list of hash
16 values of executables and other sensitive system files,
17 as they are read or executed. If an attacker manages
18 to change the contents of an important system file
19 being measured, we can tell.
20
21 If your system has a TPM chip, then IMA also maintains
22 an aggregate integrity value over this list inside the
23 TPM hardware, so that the TPM can prove to a third party
24 whether or not critical system files have been modified.
25 Read <http://www.usenix.org/events/sec04/tech/sailer.html>
26 to learn more about IMA.
27 If unsure, say N.
28
29config IMA_MEASURE_PCR_IDX
30 int
31 depends on IMA
32 range 8 14
33 default 10
34 help
35 IMA_MEASURE_PCR_IDX determines the TPM PCR register index
36 that IMA uses to maintain the integrity aggregate of the
37 measurement list. If unsure, use the default 10.
38
39config IMA_AUDIT
40 bool
41 depends on IMA
42 default y
43 help
44 This option adds a kernel parameter 'ima_audit', which
45 allows informational auditing messages to be enabled
46 at boot. If this option is selected, informational integrity
47 auditing messages can be enabled with 'ima_audit=1' on
48 the kernel command line.
49
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
new file mode 100644
index 000000000000..9d6bf973b9be
--- /dev/null
+++ b/security/integrity/ima/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for building Trusted Computing Group's(TCG) runtime Integrity
3# Measurement Architecture(IMA).
4#
5
6obj-$(CONFIG_IMA) += ima.o
7
8ima-y := ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
9 ima_policy.o ima_iint.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
new file mode 100644
index 000000000000..bfa72ed41b9b
--- /dev/null
+++ b/security/integrity/ima/ima.h
@@ -0,0 +1,135 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Reiner Sailer <sailer@watson.ibm.com>
6 * Mimi Zohar <zohar@us.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, version 2 of the
11 * License.
12 *
13 * File: ima.h
14 * internal Integrity Measurement Architecture (IMA) definitions
15 */
16
17#ifndef __LINUX_IMA_H
18#define __LINUX_IMA_H
19
20#include <linux/types.h>
21#include <linux/crypto.h>
22#include <linux/security.h>
23#include <linux/hash.h>
24#include <linux/tpm.h>
25#include <linux/audit.h>
26
27enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII };
28enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
29
30/* digest size for IMA, fits SHA1 or MD5 */
31#define IMA_DIGEST_SIZE 20
32#define IMA_EVENT_NAME_LEN_MAX 255
33
34#define IMA_HASH_BITS 9
35#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
36
37/* set during initialization */
38extern int ima_initialized;
39extern int ima_used_chip;
40extern char *ima_hash;
41
42/* IMA inode template definition */
43struct ima_template_data {
44 u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */
45 char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */
46};
47
48struct ima_template_entry {
49 u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
50 char *template_name;
51 int template_len;
52 struct ima_template_data template;
53};
54
55struct ima_queue_entry {
56 struct hlist_node hnext; /* place in hash collision list */
57 struct list_head later; /* place in ima_measurements list */
58 struct ima_template_entry *entry;
59};
60extern struct list_head ima_measurements; /* list of all measurements */
61
62/* declarations */
63void integrity_audit_msg(int audit_msgno, struct inode *inode,
64 const unsigned char *fname, const char *op,
65 const char *cause, int result, int info);
66
67/* Internal IMA function definitions */
68void ima_iintcache_init(void);
69int ima_init(void);
70int ima_add_template_entry(struct ima_template_entry *entry, int violation,
71 const char *op, struct inode *inode);
72int ima_calc_hash(struct file *file, char *digest);
73int ima_calc_template_hash(int template_len, void *template, char *digest);
74int ima_calc_boot_aggregate(char *digest);
75void ima_add_violation(struct inode *inode, const unsigned char *filename,
76 const char *op, const char *cause);
77
78/*
79 * used to protect h_table and sha_table
80 */
81extern spinlock_t ima_queue_lock;
82
83struct ima_h_table {
84 atomic_long_t len; /* number of stored measurements in the list */
85 atomic_long_t violations;
86 struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
87};
88extern struct ima_h_table ima_htable;
89
90static inline unsigned long ima_hash_key(u8 *digest)
91{
92 return hash_long(*digest, IMA_HASH_BITS);
93}
94
95/* iint cache flags */
96#define IMA_MEASURED 1
97
98/* integrity data associated with an inode */
99struct ima_iint_cache {
100 u64 version; /* track inode changes */
101 unsigned long flags;
102 u8 digest[IMA_DIGEST_SIZE];
103 struct mutex mutex; /* protects: version, flags, digest */
104 long readcount; /* measured files readcount */
105 long writecount; /* measured files writecount */
106 struct kref refcount; /* ima_iint_cache reference count */
107 struct rcu_head rcu;
108};
109
110/* LIM API function definitions */
111int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
112 int mask, int function);
113int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
114void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
115 const unsigned char *filename);
116int ima_store_template(struct ima_template_entry *entry, int violation,
117 struct inode *inode);
118
119/* radix tree calls to lookup, insert, delete
120 * integrity data associated with an inode.
121 */
122struct ima_iint_cache *ima_iint_insert(struct inode *inode);
123struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
124struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode);
125void ima_iint_delete(struct inode *inode);
126void iint_free(struct kref *kref);
127void iint_rcu_free(struct rcu_head *rcu);
128
129/* IMA policy related functions */
130enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK };
131
132int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
133void ima_init_policy(void);
134void ima_update_policy(void);
135#endif
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
new file mode 100644
index 000000000000..a148a25804f6
--- /dev/null
+++ b/security/integrity/ima/ima_api.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (C) 2008 IBM Corporation
3 *
4 * Author: Mimi Zohar <zohar@us.ibm.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2 of the
9 * License.
10 *
11 * File: ima_api.c
12 * Implements must_measure, collect_measurement, store_measurement,
13 * and store_template.
14 */
15#include <linux/module.h>
16
17#include "ima.h"
18static char *IMA_TEMPLATE_NAME = "ima";
19
20/*
21 * ima_store_template - store ima template measurements
22 *
23 * Calculate the hash of a template entry, add the template entry
24 * to an ordered list of measurement entries maintained inside the kernel,
25 * and also update the aggregate integrity value (maintained inside the
26 * configured TPM PCR) over the hashes of the current list of measurement
27 * entries.
28 *
29 * Applications retrieve the current kernel-held measurement list through
30 * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
31 * TPM PCR (called quote) can be retrieved using a TPM user space library
32 * and is used to validate the measurement list.
33 *
34 * Returns 0 on success, error code otherwise
35 */
36int ima_store_template(struct ima_template_entry *entry,
37 int violation, struct inode *inode)
38{
39 const char *op = "add_template_measure";
40 const char *audit_cause = "hashing_error";
41 int result;
42
43 memset(entry->digest, 0, sizeof(entry->digest));
44 entry->template_name = IMA_TEMPLATE_NAME;
45 entry->template_len = sizeof(entry->template);
46
47 if (!violation) {
48 result = ima_calc_template_hash(entry->template_len,
49 &entry->template,
50 entry->digest);
51 if (result < 0) {
52 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
53 entry->template_name, op,
54 audit_cause, result, 0);
55 return result;
56 }
57 }
58 result = ima_add_template_entry(entry, violation, op, inode);
59 return result;
60}
61
62/*
63 * ima_add_violation - add violation to measurement list.
64 *
65 * Violations are flagged in the measurement list with zero hash values.
66 * By extending the PCR with 0xFF's instead of with zeroes, the PCR
67 * value is invalidated.
68 */
69void ima_add_violation(struct inode *inode, const unsigned char *filename,
70 const char *op, const char *cause)
71{
72 struct ima_template_entry *entry;
73 int violation = 1;
74 int result;
75
76 /* can overflow, only indicator */
77 atomic_long_inc(&ima_htable.violations);
78
79 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
80 if (!entry) {
81 result = -ENOMEM;
82 goto err_out;
83 }
84 memset(&entry->template, 0, sizeof(entry->template));
85 strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
86 result = ima_store_template(entry, violation, inode);
87 if (result < 0)
88 kfree(entry);
89err_out:
90 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
91 op, cause, result, 0);
92}
93
94/**
95 * ima_must_measure - measure decision based on policy.
96 * @inode: pointer to inode to measure
97 * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
98 * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP)
99 *
100 * The policy is defined in terms of keypairs:
101 * subj=, obj=, type=, func=, mask=, fsmagic=
102 * subj,obj, and type: are LSM specific.
103 * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP
104 * mask: contains the permission mask
105 * fsmagic: hex value
106 *
107 * Must be called with iint->mutex held.
108 *
109 * Return 0 to measure. Return 1 if already measured.
110 * For matching a DONT_MEASURE policy, no policy, or other
111 * error, return an error code.
112*/
113int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
114 int mask, int function)
115{
116 int must_measure;
117
118 if (iint->flags & IMA_MEASURED)
119 return 1;
120
121 must_measure = ima_match_policy(inode, function, mask);
122 return must_measure ? 0 : -EACCES;
123}
124
125/*
126 * ima_collect_measurement - collect file measurement
127 *
128 * Calculate the file hash, if it doesn't already exist,
129 * storing the measurement and i_version in the iint.
130 *
131 * Must be called with iint->mutex held.
132 *
133 * Return 0 on success, error code otherwise
134 */
135int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
136{
137 int result = -EEXIST;
138
139 if (!(iint->flags & IMA_MEASURED)) {
140 u64 i_version = file->f_dentry->d_inode->i_version;
141
142 memset(iint->digest, 0, IMA_DIGEST_SIZE);
143 result = ima_calc_hash(file, iint->digest);
144 if (!result)
145 iint->version = i_version;
146 }
147 return result;
148}
149
150/*
151 * ima_store_measurement - store file measurement
152 *
153 * Create an "ima" template and then store the template by calling
154 * ima_store_template.
155 *
156 * We only get here if the inode has not already been measured,
157 * but the measurement could already exist:
158 * - multiple copies of the same file on either the same or
159 * different filesystems.
160 * - the inode was previously flushed as well as the iint info,
161 * containing the hashing info.
162 *
163 * Must be called with iint->mutex held.
164 */
165void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
166 const unsigned char *filename)
167{
168 const char *op = "add_template_measure";
169 const char *audit_cause = "ENOMEM";
170 int result = -ENOMEM;
171 struct inode *inode = file->f_dentry->d_inode;
172 struct ima_template_entry *entry;
173 int violation = 0;
174
175 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
176 if (!entry) {
177 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
178 op, audit_cause, result, 0);
179 return;
180 }
181 memset(&entry->template, 0, sizeof(entry->template));
182 memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
183 strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
184
185 result = ima_store_template(entry, violation, inode);
186 if (!result)
187 iint->flags |= IMA_MEASURED;
188 else
189 kfree(entry);
190}
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c
new file mode 100644
index 000000000000..8a0f1e23ccf1
--- /dev/null
+++ b/security/integrity/ima/ima_audit.c
@@ -0,0 +1,78 @@
1/*
2 * Copyright (C) 2008 IBM Corporation
3 * Author: Mimi Zohar <zohar@us.ibm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
8 *
9 * File: integrity_audit.c
10 * Audit calls for the integrity subsystem
11 */
12
13#include <linux/fs.h>
14#include <linux/audit.h>
15#include "ima.h"
16
17static int ima_audit;
18
19#ifdef CONFIG_IMA_AUDIT
20
21/* ima_audit_setup - enable informational auditing messages */
22static int __init ima_audit_setup(char *str)
23{
24 unsigned long audit;
25 int rc;
26 char *op;
27
28 rc = strict_strtoul(str, 0, &audit);
29 if (rc || audit > 1)
30 printk(KERN_INFO "ima: invalid ima_audit value\n");
31 else
32 ima_audit = audit;
33 op = ima_audit ? "ima_audit_enabled" : "ima_audit_not_enabled";
34 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0, 0);
35 return 1;
36}
37__setup("ima_audit=", ima_audit_setup);
38#endif
39
40void integrity_audit_msg(int audit_msgno, struct inode *inode,
41 const unsigned char *fname, const char *op,
42 const char *cause, int result, int audit_info)
43{
44 struct audit_buffer *ab;
45
46 if (!ima_audit && audit_info == 1) /* Skip informational messages */
47 return;
48
49 ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
50 audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u",
51 current->pid, current->cred->uid,
52 audit_get_loginuid(current));
53 audit_log_task_context(ab);
54 switch (audit_msgno) {
55 case AUDIT_INTEGRITY_DATA:
56 case AUDIT_INTEGRITY_METADATA:
57 case AUDIT_INTEGRITY_PCR:
58 audit_log_format(ab, " op=%s cause=%s", op, cause);
59 break;
60 case AUDIT_INTEGRITY_HASH:
61 audit_log_format(ab, " op=%s hash=%s", op, cause);
62 break;
63 case AUDIT_INTEGRITY_STATUS:
64 default:
65 audit_log_format(ab, " op=%s", op);
66 }
67 audit_log_format(ab, " comm=");
68 audit_log_untrustedstring(ab, current->comm);
69 if (fname) {
70 audit_log_format(ab, " name=");
71 audit_log_untrustedstring(ab, fname);
72 }
73 if (inode)
74 audit_log_format(ab, " dev=%s ino=%lu",
75 inode->i_sb->s_id, inode->i_ino);
76 audit_log_format(ab, " res=%d", result);
77 audit_log_end(ab);
78}
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
new file mode 100644
index 000000000000..c2a46e40999d
--- /dev/null
+++ b/security/integrity/ima/ima_crypto.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Mimi Zohar <zohar@us.ibm.com>
6 * Kylene Hall <kjhall@us.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, version 2 of the License.
11 *
12 * File: ima_crypto.c
13 * Calculates md5/sha1 file hash, template hash, boot-aggreate hash
14 */
15
16#include <linux/kernel.h>
17#include <linux/file.h>
18#include <linux/crypto.h>
19#include <linux/scatterlist.h>
20#include <linux/err.h>
21#include "ima.h"
22
23static int init_desc(struct hash_desc *desc)
24{
25 int rc;
26
27 desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
28 if (IS_ERR(desc->tfm)) {
29 pr_info("failed to load %s transform: %ld\n",
30 ima_hash, PTR_ERR(desc->tfm));
31 rc = PTR_ERR(desc->tfm);
32 return rc;
33 }
34 desc->flags = 0;
35 rc = crypto_hash_init(desc);
36 if (rc)
37 crypto_free_hash(desc->tfm);
38 return rc;
39}
40
41/*
42 * Calculate the MD5/SHA1 file digest
43 */
44int ima_calc_hash(struct file *file, char *digest)
45{
46 struct hash_desc desc;
47 struct scatterlist sg[1];
48 loff_t i_size;
49 char *rbuf;
50 int rc, offset = 0;
51
52 rc = init_desc(&desc);
53 if (rc != 0)
54 return rc;
55
56 rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
57 if (!rbuf) {
58 rc = -ENOMEM;
59 goto out;
60 }
61 i_size = i_size_read(file->f_dentry->d_inode);
62 while (offset < i_size) {
63 int rbuf_len;
64
65 rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
66 if (rbuf_len < 0) {
67 rc = rbuf_len;
68 break;
69 }
70 offset += rbuf_len;
71 sg_set_buf(sg, rbuf, rbuf_len);
72
73 rc = crypto_hash_update(&desc, sg, rbuf_len);
74 if (rc)
75 break;
76 }
77 kfree(rbuf);
78 if (!rc)
79 rc = crypto_hash_final(&desc, digest);
80out:
81 crypto_free_hash(desc.tfm);
82 return rc;
83}
84
85/*
86 * Calculate the hash of a given template
87 */
88int ima_calc_template_hash(int template_len, void *template, char *digest)
89{
90 struct hash_desc desc;
91 struct scatterlist sg[1];
92 int rc;
93
94 rc = init_desc(&desc);
95 if (rc != 0)
96 return rc;
97
98 sg_set_buf(sg, template, template_len);
99 rc = crypto_hash_update(&desc, sg, template_len);
100 if (!rc)
101 rc = crypto_hash_final(&desc, digest);
102 crypto_free_hash(desc.tfm);
103 return rc;
104}
105
106static void ima_pcrread(int idx, u8 *pcr)
107{
108 if (!ima_used_chip)
109 return;
110
111 if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
112 pr_err("Error Communicating to TPM chip\n");
113}
114
115/*
116 * Calculate the boot aggregate hash
117 */
118int ima_calc_boot_aggregate(char *digest)
119{
120 struct hash_desc desc;
121 struct scatterlist sg;
122 u8 pcr_i[IMA_DIGEST_SIZE];
123 int rc, i;
124
125 rc = init_desc(&desc);
126 if (rc != 0)
127 return rc;
128
129 /* cumulative sha1 over tpm registers 0-7 */
130 for (i = TPM_PCR0; i < TPM_PCR8; i++) {
131 ima_pcrread(i, pcr_i);
132 /* now accumulate with current aggregate */
133 sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE);
134 rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE);
135 }
136 if (!rc)
137 crypto_hash_final(&desc, digest);
138 crypto_free_hash(desc.tfm);
139 return rc;
140}
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
new file mode 100644
index 000000000000..750db3c993a7
--- /dev/null
+++ b/security/integrity/ima/ima_iint.c
@@ -0,0 +1,185 @@
1/*
2 * Copyright (C) 2008 IBM Corporation
3 *
4 * Authors:
5 * Mimi Zohar <zohar@us.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2 of the
10 * License.
11 *
12 * File: ima_iint.c
13 * - implements the IMA hooks: ima_inode_alloc, ima_inode_free
14 * - cache integrity information associated with an inode
15 * using a radix tree.
16 */
17#include <linux/module.h>
18#include <linux/spinlock.h>
19#include <linux/radix-tree.h>
20#include "ima.h"
21
22#define ima_iint_delete ima_inode_free
23
24RADIX_TREE(ima_iint_store, GFP_ATOMIC);
25DEFINE_SPINLOCK(ima_iint_lock);
26
27static struct kmem_cache *iint_cache __read_mostly;
28
29/* ima_iint_find_get - return the iint associated with an inode
30 *
31 * ima_iint_find_get gets a reference to the iint. Caller must
32 * remember to put the iint reference.
33 */
34struct ima_iint_cache *ima_iint_find_get(struct inode *inode)
35{
36 struct ima_iint_cache *iint;
37
38 rcu_read_lock();
39 iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode);
40 if (!iint)
41 goto out;
42 kref_get(&iint->refcount);
43out:
44 rcu_read_unlock();
45 return iint;
46}
47
48/* Allocate memory for the iint associated with the inode
49 * from the iint_cache slab, initialize the iint, and
50 * insert it into the radix tree.
51 *
52 * On success return a pointer to the iint; on failure return NULL.
53 */
54struct ima_iint_cache *ima_iint_insert(struct inode *inode)
55{
56 struct ima_iint_cache *iint = NULL;
57 int rc = 0;
58
59 if (!ima_initialized)
60 return iint;
61 iint = kmem_cache_alloc(iint_cache, GFP_KERNEL);
62 if (!iint)
63 return iint;
64
65 rc = radix_tree_preload(GFP_KERNEL);
66 if (rc < 0)
67 goto out;
68
69 spin_lock(&ima_iint_lock);
70 rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
71 spin_unlock(&ima_iint_lock);
72out:
73 if (rc < 0) {
74 kmem_cache_free(iint_cache, iint);
75 if (rc == -EEXIST) {
76 iint = radix_tree_lookup(&ima_iint_store,
77 (unsigned long)inode);
78 } else
79 iint = NULL;
80 }
81 radix_tree_preload_end();
82 return iint;
83}
84
85/**
86 * ima_inode_alloc - allocate an iint associated with an inode
87 * @inode: pointer to the inode
88 *
89 * Return 0 on success, 1 on failure.
90 */
91int ima_inode_alloc(struct inode *inode)
92{
93 struct ima_iint_cache *iint;
94
95 if (!ima_initialized)
96 return 0;
97
98 iint = ima_iint_insert(inode);
99 if (!iint)
100 return 1;
101 return 0;
102}
103
104/* ima_iint_find_insert_get - get the iint associated with an inode
105 *
106 * Most insertions are done at inode_alloc, except those allocated
107 * before late_initcall. When the iint does not exist, allocate it,
108 * initialize and insert it, and increment the iint refcount.
109 *
110 * (Can't initialize at security_initcall before any inodes are
111 * allocated, got to wait at least until proc_init.)
112 *
113 * Return the iint.
114 */
115struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode)
116{
117 struct ima_iint_cache *iint = NULL;
118
119 iint = ima_iint_find_get(inode);
120 if (iint)
121 return iint;
122
123 iint = ima_iint_insert(inode);
124 if (iint)
125 kref_get(&iint->refcount);
126
127 return iint;
128}
129
130/* iint_free - called when the iint refcount goes to zero */
131void iint_free(struct kref *kref)
132{
133 struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
134 refcount);
135 iint->version = 0;
136 iint->flags = 0UL;
137 kref_set(&iint->refcount, 1);
138 kmem_cache_free(iint_cache, iint);
139}
140
141void iint_rcu_free(struct rcu_head *rcu_head)
142{
143 struct ima_iint_cache *iint = container_of(rcu_head,
144 struct ima_iint_cache, rcu);
145 kref_put(&iint->refcount, iint_free);
146}
147
148/**
149 * ima_iint_delete - called on integrity_inode_free
150 * @inode: pointer to the inode
151 *
152 * Free the integrity information(iint) associated with an inode.
153 */
154void ima_iint_delete(struct inode *inode)
155{
156 struct ima_iint_cache *iint;
157
158 if (!ima_initialized)
159 return;
160 spin_lock(&ima_iint_lock);
161 iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
162 spin_unlock(&ima_iint_lock);
163 if (iint)
164 call_rcu(&iint->rcu, iint_rcu_free);
165}
166
167static void init_once(void *foo)
168{
169 struct ima_iint_cache *iint = foo;
170
171 memset(iint, 0, sizeof *iint);
172 iint->version = 0;
173 iint->flags = 0UL;
174 mutex_init(&iint->mutex);
175 iint->readcount = 0;
176 iint->writecount = 0;
177 kref_set(&iint->refcount, 1);
178}
179
180void ima_iintcache_init(void)
181{
182 iint_cache =
183 kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
184 SLAB_PANIC, init_once);
185}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
new file mode 100644
index 000000000000..e0f02e328d77
--- /dev/null
+++ b/security/integrity/ima/ima_init.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Reiner Sailer <sailer@watson.ibm.com>
6 * Leendert van Doorn <leendert@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_init.c
15 * initialization and cleanup functions
16 */
17#include <linux/module.h>
18#include <linux/scatterlist.h>
19#include <linux/err.h>
20#include "ima.h"
21
22/* name for boot aggregate entry */
23static char *boot_aggregate_name = "boot_aggregate";
24int ima_used_chip;
25
26/* Add the boot aggregate to the IMA measurement list and extend
27 * the PCR register.
28 *
29 * Calculate the boot aggregate, a SHA1 over tpm registers 0-7,
30 * assuming a TPM chip exists, and zeroes if the TPM chip does not
31 * exist. Add the boot aggregate measurement to the measurement
32 * list and extend the PCR register.
33 *
34 * If a tpm chip does not exist, indicate the core root of trust is
35 * not hardware based by invalidating the aggregate PCR value.
36 * (The aggregate PCR value is invalidated by adding one value to
37 * the measurement list and extending the aggregate PCR value with
38 * a different value.) Violations add a zero entry to the measurement
39 * list and extend the aggregate PCR value with ff...ff's.
40 */
41static void ima_add_boot_aggregate(void)
42{
43 struct ima_template_entry *entry;
44 const char *op = "add_boot_aggregate";
45 const char *audit_cause = "ENOMEM";
46 int result = -ENOMEM;
47 int violation = 1;
48
49 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
50 if (!entry)
51 goto err_out;
52
53 memset(&entry->template, 0, sizeof(entry->template));
54 strncpy(entry->template.file_name, boot_aggregate_name,
55 IMA_EVENT_NAME_LEN_MAX);
56 if (ima_used_chip) {
57 violation = 0;
58 result = ima_calc_boot_aggregate(entry->template.digest);
59 if (result < 0) {
60 audit_cause = "hashing_error";
61 kfree(entry);
62 goto err_out;
63 }
64 }
65 result = ima_store_template(entry, violation, NULL);
66 if (result < 0)
67 kfree(entry);
68 return;
69err_out:
70 integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
71 audit_cause, result, 0);
72}
73
74int ima_init(void)
75{
76 u8 pcr_i[IMA_DIGEST_SIZE];
77 int rc;
78
79 ima_used_chip = 0;
80 rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i);
81 if (rc == 0)
82 ima_used_chip = 1;
83
84 if (!ima_used_chip)
85 pr_info("No TPM chip found, activating TPM-bypass!\n");
86
87 ima_add_boot_aggregate(); /* boot aggregate must be first entry */
88 ima_init_policy();
89 return 0;
90}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
new file mode 100644
index 000000000000..53cee4c512ce
--- /dev/null
+++ b/security/integrity/ima/ima_main.c
@@ -0,0 +1,280 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Reiner Sailer <sailer@watson.ibm.com>
6 * Serge Hallyn <serue@us.ibm.com>
7 * Kylene Hall <kylene@us.ibm.com>
8 * Mimi Zohar <zohar@us.ibm.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, version 2 of the
13 * License.
14 *
15 * File: ima_main.c
16 * implements the IMA hooks: ima_bprm_check, ima_file_mmap,
17 * and ima_path_check.
18 */
19#include <linux/module.h>
20#include <linux/file.h>
21#include <linux/binfmts.h>
22#include <linux/mount.h>
23#include <linux/mman.h>
24
25#include "ima.h"
26
27int ima_initialized;
28
29char *ima_hash = "sha1";
30static int __init hash_setup(char *str)
31{
32 const char *op = "hash_setup";
33 const char *hash = "sha1";
34 int result = 0;
35 int audit_info = 0;
36
37 if (strncmp(str, "md5", 3) == 0) {
38 hash = "md5";
39 ima_hash = str;
40 } else if (strncmp(str, "sha1", 4) != 0) {
41 hash = "invalid_hash_type";
42 result = 1;
43 }
44 integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash,
45 result, audit_info);
46 return 1;
47}
48__setup("ima_hash=", hash_setup);
49
50/**
51 * ima_file_free - called on __fput()
52 * @file: pointer to file structure being freed
53 *
54 * Flag files that changed, based on i_version;
55 * and decrement the iint readcount/writecount.
56 */
57void ima_file_free(struct file *file)
58{
59 struct inode *inode = file->f_dentry->d_inode;
60 struct ima_iint_cache *iint;
61
62 if (!ima_initialized || !S_ISREG(inode->i_mode))
63 return;
64 iint = ima_iint_find_get(inode);
65 if (!iint)
66 return;
67
68 mutex_lock(&iint->mutex);
69 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
70 iint->readcount--;
71
72 if (file->f_mode & FMODE_WRITE) {
73 iint->writecount--;
74 if (iint->writecount == 0) {
75 if (iint->version != inode->i_version)
76 iint->flags &= ~IMA_MEASURED;
77 }
78 }
79 mutex_unlock(&iint->mutex);
80 kref_put(&iint->refcount, iint_free);
81}
82
83/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
84 *
85 * When opening a file for read, if the file is already open for write,
86 * the file could change, resulting in a file measurement error.
87 *
88 * Opening a file for write, if the file is already open for read, results
89 * in a time of measure, time of use (ToMToU) error.
90 *
91 * In either case invalidate the PCR.
92 */
93enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
94static void ima_read_write_check(enum iint_pcr_error error,
95 struct ima_iint_cache *iint,
96 struct inode *inode,
97 const unsigned char *filename)
98{
99 switch (error) {
100 case TOMTOU:
101 if (iint->readcount > 0)
102 ima_add_violation(inode, filename, "invalid_pcr",
103 "ToMToU");
104 break;
105 case OPEN_WRITERS:
106 if (iint->writecount > 0)
107 ima_add_violation(inode, filename, "invalid_pcr",
108 "open_writers");
109 break;
110 }
111}
112
113static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
114 const unsigned char *filename)
115{
116 int rc = 0;
117
118 if (IS_ERR(file)) {
119 pr_info("%s dentry_open failed\n", filename);
120 return rc;
121 }
122 iint->readcount++;
123
124 rc = ima_collect_measurement(iint, file);
125 if (!rc)
126 ima_store_measurement(iint, file, filename);
127 return rc;
128}
129
130/**
131 * ima_path_check - based on policy, collect/store measurement.
132 * @path: contains a pointer to the path to be measured
133 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
134 *
135 * Measure the file being open for readonly, based on the
136 * ima_must_measure() policy decision.
137 *
138 * Keep read/write counters for all files, but only
139 * invalidate the PCR for measured files:
140 * - Opening a file for write when already open for read,
141 * results in a time of measure, time of use (ToMToU) error.
142 * - Opening a file for read when already open for write,
143 * could result in a file measurement error.
144 *
145 * Return 0 on success, an error code on failure.
146 * (Based on the results of appraise_measurement().)
147 */
148int ima_path_check(struct path *path, int mask)
149{
150 struct inode *inode = path->dentry->d_inode;
151 struct ima_iint_cache *iint;
152 struct file *file = NULL;
153 int rc;
154
155 if (!ima_initialized || !S_ISREG(inode->i_mode))
156 return 0;
157 iint = ima_iint_find_insert_get(inode);
158 if (!iint)
159 return 0;
160
161 mutex_lock(&iint->mutex);
162 if ((mask & MAY_WRITE) || (mask == 0))
163 iint->writecount++;
164 else if (mask & (MAY_READ | MAY_EXEC))
165 iint->readcount++;
166
167 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
168 if (rc < 0)
169 goto out;
170
171 if ((mask & MAY_WRITE) || (mask == 0))
172 ima_read_write_check(TOMTOU, iint, inode,
173 path->dentry->d_name.name);
174
175 if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
176 goto out;
177
178 ima_read_write_check(OPEN_WRITERS, iint, inode,
179 path->dentry->d_name.name);
180 if (!(iint->flags & IMA_MEASURED)) {
181 struct dentry *dentry = dget(path->dentry);
182 struct vfsmount *mnt = mntget(path->mnt);
183
184 file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
185 rc = get_path_measurement(iint, file, dentry->d_name.name);
186 }
187out:
188 mutex_unlock(&iint->mutex);
189 if (file)
190 fput(file);
191 kref_put(&iint->refcount, iint_free);
192 return 0;
193}
194
195static int process_measurement(struct file *file, const unsigned char *filename,
196 int mask, int function)
197{
198 struct inode *inode = file->f_dentry->d_inode;
199 struct ima_iint_cache *iint;
200 int rc;
201
202 if (!ima_initialized || !S_ISREG(inode->i_mode))
203 return 0;
204 iint = ima_iint_find_insert_get(inode);
205 if (!iint)
206 return -ENOMEM;
207
208 mutex_lock(&iint->mutex);
209 rc = ima_must_measure(iint, inode, mask, function);
210 if (rc != 0)
211 goto out;
212
213 rc = ima_collect_measurement(iint, file);
214 if (!rc)
215 ima_store_measurement(iint, file, filename);
216out:
217 mutex_unlock(&iint->mutex);
218 kref_put(&iint->refcount, iint_free);
219 return rc;
220}
221
222/**
223 * ima_file_mmap - based on policy, collect/store measurement.
224 * @file: pointer to the file to be measured (May be NULL)
225 * @prot: contains the protection that will be applied by the kernel.
226 *
227 * Measure files being mmapped executable based on the ima_must_measure()
228 * policy decision.
229 *
230 * Return 0 on success, an error code on failure.
231 * (Based on the results of appraise_measurement().)
232 */
233int ima_file_mmap(struct file *file, unsigned long prot)
234{
235 int rc;
236
237 if (!file)
238 return 0;
239 if (prot & PROT_EXEC)
240 rc = process_measurement(file, file->f_dentry->d_name.name,
241 MAY_EXEC, FILE_MMAP);
242 return 0;
243}
244
245/**
246 * ima_bprm_check - based on policy, collect/store measurement.
247 * @bprm: contains the linux_binprm structure
248 *
249 * The OS protects against an executable file, already open for write,
250 * from being executed in deny_write_access() and an executable file,
251 * already open for execute, from being modified in get_write_access().
252 * So we can be certain that what we verify and measure here is actually
253 * what is being executed.
254 *
255 * Return 0 on success, an error code on failure.
256 * (Based on the results of appraise_measurement().)
257 */
258int ima_bprm_check(struct linux_binprm *bprm)
259{
260 int rc;
261
262 rc = process_measurement(bprm->file, bprm->filename,
263 MAY_EXEC, BPRM_CHECK);
264 return 0;
265}
266
267static int __init init_ima(void)
268{
269 int error;
270
271 ima_iintcache_init();
272 error = ima_init();
273 ima_initialized = 1;
274 return error;
275}
276
277late_initcall(init_ima); /* Start IMA after the TPM is available */
278
279MODULE_DESCRIPTION("Integrity Measurement Architecture");
280MODULE_LICENSE("GPL");
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
new file mode 100644
index 000000000000..7c3d1ffb1472
--- /dev/null
+++ b/security/integrity/ima/ima_policy.c
@@ -0,0 +1,126 @@
1/*
2 * Copyright (C) 2008 IBM Corporation
3 * Author: Mimi Zohar <zohar@us.ibm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
8 *
9 * ima_policy.c
10 * - initialize default measure policy rules
11 *
12 */
13#include <linux/module.h>
14#include <linux/list.h>
15#include <linux/audit.h>
16#include <linux/security.h>
17#include <linux/magic.h>
18
19#include "ima.h"
20
21/* flags definitions */
22#define IMA_FUNC 0x0001
23#define IMA_MASK 0x0002
24#define IMA_FSMAGIC 0x0004
25#define IMA_UID 0x0008
26
27enum ima_action { DONT_MEASURE, MEASURE };
28
29struct ima_measure_rule_entry {
30 struct list_head list;
31 enum ima_action action;
32 unsigned int flags;
33 enum ima_hooks func;
34 int mask;
35 unsigned long fsmagic;
36 uid_t uid;
37};
38
39static struct ima_measure_rule_entry default_rules[] = {
40 {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
41 .flags = IMA_FSMAGIC},
42 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
43 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
44 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
45 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
46 .flags = IMA_FSMAGIC},
47 {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
48 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
49 .flags = IMA_FUNC | IMA_MASK},
50 {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
51 .flags = IMA_FUNC | IMA_MASK},
52 {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
53 .flags = IMA_FUNC | IMA_MASK | IMA_UID}
54};
55
56static LIST_HEAD(measure_default_rules);
57static struct list_head *ima_measure;
58
59/**
60 * ima_match_rules - determine whether an inode matches the measure rule.
61 * @rule: a pointer to a rule
62 * @inode: a pointer to an inode
63 * @func: LIM hook identifier
64 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
65 *
66 * Returns true on rule match, false on failure.
67 */
68static bool ima_match_rules(struct ima_measure_rule_entry *rule,
69 struct inode *inode, enum ima_hooks func, int mask)
70{
71 struct task_struct *tsk = current;
72
73 if ((rule->flags & IMA_FUNC) && rule->func != func)
74 return false;
75 if ((rule->flags & IMA_MASK) && rule->mask != mask)
76 return false;
77 if ((rule->flags & IMA_FSMAGIC)
78 && rule->fsmagic != inode->i_sb->s_magic)
79 return false;
80 if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
81 return false;
82 return true;
83}
84
85/**
86 * ima_match_policy - decision based on LSM and other conditions
87 * @inode: pointer to an inode for which the policy decision is being made
88 * @func: IMA hook identifier
89 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
90 *
91 * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
92 * conditions.
93 *
94 * (There is no need for locking when walking the policy list,
95 * as elements in the list are never deleted, nor does the list
96 * change.)
97 */
98int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
99{
100 struct ima_measure_rule_entry *entry;
101
102 list_for_each_entry(entry, ima_measure, list) {
103 bool rc;
104
105 rc = ima_match_rules(entry, inode, func, mask);
106 if (rc)
107 return entry->action;
108 }
109 return 0;
110}
111
112/**
113 * ima_init_policy - initialize the default measure rules.
114 *
115 * (Could use the default_rules directly, but in policy patch
116 * ima_measure points to either the measure_default_rules or the
117 * the new measure_policy_rules.)
118 */
119void ima_init_policy(void)
120{
121 int i;
122
123 for (i = 0; i < ARRAY_SIZE(default_rules); i++)
124 list_add_tail(&default_rules[i].list, &measure_default_rules);
125 ima_measure = &measure_default_rules;
126}
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
new file mode 100644
index 000000000000..7ec94314ac0c
--- /dev/null
+++ b/security/integrity/ima/ima_queue.c
@@ -0,0 +1,140 @@
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
25LIST_HEAD(ima_measurements); /* list of all measurements */
26
27/* key: inode (before secure-hashing a file) */
28struct 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 */
38static DEFINE_MUTEX(ima_extend_list_mutex);
39
40/* lookup up the digest value in the hash table, and return the entry */
41static 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 */
66static 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
87static 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 */
103int 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 }
135out:
136 mutex_unlock(&ima_extend_list_mutex);
137 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name,
138 op, audit_cause, result, audit_info);
139 return result;
140}