aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima/ima_main.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /security/integrity/ima/ima_main.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r--security/integrity/ima/ima_main.c310
1 files changed, 140 insertions, 170 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b85e61bcf246..b2c89d9de2a4 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -13,14 +13,15 @@
13 * License. 13 * License.
14 * 14 *
15 * File: ima_main.c 15 * File: ima_main.c
16 * implements the IMA hooks: ima_bprm_check, ima_file_mmap, 16 * implements the IMA hooks: ima_bprm_check, ima_file_mmap,
17 * and ima_path_check. 17 * and ima_file_check.
18 */ 18 */
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/file.h> 20#include <linux/file.h>
21#include <linux/binfmts.h> 21#include <linux/binfmts.h>
22#include <linux/mount.h> 22#include <linux/mount.h>
23#include <linux/mman.h> 23#include <linux/mman.h>
24#include <linux/slab.h>
24 25
25#include "ima.h" 26#include "ima.h"
26 27
@@ -35,50 +36,53 @@ static int __init hash_setup(char *str)
35} 36}
36__setup("ima_hash=", hash_setup); 37__setup("ima_hash=", hash_setup);
37 38
38/** 39struct ima_imbalance {
39 * ima_file_free - called on __fput() 40 struct hlist_node node;
40 * @file: pointer to file structure being freed 41 unsigned long fsmagic;
42};
43
44/*
45 * ima_limit_imbalance - emit one imbalance message per filesystem type
41 * 46 *
42 * Flag files that changed, based on i_version; 47 * Maintain list of filesystem types that do not measure files properly.
43 * and decrement the iint readcount/writecount. 48 * Return false if unknown, true if known.
44 */ 49 */
45void ima_file_free(struct file *file) 50static bool ima_limit_imbalance(struct file *file)
46{ 51{
47 struct inode *inode = file->f_dentry->d_inode; 52 static DEFINE_SPINLOCK(ima_imbalance_lock);
48 struct ima_iint_cache *iint; 53 static HLIST_HEAD(ima_imbalance_list);
49 54
50 if (!ima_initialized || !S_ISREG(inode->i_mode)) 55 struct super_block *sb = file->f_dentry->d_sb;
51 return; 56 struct ima_imbalance *entry;
52 iint = ima_iint_find_get(inode); 57 struct hlist_node *node;
53 if (!iint) 58 bool found = false;
54 return; 59
55 60 rcu_read_lock();
56 mutex_lock(&iint->mutex); 61 hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) {
57 if (iint->opencount <= 0) { 62 if (entry->fsmagic == sb->s_magic) {
58 printk(KERN_INFO 63 found = true;
59 "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n", 64 break;
60 __FUNCTION__, file->f_dentry->d_name.name,
61 iint->readcount, iint->writecount,
62 iint->opencount, atomic_long_read(&file->f_count));
63 if (!(iint->flags & IMA_IINT_DUMP_STACK)) {
64 dump_stack();
65 iint->flags |= IMA_IINT_DUMP_STACK;
66 } 65 }
67 } 66 }
68 iint->opencount--; 67 rcu_read_unlock();
69 68 if (found)
70 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) 69 goto out;
71 iint->readcount--;
72 70
73 if (file->f_mode & FMODE_WRITE) { 71 entry = kmalloc(sizeof(*entry), GFP_NOFS);
74 iint->writecount--; 72 if (!entry)
75 if (iint->writecount == 0) { 73 goto out;
76 if (iint->version != inode->i_version) 74 entry->fsmagic = sb->s_magic;
77 iint->flags &= ~IMA_MEASURED; 75 spin_lock(&ima_imbalance_lock);
78 } 76 /*
79 } 77 * we could have raced and something else might have added this fs
80 mutex_unlock(&iint->mutex); 78 * to the list, but we don't really care
81 kref_put(&iint->refcount, iint_free); 79 */
80 hlist_add_head_rcu(&entry->node, &ima_imbalance_list);
81 spin_unlock(&ima_imbalance_lock);
82 printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n",
83 entry->fsmagic);
84out:
85 return found;
82} 86}
83 87
84/* ima_read_write_check - reflect possible reading/writing errors in the PCR. 88/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
@@ -111,196 +115,142 @@ static void ima_read_write_check(enum iint_pcr_error error,
111 } 115 }
112} 116}
113 117
114static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, 118/*
115 const unsigned char *filename) 119 * Update the counts given an fmode_t
120 */
121static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
116{ 122{
117 int rc = 0; 123 BUG_ON(!mutex_is_locked(&iint->mutex));
118
119 iint->opencount++;
120 iint->readcount++;
121
122 rc = ima_collect_measurement(iint, file);
123 if (!rc)
124 ima_store_measurement(iint, file, filename);
125 return rc;
126}
127 124
128static void ima_update_counts(struct ima_iint_cache *iint, int mask)
129{
130 iint->opencount++; 125 iint->opencount++;
131 if ((mask & MAY_WRITE) || (mask == 0)) 126 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
132 iint->writecount++;
133 else if (mask & (MAY_READ | MAY_EXEC))
134 iint->readcount++; 127 iint->readcount++;
128 if (mode & FMODE_WRITE)
129 iint->writecount++;
135} 130}
136 131
137/** 132/*
138 * ima_path_check - based on policy, collect/store measurement. 133 * ima_counts_get - increment file counts
139 * @path: contains a pointer to the path to be measured
140 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
141 *
142 * Measure the file being open for readonly, based on the
143 * ima_must_measure() policy decision.
144 * 134 *
145 * Keep read/write counters for all files, but only 135 * Maintain read/write counters for all files, but only
146 * invalidate the PCR for measured files: 136 * invalidate the PCR for measured files:
147 * - Opening a file for write when already open for read, 137 * - Opening a file for write when already open for read,
148 * results in a time of measure, time of use (ToMToU) error. 138 * results in a time of measure, time of use (ToMToU) error.
149 * - Opening a file for read when already open for write, 139 * - Opening a file for read when already open for write,
150 * could result in a file measurement error. 140 * could result in a file measurement error.
151 * 141 *
152 * Always return 0 and audit dentry_open failures.
153 * (Return code will be based upon measurement appraisal.)
154 */ 142 */
155int ima_path_check(struct path *path, int mask, int update_counts) 143void ima_counts_get(struct file *file)
156{ 144{
157 struct inode *inode = path->dentry->d_inode; 145 struct dentry *dentry = file->f_path.dentry;
146 struct inode *inode = dentry->d_inode;
147 fmode_t mode = file->f_mode;
158 struct ima_iint_cache *iint; 148 struct ima_iint_cache *iint;
159 struct file *file = NULL;
160 int rc; 149 int rc;
161 150
162 if (!ima_initialized || !S_ISREG(inode->i_mode)) 151 if (!ima_initialized || !S_ISREG(inode->i_mode))
163 return 0; 152 return;
164 iint = ima_iint_find_insert_get(inode); 153 iint = ima_iint_find_get(inode);
165 if (!iint) 154 if (!iint)
166 return 0; 155 return;
167
168 mutex_lock(&iint->mutex); 156 mutex_lock(&iint->mutex);
169 if (update_counts) 157 rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
170 ima_update_counts(iint, mask);
171
172 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
173 if (rc < 0) 158 if (rc < 0)
174 goto out; 159 goto out;
175 160
176 if ((mask & MAY_WRITE) || (mask == 0)) 161 if (mode & FMODE_WRITE) {
177 ima_read_write_check(TOMTOU, iint, inode, 162 ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name);
178 path->dentry->d_name.name);
179
180 if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
181 goto out; 163 goto out;
182
183 ima_read_write_check(OPEN_WRITERS, iint, inode,
184 path->dentry->d_name.name);
185 if (!(iint->flags & IMA_MEASURED)) {
186 struct dentry *dentry = dget(path->dentry);
187 struct vfsmount *mnt = mntget(path->mnt);
188
189 file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE,
190 current_cred());
191 if (IS_ERR(file)) {
192 int audit_info = 0;
193
194 integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
195 dentry->d_name.name,
196 "add_measurement",
197 "dentry_open failed",
198 1, audit_info);
199 file = NULL;
200 goto out;
201 }
202 rc = get_path_measurement(iint, file, dentry->d_name.name);
203 } 164 }
165 ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name);
204out: 166out:
167 ima_inc_counts(iint, file->f_mode);
205 mutex_unlock(&iint->mutex); 168 mutex_unlock(&iint->mutex);
206 if (file) 169
207 fput(file);
208 kref_put(&iint->refcount, iint_free); 170 kref_put(&iint->refcount, iint_free);
209 return 0;
210} 171}
211EXPORT_SYMBOL_GPL(ima_path_check);
212 172
213static int process_measurement(struct file *file, const unsigned char *filename, 173/*
214 int mask, int function) 174 * Decrement ima counts
175 */
176static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
177 struct file *file)
215{ 178{
216 struct inode *inode = file->f_dentry->d_inode; 179 mode_t mode = file->f_mode;
217 struct ima_iint_cache *iint; 180 BUG_ON(!mutex_is_locked(&iint->mutex));
218 int rc;
219 181
220 if (!ima_initialized || !S_ISREG(inode->i_mode)) 182 iint->opencount--;
221 return 0; 183 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
222 iint = ima_iint_find_insert_get(inode); 184 iint->readcount--;
223 if (!iint) 185 if (mode & FMODE_WRITE) {
224 return -ENOMEM; 186 iint->writecount--;
225 187 if (iint->writecount == 0) {
226 mutex_lock(&iint->mutex); 188 if (iint->version != inode->i_version)
227 rc = ima_must_measure(iint, inode, mask, function); 189 iint->flags &= ~IMA_MEASURED;
228 if (rc != 0) 190 }
229 goto out; 191 }
230 192
231 rc = ima_collect_measurement(iint, file); 193 if (((iint->opencount < 0) ||
232 if (!rc) 194 (iint->readcount < 0) ||
233 ima_store_measurement(iint, file, filename); 195 (iint->writecount < 0)) &&
234out: 196 !ima_limit_imbalance(file)) {
235 mutex_unlock(&iint->mutex); 197 printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
236 kref_put(&iint->refcount, iint_free); 198 __FUNCTION__, iint->readcount, iint->writecount,
237 return rc; 199 iint->opencount);
200 dump_stack();
201 }
238} 202}
239 203
240/* 204/**
241 * ima_counts_put - decrement file counts 205 * ima_file_free - called on __fput()
206 * @file: pointer to file structure being freed
242 * 207 *
243 * File counts are incremented in ima_path_check. On file open 208 * Flag files that changed, based on i_version;
244 * error, such as ETXTBSY, decrement the counts to prevent 209 * and decrement the iint readcount/writecount.
245 * unnecessary imbalance messages.
246 */ 210 */
247void ima_counts_put(struct path *path, int mask) 211void ima_file_free(struct file *file)
248{ 212{
249 struct inode *inode = path->dentry->d_inode; 213 struct inode *inode = file->f_dentry->d_inode;
250 struct ima_iint_cache *iint; 214 struct ima_iint_cache *iint;
251 215
252 /* The inode may already have been freed, freeing the iint 216 if (!ima_initialized || !S_ISREG(inode->i_mode))
253 * with it. Verify the inode is not NULL before dereferencing
254 * it.
255 */
256 if (!ima_initialized || !inode || !S_ISREG(inode->i_mode))
257 return; 217 return;
258 iint = ima_iint_find_insert_get(inode); 218 iint = ima_iint_find_get(inode);
259 if (!iint) 219 if (!iint)
260 return; 220 return;
261 221
262 mutex_lock(&iint->mutex); 222 mutex_lock(&iint->mutex);
263 iint->opencount--; 223 ima_dec_counts(iint, inode, file);
264 if ((mask & MAY_WRITE) || (mask == 0))
265 iint->writecount--;
266 else if (mask & (MAY_READ | MAY_EXEC))
267 iint->readcount--;
268 mutex_unlock(&iint->mutex); 224 mutex_unlock(&iint->mutex);
269
270 kref_put(&iint->refcount, iint_free); 225 kref_put(&iint->refcount, iint_free);
271} 226}
272 227
273/* 228static int process_measurement(struct file *file, const unsigned char *filename,
274 * ima_counts_get - increment file counts 229 int mask, int function)
275 *
276 * - for IPC shm and shmat file.
277 * - for nfsd exported files.
278 *
279 * Increment the counts for these files to prevent unnecessary
280 * imbalance messages.
281 */
282void ima_counts_get(struct file *file)
283{ 230{
284 struct inode *inode = file->f_dentry->d_inode; 231 struct inode *inode = file->f_dentry->d_inode;
285 struct ima_iint_cache *iint; 232 struct ima_iint_cache *iint;
233 int rc;
286 234
287 if (!ima_initialized || !S_ISREG(inode->i_mode)) 235 if (!ima_initialized || !S_ISREG(inode->i_mode))
288 return; 236 return 0;
289 iint = ima_iint_find_insert_get(inode); 237 iint = ima_iint_find_get(inode);
290 if (!iint) 238 if (!iint)
291 return; 239 return -ENOMEM;
240
292 mutex_lock(&iint->mutex); 241 mutex_lock(&iint->mutex);
293 iint->opencount++; 242 rc = ima_must_measure(iint, inode, mask, function);
294 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) 243 if (rc != 0)
295 iint->readcount++; 244 goto out;
296 245
297 if (file->f_mode & FMODE_WRITE) 246 rc = ima_collect_measurement(iint, file);
298 iint->writecount++; 247 if (!rc)
248 ima_store_measurement(iint, file, filename);
249out:
299 mutex_unlock(&iint->mutex); 250 mutex_unlock(&iint->mutex);
300
301 kref_put(&iint->refcount, iint_free); 251 kref_put(&iint->refcount, iint_free);
252 return rc;
302} 253}
303EXPORT_SYMBOL_GPL(ima_counts_get);
304 254
305/** 255/**
306 * ima_file_mmap - based on policy, collect/store measurement. 256 * ima_file_mmap - based on policy, collect/store measurement.
@@ -347,11 +297,31 @@ int ima_bprm_check(struct linux_binprm *bprm)
347 return 0; 297 return 0;
348} 298}
349 299
300/**
301 * ima_path_check - based on policy, collect/store measurement.
302 * @file: pointer to the file to be measured
303 * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
304 *
305 * Measure files based on the ima_must_measure() policy decision.
306 *
307 * Always return 0 and audit dentry_open failures.
308 * (Return code will be based upon measurement appraisal.)
309 */
310int ima_file_check(struct file *file, int mask)
311{
312 int rc;
313
314 rc = process_measurement(file, file->f_dentry->d_name.name,
315 mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
316 FILE_CHECK);
317 return 0;
318}
319EXPORT_SYMBOL_GPL(ima_file_check);
320
350static int __init init_ima(void) 321static int __init init_ima(void)
351{ 322{
352 int error; 323 int error;
353 324
354 ima_iintcache_init();
355 error = ima_init(); 325 error = ima_init();
356 ima_initialized = 1; 326 ima_initialized = 1;
357 return error; 327 return error;