aboutsummaryrefslogtreecommitdiffstats
path: root/security/integrity/ima
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 15:04:02 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 15:04:02 -0500
commitbac5e54c29f352d962a2447d22735316b347b9f1 (patch)
tree7642993fa93164835ffaa2dacd341388193f1979 /security/integrity/ima
parent529e89430d6c0d64db8ac474cb95e68e2527c79a (diff)
parentc05c4edd876b7ae92787d1295868afcb89b6a348 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (38 commits) direct I/O fallback sync simplification ocfs: stop using do_sync_mapping_range cleanup blockdev_direct_IO locking make generic_acl slightly more generic sanitize xattr handler prototypes libfs: move EXPORT_SYMBOL for d_alloc_name vfs: force reval of target when following LAST_BIND symlinks (try #7) ima: limit imbalance msg Untangling ima mess, part 3: kill dead code in ima Untangling ima mess, part 2: deal with counters Untangling ima mess, part 1: alloc_file() O_TRUNC open shouldn't fail after file truncation ima: call ima_inode_free ima_inode_free IMA: clean up the IMA counts updating code ima: only insert at inode creation time ima: valid return code from ima_inode_alloc fs: move get_empty_filp() deffinition to internal.h Sanitize exec_permission_lite() Kill cached_lookup() and real_lookup() Kill path_lookup_open() ... Trivial conflicts in fs/direct-io.c
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/ima.h3
-rw-r--r--security/integrity/ima/ima_iint.c79
-rw-r--r--security/integrity/ima/ima_main.c184
3 files changed, 115 insertions, 151 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 165eb5397ea..c41afe6639a 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -97,7 +97,6 @@ static inline unsigned long ima_hash_key(u8 *digest)
97 97
98/* iint cache flags */ 98/* iint cache flags */
99#define IMA_MEASURED 1 99#define IMA_MEASURED 1
100#define IMA_IINT_DUMP_STACK 512
101 100
102/* integrity data associated with an inode */ 101/* integrity data associated with an inode */
103struct ima_iint_cache { 102struct ima_iint_cache {
@@ -128,8 +127,6 @@ void ima_template_show(struct seq_file *m, void *e,
128 */ 127 */
129struct ima_iint_cache *ima_iint_insert(struct inode *inode); 128struct ima_iint_cache *ima_iint_insert(struct inode *inode);
130struct ima_iint_cache *ima_iint_find_get(struct inode *inode); 129struct 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); 130void iint_free(struct kref *kref);
134void iint_rcu_free(struct rcu_head *rcu); 131void iint_rcu_free(struct rcu_head *rcu);
135 132
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
index a4e2b1dac94..fa592ff1ac1 100644
--- a/security/integrity/ima/ima_iint.c
+++ b/security/integrity/ima/ima_iint.c
@@ -19,8 +19,6 @@
19#include <linux/radix-tree.h> 19#include <linux/radix-tree.h>
20#include "ima.h" 20#include "ima.h"
21 21
22#define ima_iint_delete ima_inode_free
23
24RADIX_TREE(ima_iint_store, GFP_ATOMIC); 22RADIX_TREE(ima_iint_store, GFP_ATOMIC);
25DEFINE_SPINLOCK(ima_iint_lock); 23DEFINE_SPINLOCK(ima_iint_lock);
26 24
@@ -45,22 +43,21 @@ out:
45 return iint; 43 return iint;
46} 44}
47 45
48/* Allocate memory for the iint associated with the inode 46/**
49 * from the iint_cache slab, initialize the iint, and 47 * ima_inode_alloc - allocate an iint associated with an inode
50 * insert it into the radix tree. 48 * @inode: pointer to the inode
51 *
52 * On success return a pointer to the iint; on failure return NULL.
53 */ 49 */
54struct ima_iint_cache *ima_iint_insert(struct inode *inode) 50int ima_inode_alloc(struct inode *inode)
55{ 51{
56 struct ima_iint_cache *iint = NULL; 52 struct ima_iint_cache *iint = NULL;
57 int rc = 0; 53 int rc = 0;
58 54
59 if (!ima_initialized) 55 if (!ima_initialized)
60 return iint; 56 return 0;
57
61 iint = kmem_cache_alloc(iint_cache, GFP_NOFS); 58 iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
62 if (!iint) 59 if (!iint)
63 return iint; 60 return -ENOMEM;
64 61
65 rc = radix_tree_preload(GFP_NOFS); 62 rc = radix_tree_preload(GFP_NOFS);
66 if (rc < 0) 63 if (rc < 0)
@@ -70,65 +67,13 @@ struct ima_iint_cache *ima_iint_insert(struct inode *inode)
70 rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); 67 rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
71 spin_unlock(&ima_iint_lock); 68 spin_unlock(&ima_iint_lock);
72out: 69out:
73 if (rc < 0) { 70 if (rc < 0)
74 kmem_cache_free(iint_cache, iint); 71 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 72
121 iint = ima_iint_find_get(inode); 73 radix_tree_preload_end();
122 if (iint)
123 return iint;
124
125 iint = ima_iint_insert(inode);
126 if (iint)
127 kref_get(&iint->refcount);
128 74
129 return iint; 75 return rc;
130} 76}
131EXPORT_SYMBOL_GPL(ima_iint_find_insert_get);
132 77
133/* iint_free - called when the iint refcount goes to zero */ 78/* iint_free - called when the iint refcount goes to zero */
134void iint_free(struct kref *kref) 79void iint_free(struct kref *kref)
@@ -164,12 +109,12 @@ void iint_rcu_free(struct rcu_head *rcu_head)
164} 109}
165 110
166/** 111/**
167 * ima_iint_delete - called on integrity_inode_free 112 * ima_inode_free - called on security_inode_free
168 * @inode: pointer to the inode 113 * @inode: pointer to the inode
169 * 114 *
170 * Free the integrity information(iint) associated with an inode. 115 * Free the integrity information(iint) associated with an inode.
171 */ 116 */
172void ima_iint_delete(struct inode *inode) 117void ima_inode_free(struct inode *inode)
173{ 118{
174 struct ima_iint_cache *iint; 119 struct ima_iint_cache *iint;
175 120
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index b85e61bcf24..a89f44d5e03 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -13,8 +13,8 @@
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_path_check.
18 */ 18 */
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/file.h> 20#include <linux/file.h>
@@ -35,6 +35,100 @@ static int __init hash_setup(char *str)
35} 35}
36__setup("ima_hash=", hash_setup); 36__setup("ima_hash=", hash_setup);
37 37
38struct ima_imbalance {
39 struct hlist_node node;
40 unsigned long fsmagic;
41};
42
43/*
44 * ima_limit_imbalance - emit one imbalance message per filesystem type
45 *
46 * Maintain list of filesystem types that do not measure files properly.
47 * Return false if unknown, true if known.
48 */
49static bool ima_limit_imbalance(struct file *file)
50{
51 static DEFINE_SPINLOCK(ima_imbalance_lock);
52 static HLIST_HEAD(ima_imbalance_list);
53
54 struct super_block *sb = file->f_dentry->d_sb;
55 struct ima_imbalance *entry;
56 struct hlist_node *node;
57 bool found = false;
58
59 rcu_read_lock();
60 hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) {
61 if (entry->fsmagic == sb->s_magic) {
62 found = true;
63 break;
64 }
65 }
66 rcu_read_unlock();
67 if (found)
68 goto out;
69
70 entry = kmalloc(sizeof(*entry), GFP_NOFS);
71 if (!entry)
72 goto out;
73 entry->fsmagic = sb->s_magic;
74 spin_lock(&ima_imbalance_lock);
75 /*
76 * we could have raced and something else might have added this fs
77 * to the list, but we don't really care
78 */
79 hlist_add_head_rcu(&entry->node, &ima_imbalance_list);
80 spin_unlock(&ima_imbalance_lock);
81 printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n",
82 entry->fsmagic);
83out:
84 return found;
85}
86
87/*
88 * Update the counts given an fmode_t
89 */
90static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
91{
92 BUG_ON(!mutex_is_locked(&iint->mutex));
93
94 iint->opencount++;
95 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
96 iint->readcount++;
97 if (mode & FMODE_WRITE)
98 iint->writecount++;
99}
100
101/*
102 * Decrement ima counts
103 */
104static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
105 struct file *file)
106{
107 mode_t mode = file->f_mode;
108 BUG_ON(!mutex_is_locked(&iint->mutex));
109
110 iint->opencount--;
111 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
112 iint->readcount--;
113 if (mode & FMODE_WRITE) {
114 iint->writecount--;
115 if (iint->writecount == 0) {
116 if (iint->version != inode->i_version)
117 iint->flags &= ~IMA_MEASURED;
118 }
119 }
120
121 if (((iint->opencount < 0) ||
122 (iint->readcount < 0) ||
123 (iint->writecount < 0)) &&
124 !ima_limit_imbalance(file)) {
125 printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
126 __FUNCTION__, iint->readcount, iint->writecount,
127 iint->opencount);
128 dump_stack();
129 }
130}
131
38/** 132/**
39 * ima_file_free - called on __fput() 133 * ima_file_free - called on __fput()
40 * @file: pointer to file structure being freed 134 * @file: pointer to file structure being freed
@@ -54,29 +148,7 @@ void ima_file_free(struct file *file)
54 return; 148 return;
55 149
56 mutex_lock(&iint->mutex); 150 mutex_lock(&iint->mutex);
57 if (iint->opencount <= 0) { 151 ima_dec_counts(iint, inode, file);
58 printk(KERN_INFO
59 "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n",
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 }
67 }
68 iint->opencount--;
69
70 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
71 iint->readcount--;
72
73 if (file->f_mode & FMODE_WRITE) {
74 iint->writecount--;
75 if (iint->writecount == 0) {
76 if (iint->version != inode->i_version)
77 iint->flags &= ~IMA_MEASURED;
78 }
79 }
80 mutex_unlock(&iint->mutex); 152 mutex_unlock(&iint->mutex);
81 kref_put(&iint->refcount, iint_free); 153 kref_put(&iint->refcount, iint_free);
82} 154}
@@ -116,8 +188,7 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
116{ 188{
117 int rc = 0; 189 int rc = 0;
118 190
119 iint->opencount++; 191 ima_inc_counts(iint, file->f_mode);
120 iint->readcount++;
121 192
122 rc = ima_collect_measurement(iint, file); 193 rc = ima_collect_measurement(iint, file);
123 if (!rc) 194 if (!rc)
@@ -125,15 +196,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
125 return rc; 196 return rc;
126} 197}
127 198
128static void ima_update_counts(struct ima_iint_cache *iint, int mask)
129{
130 iint->opencount++;
131 if ((mask & MAY_WRITE) || (mask == 0))
132 iint->writecount++;
133 else if (mask & (MAY_READ | MAY_EXEC))
134 iint->readcount++;
135}
136
137/** 199/**
138 * ima_path_check - based on policy, collect/store measurement. 200 * ima_path_check - based on policy, collect/store measurement.
139 * @path: contains a pointer to the path to be measured 201 * @path: contains a pointer to the path to be measured
@@ -152,7 +214,7 @@ static void ima_update_counts(struct ima_iint_cache *iint, int mask)
152 * Always return 0 and audit dentry_open failures. 214 * Always return 0 and audit dentry_open failures.
153 * (Return code will be based upon measurement appraisal.) 215 * (Return code will be based upon measurement appraisal.)
154 */ 216 */
155int ima_path_check(struct path *path, int mask, int update_counts) 217int ima_path_check(struct path *path, int mask)
156{ 218{
157 struct inode *inode = path->dentry->d_inode; 219 struct inode *inode = path->dentry->d_inode;
158 struct ima_iint_cache *iint; 220 struct ima_iint_cache *iint;
@@ -161,13 +223,11 @@ int ima_path_check(struct path *path, int mask, int update_counts)
161 223
162 if (!ima_initialized || !S_ISREG(inode->i_mode)) 224 if (!ima_initialized || !S_ISREG(inode->i_mode))
163 return 0; 225 return 0;
164 iint = ima_iint_find_insert_get(inode); 226 iint = ima_iint_find_get(inode);
165 if (!iint) 227 if (!iint)
166 return 0; 228 return 0;
167 229
168 mutex_lock(&iint->mutex); 230 mutex_lock(&iint->mutex);
169 if (update_counts)
170 ima_update_counts(iint, mask);
171 231
172 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); 232 rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
173 if (rc < 0) 233 if (rc < 0)
@@ -219,7 +279,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
219 279
220 if (!ima_initialized || !S_ISREG(inode->i_mode)) 280 if (!ima_initialized || !S_ISREG(inode->i_mode))
221 return 0; 281 return 0;
222 iint = ima_iint_find_insert_get(inode); 282 iint = ima_iint_find_get(inode);
223 if (!iint) 283 if (!iint)
224 return -ENOMEM; 284 return -ENOMEM;
225 285
@@ -238,39 +298,6 @@ out:
238} 298}
239 299
240/* 300/*
241 * ima_counts_put - decrement file counts
242 *
243 * File counts are incremented in ima_path_check. On file open
244 * error, such as ETXTBSY, decrement the counts to prevent
245 * unnecessary imbalance messages.
246 */
247void ima_counts_put(struct path *path, int mask)
248{
249 struct inode *inode = path->dentry->d_inode;
250 struct ima_iint_cache *iint;
251
252 /* The inode may already have been freed, freeing the iint
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;
258 iint = ima_iint_find_insert_get(inode);
259 if (!iint)
260 return;
261
262 mutex_lock(&iint->mutex);
263 iint->opencount--;
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);
269
270 kref_put(&iint->refcount, iint_free);
271}
272
273/*
274 * ima_counts_get - increment file counts 301 * ima_counts_get - increment file counts
275 * 302 *
276 * - for IPC shm and shmat file. 303 * - for IPC shm and shmat file.
@@ -286,16 +313,11 @@ void ima_counts_get(struct file *file)
286 313
287 if (!ima_initialized || !S_ISREG(inode->i_mode)) 314 if (!ima_initialized || !S_ISREG(inode->i_mode))
288 return; 315 return;
289 iint = ima_iint_find_insert_get(inode); 316 iint = ima_iint_find_get(inode);
290 if (!iint) 317 if (!iint)
291 return; 318 return;
292 mutex_lock(&iint->mutex); 319 mutex_lock(&iint->mutex);
293 iint->opencount++; 320 ima_inc_counts(iint, file->f_mode);
294 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
295 iint->readcount++;
296
297 if (file->f_mode & FMODE_WRITE)
298 iint->writecount++;
299 mutex_unlock(&iint->mutex); 321 mutex_unlock(&iint->mutex);
300 322
301 kref_put(&iint->refcount, iint_free); 323 kref_put(&iint->refcount, iint_free);