aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-04-05 19:41:22 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-05 19:41:22 -0400
commit9efe21cb82b5dbe3b0b2ae4de4eccc64ecb94e95 (patch)
tree7ff8833745d2f268f897f6fa4a27263b4a572245 /security/integrity/ima
parentde18836e447c2dc30120c0919b8db8ddc0401cc4 (diff)
parent0221c81b1b8eb0cbb6b30a0ced52ead32d2b4e4c (diff)
Merge branch 'linus' into irq/threaded
Conflicts: include/linux/irq.h kernel/irq/handle.c
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/Kconfig55
-rw-r--r--security/integrity/ima/Makefile9
-rw-r--r--security/integrity/ima/ima.h166
-rw-r--r--security/integrity/ima/ima_api.c190
-rw-r--r--security/integrity/ima/ima_audit.c81
-rw-r--r--security/integrity/ima/ima_crypto.c140
-rw-r--r--security/integrity/ima/ima_fs.c376
-rw-r--r--security/integrity/ima/ima_iint.c204
-rw-r--r--security/integrity/ima/ima_init.c96
-rw-r--r--security/integrity/ima/ima_main.c327
-rw-r--r--security/integrity/ima/ima_policy.c414
-rw-r--r--security/integrity/ima/ima_queue.c140
12 files changed, 2198 insertions, 0 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
new file mode 100644
index 000000000000..53d9764e8f09
--- /dev/null
+++ b/security/integrity/ima/Kconfig
@@ -0,0 +1,55 @@
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
50config IMA_LSM_RULES
51 bool
52 depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK)
53 default y
54 help
55 Disabling this option will disregard LSM based policy rules.
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
new file mode 100644
index 000000000000..787c4cb916cd
--- /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_fs.o 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..165eb5397ea5
--- /dev/null
+++ b/security/integrity/ima/ima.h
@@ -0,0 +1,166 @@
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 const 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);
70void ima_cleanup(void);
71int ima_fs_init(void);
72void ima_fs_cleanup(void);
73int ima_add_template_entry(struct ima_template_entry *entry, int violation,
74 const char *op, struct inode *inode);
75int ima_calc_hash(struct file *file, char *digest);
76int ima_calc_template_hash(int template_len, void *template, char *digest);
77int ima_calc_boot_aggregate(char *digest);
78void ima_add_violation(struct inode *inode, const unsigned char *filename,
79 const char *op, const char *cause);
80
81/*
82 * used to protect h_table and sha_table
83 */
84extern spinlock_t ima_queue_lock;
85
86struct ima_h_table {
87 atomic_long_t len; /* number of stored measurements in the list */
88 atomic_long_t violations;
89 struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE];
90};
91extern struct ima_h_table ima_htable;
92
93static inline unsigned long ima_hash_key(u8 *digest)
94{
95 return hash_long(*digest, IMA_HASH_BITS);
96}
97
98/* iint cache flags */
99#define IMA_MEASURED 1
100#define IMA_IINT_DUMP_STACK 512
101
102/* integrity data associated with an inode */
103struct ima_iint_cache {
104 u64 version; /* track inode changes */
105 unsigned long flags;
106 u8 digest[IMA_DIGEST_SIZE];
107 struct mutex mutex; /* protects: version, flags, digest */
108 long readcount; /* measured files readcount */
109 long writecount; /* measured files writecount */
110 long opencount; /* opens reference count */
111 struct kref refcount; /* ima_iint_cache reference count */
112 struct rcu_head rcu;
113};
114
115/* LIM API function definitions */
116int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
117 int mask, int function);
118int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
119void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
120 const unsigned char *filename);
121int ima_store_template(struct ima_template_entry *entry, int violation,
122 struct inode *inode);
123void ima_template_show(struct seq_file *m, void *e,
124 enum ima_show_type show);
125
126/* radix tree calls to lookup, insert, delete
127 * integrity data associated with an inode.
128 */
129struct ima_iint_cache *ima_iint_insert(struct inode *inode);
130struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
131struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode);
132void ima_iint_delete(struct inode *inode);
133void iint_free(struct kref *kref);
134void iint_rcu_free(struct rcu_head *rcu);
135
136/* IMA policy related functions */
137enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK };
138
139int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
140void ima_init_policy(void);
141void ima_update_policy(void);
142int ima_parse_add_rule(char *);
143void ima_delete_rules(void);
144
145/* LSM based policy rules require audit */
146#ifdef CONFIG_IMA_LSM_RULES
147
148#define security_filter_rule_init security_audit_rule_init
149#define security_filter_rule_match security_audit_rule_match
150
151#else
152
153static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
154 void **lsmrule)
155{
156 return -EINVAL;
157}
158
159static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
160 void *lsmrule,
161 struct audit_context *actx)
162{
163 return -EINVAL;
164}
165#endif /* CONFIG_IMA_LSM_RULES */
166#endif
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
new file mode 100644
index 000000000000..3cd58b60afd2
--- /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 const 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..1e082bb987be
--- /dev/null
+++ b/security/integrity/ima/ima_audit.c
@@ -0,0 +1,81 @@
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, result = 0;
26 char *op = "ima_audit";
27 char *cause;
28
29 rc = strict_strtoul(str, 0, &audit);
30 if (rc || audit > 1)
31 result = 1;
32 else
33 ima_audit = audit;
34 cause = ima_audit ? "enabled" : "not_enabled";
35 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
36 op, cause, result, 0);
37 return 1;
38}
39__setup("ima_audit=", ima_audit_setup);
40#endif
41
42void integrity_audit_msg(int audit_msgno, struct inode *inode,
43 const unsigned char *fname, const char *op,
44 const char *cause, int result, int audit_info)
45{
46 struct audit_buffer *ab;
47
48 if (!ima_audit && audit_info == 1) /* Skip informational messages */
49 return;
50
51 ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
52 audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u",
53 current->pid, current->cred->uid,
54 audit_get_loginuid(current),
55 audit_get_sessionid(current));
56 audit_log_task_context(ab);
57 switch (audit_msgno) {
58 case AUDIT_INTEGRITY_DATA:
59 case AUDIT_INTEGRITY_METADATA:
60 case AUDIT_INTEGRITY_PCR:
61 case AUDIT_INTEGRITY_STATUS:
62 audit_log_format(ab, " op=%s cause=%s", op, cause);
63 break;
64 case AUDIT_INTEGRITY_HASH:
65 audit_log_format(ab, " op=%s hash=%s", op, cause);
66 break;
67 default:
68 audit_log_format(ab, " op=%s", op);
69 }
70 audit_log_format(ab, " comm=");
71 audit_log_untrustedstring(ab, current->comm);
72 if (fname) {
73 audit_log_format(ab, " name=");
74 audit_log_untrustedstring(ab, fname);
75 }
76 if (inode)
77 audit_log_format(ab, " dev=%s ino=%lu",
78 inode->i_sb->s_id, inode->i_ino);
79 audit_log_format(ab, " res=%d", !result ? 0 : 1);
80 audit_log_end(ab);
81}
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
new file mode 100644
index 000000000000..50d572b74caf
--- /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_init_one(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_init_one(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_fs.c b/security/integrity/ima/ima_fs.c
new file mode 100644
index 000000000000..ffbe259700b1
--- /dev/null
+++ b/security/integrity/ima/ima_fs.c
@@ -0,0 +1,376 @@
1/*
2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
3 *
4 * Authors:
5 * Kylene Hall <kjhall@us.ibm.com>
6 * Reiner Sailer <sailer@us.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_fs.c
15 * implemenents security file system for reporting
16 * current measurement list and IMA statistics
17 */
18#include <linux/module.h>
19#include <linux/seq_file.h>
20#include <linux/rculist.h>
21#include <linux/rcupdate.h>
22#include <linux/parser.h>
23
24#include "ima.h"
25
26static int valid_policy = 1;
27#define TMPBUFLEN 12
28static ssize_t ima_show_htable_value(char __user *buf, size_t count,
29 loff_t *ppos, atomic_long_t *val)
30{
31 char tmpbuf[TMPBUFLEN];
32 ssize_t len;
33
34 len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val));
35 return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
36}
37
38static ssize_t ima_show_htable_violations(struct file *filp,
39 char __user *buf,
40 size_t count, loff_t *ppos)
41{
42 return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
43}
44
45static struct file_operations ima_htable_violations_ops = {
46 .read = ima_show_htable_violations
47};
48
49static ssize_t ima_show_measurements_count(struct file *filp,
50 char __user *buf,
51 size_t count, loff_t *ppos)
52{
53 return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
54
55}
56
57static struct file_operations ima_measurements_count_ops = {
58 .read = ima_show_measurements_count
59};
60
61/* returns pointer to hlist_node */
62static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
63{
64 loff_t l = *pos;
65 struct ima_queue_entry *qe;
66
67 /* we need a lock since pos could point beyond last element */
68 rcu_read_lock();
69 list_for_each_entry_rcu(qe, &ima_measurements, later) {
70 if (!l--) {
71 rcu_read_unlock();
72 return qe;
73 }
74 }
75 rcu_read_unlock();
76 return NULL;
77}
78
79static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
80{
81 struct ima_queue_entry *qe = v;
82
83 /* lock protects when reading beyond last element
84 * against concurrent list-extension
85 */
86 rcu_read_lock();
87 qe = list_entry(rcu_dereference(qe->later.next),
88 struct ima_queue_entry, later);
89 rcu_read_unlock();
90 (*pos)++;
91
92 return (&qe->later == &ima_measurements) ? NULL : qe;
93}
94
95static void ima_measurements_stop(struct seq_file *m, void *v)
96{
97}
98
99static void ima_putc(struct seq_file *m, void *data, int datalen)
100{
101 while (datalen--)
102 seq_putc(m, *(char *)data++);
103}
104
105/* print format:
106 * 32bit-le=pcr#
107 * char[20]=template digest
108 * 32bit-le=template name size
109 * char[n]=template name
110 * eventdata[n]=template specific data
111 */
112static int ima_measurements_show(struct seq_file *m, void *v)
113{
114 /* the list never shrinks, so we don't need a lock here */
115 struct ima_queue_entry *qe = v;
116 struct ima_template_entry *e;
117 int namelen;
118 u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
119
120 /* get entry */
121 e = qe->entry;
122 if (e == NULL)
123 return -1;
124
125 /*
126 * 1st: PCRIndex
127 * PCR used is always the same (config option) in
128 * little-endian format
129 */
130 ima_putc(m, &pcr, sizeof pcr);
131
132 /* 2nd: template digest */
133 ima_putc(m, e->digest, IMA_DIGEST_SIZE);
134
135 /* 3rd: template name size */
136 namelen = strlen(e->template_name);
137 ima_putc(m, &namelen, sizeof namelen);
138
139 /* 4th: template name */
140 ima_putc(m, (void *)e->template_name, namelen);
141
142 /* 5th: template specific data */
143 ima_template_show(m, (struct ima_template_data *)&e->template,
144 IMA_SHOW_BINARY);
145 return 0;
146}
147
148static struct seq_operations ima_measurments_seqops = {
149 .start = ima_measurements_start,
150 .next = ima_measurements_next,
151 .stop = ima_measurements_stop,
152 .show = ima_measurements_show
153};
154
155static int ima_measurements_open(struct inode *inode, struct file *file)
156{
157 return seq_open(file, &ima_measurments_seqops);
158}
159
160static struct file_operations ima_measurements_ops = {
161 .open = ima_measurements_open,
162 .read = seq_read,
163 .llseek = seq_lseek,
164 .release = seq_release,
165};
166
167static void ima_print_digest(struct seq_file *m, u8 *digest)
168{
169 int i;
170
171 for (i = 0; i < IMA_DIGEST_SIZE; i++)
172 seq_printf(m, "%02x", *(digest + i));
173}
174
175void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show)
176{
177 struct ima_template_data *entry = e;
178 int namelen;
179
180 switch (show) {
181 case IMA_SHOW_ASCII:
182 ima_print_digest(m, entry->digest);
183 seq_printf(m, " %s\n", entry->file_name);
184 break;
185 case IMA_SHOW_BINARY:
186 ima_putc(m, entry->digest, IMA_DIGEST_SIZE);
187
188 namelen = strlen(entry->file_name);
189 ima_putc(m, &namelen, sizeof namelen);
190 ima_putc(m, entry->file_name, namelen);
191 default:
192 break;
193 }
194}
195
196/* print in ascii */
197static int ima_ascii_measurements_show(struct seq_file *m, void *v)
198{
199 /* the list never shrinks, so we don't need a lock here */
200 struct ima_queue_entry *qe = v;
201 struct ima_template_entry *e;
202
203 /* get entry */
204 e = qe->entry;
205 if (e == NULL)
206 return -1;
207
208 /* 1st: PCR used (config option) */
209 seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
210
211 /* 2nd: SHA1 template hash */
212 ima_print_digest(m, e->digest);
213
214 /* 3th: template name */
215 seq_printf(m, " %s ", e->template_name);
216
217 /* 4th: template specific data */
218 ima_template_show(m, (struct ima_template_data *)&e->template,
219 IMA_SHOW_ASCII);
220 return 0;
221}
222
223static struct seq_operations ima_ascii_measurements_seqops = {
224 .start = ima_measurements_start,
225 .next = ima_measurements_next,
226 .stop = ima_measurements_stop,
227 .show = ima_ascii_measurements_show
228};
229
230static int ima_ascii_measurements_open(struct inode *inode, struct file *file)
231{
232 return seq_open(file, &ima_ascii_measurements_seqops);
233}
234
235static struct file_operations ima_ascii_measurements_ops = {
236 .open = ima_ascii_measurements_open,
237 .read = seq_read,
238 .llseek = seq_lseek,
239 .release = seq_release,
240};
241
242static ssize_t ima_write_policy(struct file *file, const char __user *buf,
243 size_t datalen, loff_t *ppos)
244{
245 char *data;
246 int rc;
247
248 if (datalen >= PAGE_SIZE)
249 return -ENOMEM;
250 if (*ppos != 0) {
251 /* No partial writes. */
252 return -EINVAL;
253 }
254 data = kmalloc(datalen + 1, GFP_KERNEL);
255 if (!data)
256 return -ENOMEM;
257
258 if (copy_from_user(data, buf, datalen)) {
259 kfree(data);
260 return -EFAULT;
261 }
262 *(data + datalen) = '\0';
263 rc = ima_parse_add_rule(data);
264 if (rc < 0) {
265 datalen = -EINVAL;
266 valid_policy = 0;
267 }
268
269 kfree(data);
270 return datalen;
271}
272
273static struct dentry *ima_dir;
274static struct dentry *binary_runtime_measurements;
275static struct dentry *ascii_runtime_measurements;
276static struct dentry *runtime_measurements_count;
277static struct dentry *violations;
278static struct dentry *ima_policy;
279
280static atomic_t policy_opencount = ATOMIC_INIT(1);
281/*
282 * ima_open_policy: sequentialize access to the policy file
283 */
284int ima_open_policy(struct inode * inode, struct file * filp)
285{
286 if (atomic_dec_and_test(&policy_opencount))
287 return 0;
288 return -EBUSY;
289}
290
291/*
292 * ima_release_policy - start using the new measure policy rules.
293 *
294 * Initially, ima_measure points to the default policy rules, now
295 * point to the new policy rules, and remove the securityfs policy file,
296 * assuming a valid policy.
297 */
298static int ima_release_policy(struct inode *inode, struct file *file)
299{
300 if (!valid_policy) {
301 ima_delete_rules();
302 valid_policy = 1;
303 atomic_set(&policy_opencount, 1);
304 return 0;
305 }
306 ima_update_policy();
307 securityfs_remove(ima_policy);
308 ima_policy = NULL;
309 return 0;
310}
311
312static struct file_operations ima_measure_policy_ops = {
313 .open = ima_open_policy,
314 .write = ima_write_policy,
315 .release = ima_release_policy
316};
317
318int ima_fs_init(void)
319{
320 ima_dir = securityfs_create_dir("ima", NULL);
321 if (IS_ERR(ima_dir))
322 return -1;
323
324 binary_runtime_measurements =
325 securityfs_create_file("binary_runtime_measurements",
326 S_IRUSR | S_IRGRP, ima_dir, NULL,
327 &ima_measurements_ops);
328 if (IS_ERR(binary_runtime_measurements))
329 goto out;
330
331 ascii_runtime_measurements =
332 securityfs_create_file("ascii_runtime_measurements",
333 S_IRUSR | S_IRGRP, ima_dir, NULL,
334 &ima_ascii_measurements_ops);
335 if (IS_ERR(ascii_runtime_measurements))
336 goto out;
337
338 runtime_measurements_count =
339 securityfs_create_file("runtime_measurements_count",
340 S_IRUSR | S_IRGRP, ima_dir, NULL,
341 &ima_measurements_count_ops);
342 if (IS_ERR(runtime_measurements_count))
343 goto out;
344
345 violations =
346 securityfs_create_file("violations", S_IRUSR | S_IRGRP,
347 ima_dir, NULL, &ima_htable_violations_ops);
348 if (IS_ERR(violations))
349 goto out;
350
351 ima_policy = securityfs_create_file("policy",
352 S_IRUSR | S_IRGRP | S_IWUSR,
353 ima_dir, NULL,
354 &ima_measure_policy_ops);
355 if (IS_ERR(ima_policy))
356 goto out;
357
358 return 0;
359out:
360 securityfs_remove(runtime_measurements_count);
361 securityfs_remove(ascii_runtime_measurements);
362 securityfs_remove(binary_runtime_measurements);
363 securityfs_remove(ima_dir);
364 securityfs_remove(ima_policy);
365 return -1;
366}
367
368void __exit ima_fs_cleanup(void)
369{
370 securityfs_remove(violations);
371 securityfs_remove(runtime_measurements_count);
372 securityfs_remove(ascii_runtime_measurements);
373 securityfs_remove(binary_runtime_measurements);
374 securityfs_remove(ima_dir);
375 securityfs_remove(ima_policy);
376}
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
new file mode 100644
index 000000000000..ec79f1ee992c
--- /dev/null
+++ b/security/integrity/ima/ima_iint.c
@@ -0,0 +1,204 @@
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 spin_lock(&ima_iint_lock);
77 iint = radix_tree_lookup(&ima_iint_store,
78 (unsigned long)inode);
79 spin_unlock(&ima_iint_lock);
80 } else
81 iint = NULL;
82 }
83 radix_tree_preload_end();
84 return iint;
85}
86
87/**
88 * ima_inode_alloc - allocate an iint associated with an inode
89 * @inode: pointer to the inode
90 *
91 * Return 0 on success, 1 on failure.
92 */
93int ima_inode_alloc(struct inode *inode)
94{
95 struct ima_iint_cache *iint;
96
97 if (!ima_initialized)
98 return 0;
99
100 iint = ima_iint_insert(inode);
101 if (!iint)
102 return 1;
103 return 0;
104}
105
106/* ima_iint_find_insert_get - get the iint associated with an inode
107 *
108 * Most insertions are done at inode_alloc, except those allocated
109 * before late_initcall. When the iint does not exist, allocate it,
110 * initialize and insert it, and increment the iint refcount.
111 *
112 * (Can't initialize at security_initcall before any inodes are
113 * allocated, got to wait at least until proc_init.)
114 *
115 * Return the iint.
116 */
117struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode)
118{
119 struct ima_iint_cache *iint = NULL;
120
121 iint = ima_iint_find_get(inode);
122 if (iint)
123 return iint;
124
125 iint = ima_iint_insert(inode);
126 if (iint)
127 kref_get(&iint->refcount);
128
129 return iint;
130}
131EXPORT_SYMBOL_GPL(ima_iint_find_insert_get);
132
133/* iint_free - called when the iint refcount goes to zero */
134void iint_free(struct kref *kref)
135{
136 struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache,
137 refcount);
138 iint->version = 0;
139 iint->flags = 0UL;
140 if (iint->readcount != 0) {
141 printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__,
142 iint->readcount);
143 iint->readcount = 0;
144 }
145 if (iint->writecount != 0) {
146 printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__,
147 iint->writecount);
148 iint->writecount = 0;
149 }
150 if (iint->opencount != 0) {
151 printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__,
152 iint->opencount);
153 iint->opencount = 0;
154 }
155 kref_set(&iint->refcount, 1);
156 kmem_cache_free(iint_cache, iint);
157}
158
159void iint_rcu_free(struct rcu_head *rcu_head)
160{
161 struct ima_iint_cache *iint = container_of(rcu_head,
162 struct ima_iint_cache, rcu);
163 kref_put(&iint->refcount, iint_free);
164}
165
166/**
167 * ima_iint_delete - called on integrity_inode_free
168 * @inode: pointer to the inode
169 *
170 * Free the integrity information(iint) associated with an inode.
171 */
172void ima_iint_delete(struct inode *inode)
173{
174 struct ima_iint_cache *iint;
175
176 if (!ima_initialized)
177 return;
178 spin_lock(&ima_iint_lock);
179 iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
180 spin_unlock(&ima_iint_lock);
181 if (iint)
182 call_rcu(&iint->rcu, iint_rcu_free);
183}
184
185static void init_once(void *foo)
186{
187 struct ima_iint_cache *iint = foo;
188
189 memset(iint, 0, sizeof *iint);
190 iint->version = 0;
191 iint->flags = 0UL;
192 mutex_init(&iint->mutex);
193 iint->readcount = 0;
194 iint->writecount = 0;
195 iint->opencount = 0;
196 kref_set(&iint->refcount, 1);
197}
198
199void ima_iintcache_init(void)
200{
201 iint_cache =
202 kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
203 SLAB_PANIC, init_once);
204}
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
new file mode 100644
index 000000000000..0b0bb8c978cc
--- /dev/null
+++ b/security/integrity/ima/ima_init.c
@@ -0,0 +1,96 @@
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 const 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
90 return ima_fs_init();
91}
92
93void __exit ima_cleanup(void)
94{
95 ima_fs_cleanup();
96}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
new file mode 100644
index 000000000000..f4e7266f5aee
--- /dev/null
+++ b/security/integrity/ima/ima_main.c
@@ -0,0 +1,327 @@
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 (iint->opencount <= 0) {
70 printk(KERN_INFO
71 "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n",
72 __FUNCTION__, file->f_dentry->d_name.name,
73 iint->readcount, iint->writecount,
74 iint->opencount, atomic_long_read(&file->f_count));
75 if (!(iint->flags & IMA_IINT_DUMP_STACK)) {
76 dump_stack();
77 iint->flags |= IMA_IINT_DUMP_STACK;
78 }
79 }
80 iint->opencount--;
81
82 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
83 iint->readcount--;
84
85 if (file->f_mode & FMODE_WRITE) {
86 iint->writecount--;
87 if (iint->writecount == 0) {
88 if (iint->version != inode->i_version)
89 iint->flags &= ~IMA_MEASURED;
90 }
91 }
92 mutex_unlock(&iint->mutex);
93 kref_put(&iint->refcount, iint_free);
94}
95
96/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
97 *
98 * When opening a file for read, if the file is already open for write,
99 * the file could change, resulting in a file measurement error.
100 *
101 * Opening a file for write, if the file is already open for read, results
102 * in a time of measure, time of use (ToMToU) error.
103 *
104 * In either case invalidate the PCR.
105 */
106enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
107static void ima_read_write_check(enum iint_pcr_error error,
108 struct ima_iint_cache *iint,
109 struct inode *inode,
110 const unsigned char *filename)
111{
112 switch (error) {
113 case TOMTOU:
114 if (iint->readcount > 0)
115 ima_add_violation(inode, filename, "invalid_pcr",
116 "ToMToU");
117 break;
118 case OPEN_WRITERS:
119 if (iint->writecount > 0)
120 ima_add_violation(inode, filename, "invalid_pcr",
121 "open_writers");
122 break;
123 }
124}
125
126static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
127 const unsigned char *filename)
128{
129 int rc = 0;
130
131 if (IS_ERR(file)) {
132 pr_info("%s dentry_open failed\n", filename);
133 return rc;
134 }
135 iint->opencount++;
136 iint->readcount++;
137
138 rc = ima_collect_measurement(iint, file);
139 if (!rc)
140 ima_store_measurement(iint, file, filename);
141 return rc;
142}
143
144/**
145 * ima_path_check - based on policy, collect/store measurement.
146 * @path: contains a pointer to the path to be measured
147 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
148 *
149 * Measure the file being open for readonly, based on the
150 * ima_must_measure() policy decision.
151 *
152 * Keep read/write counters for all files, but only
153 * invalidate the PCR for measured files:
154 * - Opening a file for write when already open for read,
155 * results in a time of measure, time of use (ToMToU) error.
156 * - Opening a file for read when already open for write,
157 * could result in a file measurement error.
158 *
159 * Return 0 on success, an error code on failure.
160 * (Based on the results of appraise_measurement().)
161 */
162int ima_path_check(struct path *path, int mask)
163{
164 struct inode *inode = path->dentry->d_inode;
165 struct ima_iint_cache *iint;
166 struct file *file = NULL;
167 int rc;
168
169 if (!ima_initialized || !S_ISREG(inode->i_mode))
170 return 0;
171 iint = ima_iint_find_insert_get(inode);
172 if (!iint)
173 return 0;
174
175 mutex_lock(&iint->mutex);
176 iint->opencount++;
177 if ((mask & MAY_WRITE) || (mask == 0))
178 iint->writecount++;
179 else if (mask & (MAY_READ | MAY_EXEC))
180 iint->readcount++;
181
182 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
183 if (rc < 0)
184 goto out;
185
186 if ((mask & MAY_WRITE) || (mask == 0))
187 ima_read_write_check(TOMTOU, iint, inode,
188 path->dentry->d_name.name);
189
190 if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
191 goto out;
192
193 ima_read_write_check(OPEN_WRITERS, iint, inode,
194 path->dentry->d_name.name);
195 if (!(iint->flags & IMA_MEASURED)) {
196 struct dentry *dentry = dget(path->dentry);
197 struct vfsmount *mnt = mntget(path->mnt);
198
199 file = dentry_open(dentry, mnt, O_RDONLY, current->cred);
200 rc = get_path_measurement(iint, file, dentry->d_name.name);
201 }
202out:
203 mutex_unlock(&iint->mutex);
204 if (file)
205 fput(file);
206 kref_put(&iint->refcount, iint_free);
207 return 0;
208}
209
210static int process_measurement(struct file *file, const unsigned char *filename,
211 int mask, int function)
212{
213 struct inode *inode = file->f_dentry->d_inode;
214 struct ima_iint_cache *iint;
215 int rc;
216
217 if (!ima_initialized || !S_ISREG(inode->i_mode))
218 return 0;
219 iint = ima_iint_find_insert_get(inode);
220 if (!iint)
221 return -ENOMEM;
222
223 mutex_lock(&iint->mutex);
224 rc = ima_must_measure(iint, inode, mask, function);
225 if (rc != 0)
226 goto out;
227
228 rc = ima_collect_measurement(iint, file);
229 if (!rc)
230 ima_store_measurement(iint, file, filename);
231out:
232 mutex_unlock(&iint->mutex);
233 kref_put(&iint->refcount, iint_free);
234 return rc;
235}
236
237static void opencount_get(struct file *file)
238{
239 struct inode *inode = file->f_dentry->d_inode;
240 struct ima_iint_cache *iint;
241
242 if (!ima_initialized || !S_ISREG(inode->i_mode))
243 return;
244 iint = ima_iint_find_insert_get(inode);
245 if (!iint)
246 return;
247 mutex_lock(&iint->mutex);
248 iint->opencount++;
249 mutex_unlock(&iint->mutex);
250}
251
252/**
253 * ima_file_mmap - based on policy, collect/store measurement.
254 * @file: pointer to the file to be measured (May be NULL)
255 * @prot: contains the protection that will be applied by the kernel.
256 *
257 * Measure files being mmapped executable based on the ima_must_measure()
258 * policy decision.
259 *
260 * Return 0 on success, an error code on failure.
261 * (Based on the results of appraise_measurement().)
262 */
263int ima_file_mmap(struct file *file, unsigned long prot)
264{
265 int rc;
266
267 if (!file)
268 return 0;
269 if (prot & PROT_EXEC)
270 rc = process_measurement(file, file->f_dentry->d_name.name,
271 MAY_EXEC, FILE_MMAP);
272 return 0;
273}
274
275/*
276 * ima_shm_check - IPC shm and shmat create/fput a file
277 *
278 * Maintain the opencount for these files to prevent unnecessary
279 * imbalance messages.
280 */
281void ima_shm_check(struct file *file)
282{
283 opencount_get(file);
284 return;
285}
286
287/**
288 * ima_bprm_check - based on policy, collect/store measurement.
289 * @bprm: contains the linux_binprm structure
290 *
291 * The OS protects against an executable file, already open for write,
292 * from being executed in deny_write_access() and an executable file,
293 * already open for execute, from being modified in get_write_access().
294 * So we can be certain that what we verify and measure here is actually
295 * what is being executed.
296 *
297 * Return 0 on success, an error code on failure.
298 * (Based on the results of appraise_measurement().)
299 */
300int ima_bprm_check(struct linux_binprm *bprm)
301{
302 int rc;
303
304 rc = process_measurement(bprm->file, bprm->filename,
305 MAY_EXEC, BPRM_CHECK);
306 return 0;
307}
308
309static int __init init_ima(void)
310{
311 int error;
312
313 ima_iintcache_init();
314 error = ima_init();
315 ima_initialized = 1;
316 return error;
317}
318
319static void __exit cleanup_ima(void)
320{
321 ima_cleanup();
322}
323
324late_initcall(init_ima); /* Start IMA after the TPM is available */
325
326MODULE_DESCRIPTION("Integrity Measurement Architecture");
327MODULE_LICENSE("GPL");
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
new file mode 100644
index 000000000000..b5291ad5ef56
--- /dev/null
+++ b/security/integrity/ima/ima_policy.c
@@ -0,0 +1,414 @@
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/security.h>
16#include <linux/magic.h>
17#include <linux/parser.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 { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE };
28
29#define MAX_LSM_RULES 6
30enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
31 LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
32};
33
34struct ima_measure_rule_entry {
35 struct list_head list;
36 enum ima_action action;
37 unsigned int flags;
38 enum ima_hooks func;
39 int mask;
40 unsigned long fsmagic;
41 uid_t uid;
42 struct {
43 void *rule; /* LSM file metadata specific */
44 int type; /* audit type */
45 } lsm[MAX_LSM_RULES];
46};
47
48/* Without LSM specific knowledge, the default policy can only be
49 * written in terms of .action, .func, .mask, .fsmagic, and .uid
50 */
51static struct ima_measure_rule_entry default_rules[] = {
52 {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,
53 .flags = IMA_FSMAGIC},
54 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
55 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
56 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
57 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,
58 .flags = IMA_FSMAGIC},
59 {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC},
60 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
61 .flags = IMA_FUNC | IMA_MASK},
62 {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC,
63 .flags = IMA_FUNC | IMA_MASK},
64 {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0,
65 .flags = IMA_FUNC | IMA_MASK | IMA_UID}
66};
67
68static LIST_HEAD(measure_default_rules);
69static LIST_HEAD(measure_policy_rules);
70static struct list_head *ima_measure;
71
72static DEFINE_MUTEX(ima_measure_mutex);
73
74/**
75 * ima_match_rules - determine whether an inode matches the measure rule.
76 * @rule: a pointer to a rule
77 * @inode: a pointer to an inode
78 * @func: LIM hook identifier
79 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
80 *
81 * Returns true on rule match, false on failure.
82 */
83static bool ima_match_rules(struct ima_measure_rule_entry *rule,
84 struct inode *inode, enum ima_hooks func, int mask)
85{
86 struct task_struct *tsk = current;
87 int i;
88
89 if ((rule->flags & IMA_FUNC) && rule->func != func)
90 return false;
91 if ((rule->flags & IMA_MASK) && rule->mask != mask)
92 return false;
93 if ((rule->flags & IMA_FSMAGIC)
94 && rule->fsmagic != inode->i_sb->s_magic)
95 return false;
96 if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
97 return false;
98 for (i = 0; i < MAX_LSM_RULES; i++) {
99 int rc;
100 u32 osid, sid;
101
102 if (!rule->lsm[i].rule)
103 continue;
104
105 switch (i) {
106 case LSM_OBJ_USER:
107 case LSM_OBJ_ROLE:
108 case LSM_OBJ_TYPE:
109 security_inode_getsecid(inode, &osid);
110 rc = security_filter_rule_match(osid,
111 rule->lsm[i].type,
112 AUDIT_EQUAL,
113 rule->lsm[i].rule,
114 NULL);
115 break;
116 case LSM_SUBJ_USER:
117 case LSM_SUBJ_ROLE:
118 case LSM_SUBJ_TYPE:
119 security_task_getsecid(tsk, &sid);
120 rc = security_filter_rule_match(sid,
121 rule->lsm[i].type,
122 AUDIT_EQUAL,
123 rule->lsm[i].rule,
124 NULL);
125 default:
126 break;
127 }
128 if (!rc)
129 return false;
130 }
131 return true;
132}
133
134/**
135 * ima_match_policy - decision based on LSM and other conditions
136 * @inode: pointer to an inode for which the policy decision is being made
137 * @func: IMA hook identifier
138 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
139 *
140 * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
141 * conditions.
142 *
143 * (There is no need for locking when walking the policy list,
144 * as elements in the list are never deleted, nor does the list
145 * change.)
146 */
147int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask)
148{
149 struct ima_measure_rule_entry *entry;
150
151 list_for_each_entry(entry, ima_measure, list) {
152 bool rc;
153
154 rc = ima_match_rules(entry, inode, func, mask);
155 if (rc)
156 return entry->action;
157 }
158 return 0;
159}
160
161/**
162 * ima_init_policy - initialize the default measure rules.
163 *
164 * ima_measure points to either the measure_default_rules or the
165 * the new measure_policy_rules.
166 */
167void ima_init_policy(void)
168{
169 int i;
170
171 for (i = 0; i < ARRAY_SIZE(default_rules); i++)
172 list_add_tail(&default_rules[i].list, &measure_default_rules);
173 ima_measure = &measure_default_rules;
174}
175
176/**
177 * ima_update_policy - update default_rules with new measure rules
178 *
179 * Called on file .release to update the default rules with a complete new
180 * policy. Once updated, the policy is locked, no additional rules can be
181 * added to the policy.
182 */
183void ima_update_policy(void)
184{
185 const char *op = "policy_update";
186 const char *cause = "already exists";
187 int result = 1;
188 int audit_info = 0;
189
190 if (ima_measure == &measure_default_rules) {
191 ima_measure = &measure_policy_rules;
192 cause = "complete";
193 result = 0;
194 }
195 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
196 NULL, op, cause, result, audit_info);
197}
198
199enum {
200 Opt_err = -1,
201 Opt_measure = 1, Opt_dont_measure,
202 Opt_obj_user, Opt_obj_role, Opt_obj_type,
203 Opt_subj_user, Opt_subj_role, Opt_subj_type,
204 Opt_func, Opt_mask, Opt_fsmagic, Opt_uid
205};
206
207static match_table_t policy_tokens = {
208 {Opt_measure, "measure"},
209 {Opt_dont_measure, "dont_measure"},
210 {Opt_obj_user, "obj_user=%s"},
211 {Opt_obj_role, "obj_role=%s"},
212 {Opt_obj_type, "obj_type=%s"},
213 {Opt_subj_user, "subj_user=%s"},
214 {Opt_subj_role, "subj_role=%s"},
215 {Opt_subj_type, "subj_type=%s"},
216 {Opt_func, "func=%s"},
217 {Opt_mask, "mask=%s"},
218 {Opt_fsmagic, "fsmagic=%s"},
219 {Opt_uid, "uid=%s"},
220 {Opt_err, NULL}
221};
222
223static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
224 char *args, int lsm_rule, int audit_type)
225{
226 int result;
227
228 entry->lsm[lsm_rule].type = audit_type;
229 result = security_filter_rule_init(entry->lsm[lsm_rule].type,
230 AUDIT_EQUAL, args,
231 &entry->lsm[lsm_rule].rule);
232 return result;
233}
234
235static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
236{
237 struct audit_buffer *ab;
238 char *p;
239 int result = 0;
240
241 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
242
243 entry->action = -1;
244 while ((p = strsep(&rule, " \n")) != NULL) {
245 substring_t args[MAX_OPT_ARGS];
246 int token;
247 unsigned long lnum;
248
249 if (result < 0)
250 break;
251 if (!*p)
252 continue;
253 token = match_token(p, policy_tokens, args);
254 switch (token) {
255 case Opt_measure:
256 audit_log_format(ab, "%s ", "measure");
257 entry->action = MEASURE;
258 break;
259 case Opt_dont_measure:
260 audit_log_format(ab, "%s ", "dont_measure");
261 entry->action = DONT_MEASURE;
262 break;
263 case Opt_func:
264 audit_log_format(ab, "func=%s ", args[0].from);
265 if (strcmp(args[0].from, "PATH_CHECK") == 0)
266 entry->func = PATH_CHECK;
267 else if (strcmp(args[0].from, "FILE_MMAP") == 0)
268 entry->func = FILE_MMAP;
269 else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
270 entry->func = BPRM_CHECK;
271 else
272 result = -EINVAL;
273 if (!result)
274 entry->flags |= IMA_FUNC;
275 break;
276 case Opt_mask:
277 audit_log_format(ab, "mask=%s ", args[0].from);
278 if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
279 entry->mask = MAY_EXEC;
280 else if (strcmp(args[0].from, "MAY_WRITE") == 0)
281 entry->mask = MAY_WRITE;
282 else if (strcmp(args[0].from, "MAY_READ") == 0)
283 entry->mask = MAY_READ;
284 else if (strcmp(args[0].from, "MAY_APPEND") == 0)
285 entry->mask = MAY_APPEND;
286 else
287 result = -EINVAL;
288 if (!result)
289 entry->flags |= IMA_MASK;
290 break;
291 case Opt_fsmagic:
292 audit_log_format(ab, "fsmagic=%s ", args[0].from);
293 result = strict_strtoul(args[0].from, 16,
294 &entry->fsmagic);
295 if (!result)
296 entry->flags |= IMA_FSMAGIC;
297 break;
298 case Opt_uid:
299 audit_log_format(ab, "uid=%s ", args[0].from);
300 result = strict_strtoul(args[0].from, 10, &lnum);
301 if (!result) {
302 entry->uid = (uid_t) lnum;
303 if (entry->uid != lnum)
304 result = -EINVAL;
305 else
306 entry->flags |= IMA_UID;
307 }
308 break;
309 case Opt_obj_user:
310 audit_log_format(ab, "obj_user=%s ", args[0].from);
311 result = ima_lsm_rule_init(entry, args[0].from,
312 LSM_OBJ_USER,
313 AUDIT_OBJ_USER);
314 break;
315 case Opt_obj_role:
316 audit_log_format(ab, "obj_role=%s ", args[0].from);
317 result = ima_lsm_rule_init(entry, args[0].from,
318 LSM_OBJ_ROLE,
319 AUDIT_OBJ_ROLE);
320 break;
321 case Opt_obj_type:
322 audit_log_format(ab, "obj_type=%s ", args[0].from);
323 result = ima_lsm_rule_init(entry, args[0].from,
324 LSM_OBJ_TYPE,
325 AUDIT_OBJ_TYPE);
326 break;
327 case Opt_subj_user:
328 audit_log_format(ab, "subj_user=%s ", args[0].from);
329 result = ima_lsm_rule_init(entry, args[0].from,
330 LSM_SUBJ_USER,
331 AUDIT_SUBJ_USER);
332 break;
333 case Opt_subj_role:
334 audit_log_format(ab, "subj_role=%s ", args[0].from);
335 result = ima_lsm_rule_init(entry, args[0].from,
336 LSM_SUBJ_ROLE,
337 AUDIT_SUBJ_ROLE);
338 break;
339 case Opt_subj_type:
340 audit_log_format(ab, "subj_type=%s ", args[0].from);
341 result = ima_lsm_rule_init(entry, args[0].from,
342 LSM_SUBJ_TYPE,
343 AUDIT_SUBJ_TYPE);
344 break;
345 case Opt_err:
346 audit_log_format(ab, "UNKNOWN=%s ", p);
347 break;
348 }
349 }
350 if (entry->action == UNKNOWN)
351 result = -EINVAL;
352
353 audit_log_format(ab, "res=%d", !result ? 0 : 1);
354 audit_log_end(ab);
355 return result;
356}
357
358/**
359 * ima_parse_add_rule - add a rule to measure_policy_rules
360 * @rule - ima measurement policy rule
361 *
362 * Uses a mutex to protect the policy list from multiple concurrent writers.
363 * Returns 0 on success, an error code on failure.
364 */
365int ima_parse_add_rule(char *rule)
366{
367 const char *op = "update_policy";
368 struct ima_measure_rule_entry *entry;
369 int result = 0;
370 int audit_info = 0;
371
372 /* Prevent installed policy from changing */
373 if (ima_measure != &measure_default_rules) {
374 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
375 NULL, op, "already exists",
376 -EACCES, audit_info);
377 return -EACCES;
378 }
379
380 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
381 if (!entry) {
382 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
383 NULL, op, "-ENOMEM", -ENOMEM, audit_info);
384 return -ENOMEM;
385 }
386
387 INIT_LIST_HEAD(&entry->list);
388
389 result = ima_parse_rule(rule, entry);
390 if (!result) {
391 mutex_lock(&ima_measure_mutex);
392 list_add_tail(&entry->list, &measure_policy_rules);
393 mutex_unlock(&ima_measure_mutex);
394 } else {
395 kfree(entry);
396 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
397 NULL, op, "invalid policy", result,
398 audit_info);
399 }
400 return result;
401}
402
403/* ima_delete_rules called to cleanup invalid policy */
404void ima_delete_rules(void)
405{
406 struct ima_measure_rule_entry *entry, *tmp;
407
408 mutex_lock(&ima_measure_mutex);
409 list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) {
410 list_del(&entry->list);
411 kfree(entry);
412 }
413 mutex_unlock(&ima_measure_mutex);
414}
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}