diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 14:37:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 14:37:48 -0400 |
commit | f9ba5375a8aae4aeea6be15df77e24707a429812 (patch) | |
tree | c6388d7e40f0f6a70d7ba6a4d4aeaa0d1f5591f6 /security | |
parent | 45352bbf48e95078b4acd20774f49e72676e1e0f (diff) | |
parent | bade72d607c4eb1b1d6c7852c493b75f065a56b5 (diff) |
Merge branch 'ima-memory-use-fixes'
* ima-memory-use-fixes:
IMA: fix the ToMToU logic
IMA: explicit IMA i_flag to remove global lock on inode_delete
IMA: drop refcnt from ima_iint_cache since it isn't needed
IMA: only allocate iint when needed
IMA: move read counter into struct inode
IMA: use i_writecount rather than a private counter
IMA: use inode->i_lock to protect read and write counters
IMA: convert internal flags from long to char
IMA: use unsigned int instead of long for counters
IMA: drop the inode opencount since it isn't needed for operation
IMA: use rbtree instead of radix tree for inode information cache
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/ima/ima.h | 18 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_iint.c | 158 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 184 | ||||
-rw-r--r-- | security/security.c | 10 |
5 files changed, 195 insertions, 177 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3fbcd1dda0ef..ac79032bdf23 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -70,6 +70,7 @@ int ima_init(void); | |||
70 | void ima_cleanup(void); | 70 | void ima_cleanup(void); |
71 | int ima_fs_init(void); | 71 | int ima_fs_init(void); |
72 | void ima_fs_cleanup(void); | 72 | void ima_fs_cleanup(void); |
73 | int ima_inode_alloc(struct inode *inode); | ||
73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | 74 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, |
74 | const char *op, struct inode *inode); | 75 | const char *op, struct inode *inode); |
75 | int ima_calc_hash(struct file *file, char *digest); | 76 | int ima_calc_hash(struct file *file, char *digest); |
@@ -96,19 +97,16 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
96 | } | 97 | } |
97 | 98 | ||
98 | /* iint cache flags */ | 99 | /* iint cache flags */ |
99 | #define IMA_MEASURED 1 | 100 | #define IMA_MEASURED 0x01 |
100 | 101 | ||
101 | /* integrity data associated with an inode */ | 102 | /* integrity data associated with an inode */ |
102 | struct ima_iint_cache { | 103 | struct ima_iint_cache { |
104 | struct rb_node rb_node; /* rooted in ima_iint_tree */ | ||
105 | struct inode *inode; /* back pointer to inode in question */ | ||
103 | u64 version; /* track inode changes */ | 106 | u64 version; /* track inode changes */ |
104 | unsigned long flags; | 107 | unsigned char flags; |
105 | u8 digest[IMA_DIGEST_SIZE]; | 108 | u8 digest[IMA_DIGEST_SIZE]; |
106 | struct mutex mutex; /* protects: version, flags, digest */ | 109 | struct mutex mutex; /* protects: version, flags, digest */ |
107 | long readcount; /* measured files readcount */ | ||
108 | long writecount; /* measured files writecount */ | ||
109 | long opencount; /* opens reference count */ | ||
110 | struct kref refcount; /* ima_iint_cache reference count */ | ||
111 | struct rcu_head rcu; | ||
112 | }; | 110 | }; |
113 | 111 | ||
114 | /* LIM API function definitions */ | 112 | /* LIM API function definitions */ |
@@ -122,13 +120,11 @@ int ima_store_template(struct ima_template_entry *entry, int violation, | |||
122 | void ima_template_show(struct seq_file *m, void *e, | 120 | void ima_template_show(struct seq_file *m, void *e, |
123 | enum ima_show_type show); | 121 | enum ima_show_type show); |
124 | 122 | ||
125 | /* radix tree calls to lookup, insert, delete | 123 | /* rbtree tree calls to lookup, insert, delete |
126 | * integrity data associated with an inode. | 124 | * integrity data associated with an inode. |
127 | */ | 125 | */ |
128 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | 126 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); |
129 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | 127 | struct ima_iint_cache *ima_iint_find(struct inode *inode); |
130 | void iint_free(struct kref *kref); | ||
131 | void iint_rcu_free(struct rcu_head *rcu); | ||
132 | 128 | ||
133 | /* IMA policy related functions */ | 129 | /* IMA policy related functions */ |
134 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 130 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 52015d098fdf..d3963de6003d 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -116,7 +116,7 @@ int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | |||
116 | { | 116 | { |
117 | int must_measure; | 117 | int must_measure; |
118 | 118 | ||
119 | if (iint->flags & IMA_MEASURED) | 119 | if (iint && iint->flags & IMA_MEASURED) |
120 | return 1; | 120 | return 1; |
121 | 121 | ||
122 | must_measure = ima_match_policy(inode, function, mask); | 122 | must_measure = ima_match_policy(inode, function, mask); |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index afba4aef812f..c442e47b6785 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
@@ -12,98 +12,119 @@ | |||
12 | * File: ima_iint.c | 12 | * File: ima_iint.c |
13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | 13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free |
14 | * - cache integrity information associated with an inode | 14 | * - cache integrity information associated with an inode |
15 | * using a radix tree. | 15 | * using a rbtree tree. |
16 | */ | 16 | */ |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/radix-tree.h> | 20 | #include <linux/rbtree.h> |
21 | #include "ima.h" | 21 | #include "ima.h" |
22 | 22 | ||
23 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | 23 | static struct rb_root ima_iint_tree = RB_ROOT; |
24 | DEFINE_SPINLOCK(ima_iint_lock); | 24 | static DEFINE_SPINLOCK(ima_iint_lock); |
25 | static struct kmem_cache *iint_cache __read_mostly; | 25 | static struct kmem_cache *iint_cache __read_mostly; |
26 | 26 | ||
27 | int iint_initialized = 0; | 27 | int iint_initialized = 0; |
28 | 28 | ||
29 | /* ima_iint_find_get - return the iint associated with an inode | 29 | /* |
30 | * | 30 | * __ima_iint_find - return the iint associated with an inode |
31 | * ima_iint_find_get gets a reference to the iint. Caller must | ||
32 | * remember to put the iint reference. | ||
33 | */ | 31 | */ |
34 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode) | 32 | static struct ima_iint_cache *__ima_iint_find(struct inode *inode) |
35 | { | 33 | { |
36 | struct ima_iint_cache *iint; | 34 | struct ima_iint_cache *iint; |
35 | struct rb_node *n = ima_iint_tree.rb_node; | ||
36 | |||
37 | assert_spin_locked(&ima_iint_lock); | ||
38 | |||
39 | while (n) { | ||
40 | iint = rb_entry(n, struct ima_iint_cache, rb_node); | ||
41 | |||
42 | if (inode < iint->inode) | ||
43 | n = n->rb_left; | ||
44 | else if (inode > iint->inode) | ||
45 | n = n->rb_right; | ||
46 | else | ||
47 | break; | ||
48 | } | ||
49 | if (!n) | ||
50 | return NULL; | ||
37 | 51 | ||
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); | ||
43 | out: | ||
44 | rcu_read_unlock(); | ||
45 | return iint; | 52 | return iint; |
46 | } | 53 | } |
47 | 54 | ||
48 | /** | 55 | /* |
49 | * ima_inode_alloc - allocate an iint associated with an inode | 56 | * ima_iint_find - return the iint associated with an inode |
50 | * @inode: pointer to the inode | ||
51 | */ | 57 | */ |
52 | int ima_inode_alloc(struct inode *inode) | 58 | struct ima_iint_cache *ima_iint_find(struct inode *inode) |
53 | { | 59 | { |
54 | struct ima_iint_cache *iint = NULL; | 60 | struct ima_iint_cache *iint; |
55 | int rc = 0; | ||
56 | |||
57 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
58 | if (!iint) | ||
59 | return -ENOMEM; | ||
60 | 61 | ||
61 | rc = radix_tree_preload(GFP_NOFS); | 62 | if (!IS_IMA(inode)) |
62 | if (rc < 0) | 63 | return NULL; |
63 | goto out; | ||
64 | 64 | ||
65 | spin_lock(&ima_iint_lock); | 65 | spin_lock(&ima_iint_lock); |
66 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | 66 | iint = __ima_iint_find(inode); |
67 | spin_unlock(&ima_iint_lock); | 67 | spin_unlock(&ima_iint_lock); |
68 | radix_tree_preload_end(); | ||
69 | out: | ||
70 | if (rc < 0) | ||
71 | kmem_cache_free(iint_cache, iint); | ||
72 | 68 | ||
73 | return rc; | 69 | return iint; |
74 | } | 70 | } |
75 | 71 | ||
76 | /* iint_free - called when the iint refcount goes to zero */ | 72 | static void iint_free(struct ima_iint_cache *iint) |
77 | void iint_free(struct kref *kref) | ||
78 | { | 73 | { |
79 | struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, | ||
80 | refcount); | ||
81 | iint->version = 0; | 74 | iint->version = 0; |
82 | iint->flags = 0UL; | 75 | iint->flags = 0UL; |
83 | if (iint->readcount != 0) { | ||
84 | printk(KERN_INFO "%s: readcount: %ld\n", __func__, | ||
85 | iint->readcount); | ||
86 | iint->readcount = 0; | ||
87 | } | ||
88 | if (iint->writecount != 0) { | ||
89 | printk(KERN_INFO "%s: writecount: %ld\n", __func__, | ||
90 | iint->writecount); | ||
91 | iint->writecount = 0; | ||
92 | } | ||
93 | if (iint->opencount != 0) { | ||
94 | printk(KERN_INFO "%s: opencount: %ld\n", __func__, | ||
95 | iint->opencount); | ||
96 | iint->opencount = 0; | ||
97 | } | ||
98 | kref_init(&iint->refcount); | ||
99 | kmem_cache_free(iint_cache, iint); | 76 | kmem_cache_free(iint_cache, iint); |
100 | } | 77 | } |
101 | 78 | ||
102 | void iint_rcu_free(struct rcu_head *rcu_head) | 79 | /** |
80 | * ima_inode_alloc - allocate an iint associated with an inode | ||
81 | * @inode: pointer to the inode | ||
82 | */ | ||
83 | int ima_inode_alloc(struct inode *inode) | ||
103 | { | 84 | { |
104 | struct ima_iint_cache *iint = container_of(rcu_head, | 85 | struct rb_node **p; |
105 | struct ima_iint_cache, rcu); | 86 | struct rb_node *new_node, *parent = NULL; |
106 | kref_put(&iint->refcount, iint_free); | 87 | struct ima_iint_cache *new_iint, *test_iint; |
88 | int rc; | ||
89 | |||
90 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
91 | if (!new_iint) | ||
92 | return -ENOMEM; | ||
93 | |||
94 | new_iint->inode = inode; | ||
95 | new_node = &new_iint->rb_node; | ||
96 | |||
97 | mutex_lock(&inode->i_mutex); /* i_flags */ | ||
98 | spin_lock(&ima_iint_lock); | ||
99 | |||
100 | p = &ima_iint_tree.rb_node; | ||
101 | while (*p) { | ||
102 | parent = *p; | ||
103 | test_iint = rb_entry(parent, struct ima_iint_cache, rb_node); | ||
104 | |||
105 | rc = -EEXIST; | ||
106 | if (inode < test_iint->inode) | ||
107 | p = &(*p)->rb_left; | ||
108 | else if (inode > test_iint->inode) | ||
109 | p = &(*p)->rb_right; | ||
110 | else | ||
111 | goto out_err; | ||
112 | } | ||
113 | |||
114 | inode->i_flags |= S_IMA; | ||
115 | rb_link_node(new_node, parent, p); | ||
116 | rb_insert_color(new_node, &ima_iint_tree); | ||
117 | |||
118 | spin_unlock(&ima_iint_lock); | ||
119 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
120 | |||
121 | return 0; | ||
122 | out_err: | ||
123 | spin_unlock(&ima_iint_lock); | ||
124 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
125 | iint_free(new_iint); | ||
126 | |||
127 | return rc; | ||
107 | } | 128 | } |
108 | 129 | ||
109 | /** | 130 | /** |
@@ -116,11 +137,20 @@ void ima_inode_free(struct inode *inode) | |||
116 | { | 137 | { |
117 | struct ima_iint_cache *iint; | 138 | struct ima_iint_cache *iint; |
118 | 139 | ||
140 | if (inode->i_readcount) | ||
141 | printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount); | ||
142 | |||
143 | inode->i_readcount = 0; | ||
144 | |||
145 | if (!IS_IMA(inode)) | ||
146 | return; | ||
147 | |||
119 | spin_lock(&ima_iint_lock); | 148 | spin_lock(&ima_iint_lock); |
120 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | 149 | iint = __ima_iint_find(inode); |
150 | rb_erase(&iint->rb_node, &ima_iint_tree); | ||
121 | spin_unlock(&ima_iint_lock); | 151 | spin_unlock(&ima_iint_lock); |
122 | if (iint) | 152 | |
123 | call_rcu(&iint->rcu, iint_rcu_free); | 153 | iint_free(iint); |
124 | } | 154 | } |
125 | 155 | ||
126 | static void init_once(void *foo) | 156 | static void init_once(void *foo) |
@@ -131,10 +161,6 @@ static void init_once(void *foo) | |||
131 | iint->version = 0; | 161 | iint->version = 0; |
132 | iint->flags = 0UL; | 162 | iint->flags = 0UL; |
133 | mutex_init(&iint->mutex); | 163 | mutex_init(&iint->mutex); |
134 | iint->readcount = 0; | ||
135 | iint->writecount = 0; | ||
136 | iint->opencount = 0; | ||
137 | kref_init(&iint->refcount); | ||
138 | } | 164 | } |
139 | 165 | ||
140 | static int __init ima_iintcache_init(void) | 166 | static int __init ima_iintcache_init(void) |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index e662b89d4079..203de979d305 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -85,50 +85,6 @@ out: | |||
85 | return found; | 85 | return found; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
89 | * | ||
90 | * When opening a file for read, if the file is already open for write, | ||
91 | * the file could change, resulting in a file measurement error. | ||
92 | * | ||
93 | * Opening a file for write, if the file is already open for read, results | ||
94 | * in a time of measure, time of use (ToMToU) error. | ||
95 | * | ||
96 | * In either case invalidate the PCR. | ||
97 | */ | ||
98 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
99 | static void ima_read_write_check(enum iint_pcr_error error, | ||
100 | struct ima_iint_cache *iint, | ||
101 | struct inode *inode, | ||
102 | const unsigned char *filename) | ||
103 | { | ||
104 | switch (error) { | ||
105 | case TOMTOU: | ||
106 | if (iint->readcount > 0) | ||
107 | ima_add_violation(inode, filename, "invalid_pcr", | ||
108 | "ToMToU"); | ||
109 | break; | ||
110 | case OPEN_WRITERS: | ||
111 | if (iint->writecount > 0) | ||
112 | ima_add_violation(inode, filename, "invalid_pcr", | ||
113 | "open_writers"); | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Update the counts given an fmode_t | ||
120 | */ | ||
121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | ||
122 | { | ||
123 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
124 | |||
125 | iint->opencount++; | ||
126 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
127 | iint->readcount++; | ||
128 | if (mode & FMODE_WRITE) | ||
129 | iint->writecount++; | ||
130 | } | ||
131 | |||
132 | /* | 88 | /* |
133 | * ima_counts_get - increment file counts | 89 | * ima_counts_get - increment file counts |
134 | * | 90 | * |
@@ -145,62 +101,101 @@ void ima_counts_get(struct file *file) | |||
145 | struct dentry *dentry = file->f_path.dentry; | 101 | struct dentry *dentry = file->f_path.dentry; |
146 | struct inode *inode = dentry->d_inode; | 102 | struct inode *inode = dentry->d_inode; |
147 | fmode_t mode = file->f_mode; | 103 | fmode_t mode = file->f_mode; |
148 | struct ima_iint_cache *iint; | ||
149 | int rc; | 104 | int rc; |
105 | bool send_tomtou = false, send_writers = false; | ||
150 | 106 | ||
151 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 107 | if (!S_ISREG(inode->i_mode)) |
152 | return; | 108 | return; |
153 | iint = ima_iint_find_get(inode); | 109 | |
154 | if (!iint) | 110 | spin_lock(&inode->i_lock); |
155 | return; | 111 | |
156 | mutex_lock(&iint->mutex); | ||
157 | if (!ima_initialized) | 112 | if (!ima_initialized) |
158 | goto out; | 113 | goto out; |
159 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | ||
160 | if (rc < 0) | ||
161 | goto out; | ||
162 | 114 | ||
163 | if (mode & FMODE_WRITE) { | 115 | if (mode & FMODE_WRITE) { |
164 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | 116 | if (inode->i_readcount && IS_IMA(inode)) |
117 | send_tomtou = true; | ||
165 | goto out; | 118 | goto out; |
166 | } | 119 | } |
167 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | 120 | |
121 | rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK); | ||
122 | if (rc < 0) | ||
123 | goto out; | ||
124 | |||
125 | if (atomic_read(&inode->i_writecount) > 0) | ||
126 | send_writers = true; | ||
168 | out: | 127 | out: |
169 | ima_inc_counts(iint, file->f_mode); | 128 | /* remember the vfs deals with i_writecount */ |
170 | mutex_unlock(&iint->mutex); | 129 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
130 | inode->i_readcount++; | ||
171 | 131 | ||
172 | kref_put(&iint->refcount, iint_free); | 132 | spin_unlock(&inode->i_lock); |
133 | |||
134 | if (send_tomtou) | ||
135 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
136 | "ToMToU"); | ||
137 | if (send_writers) | ||
138 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
139 | "open_writers"); | ||
173 | } | 140 | } |
174 | 141 | ||
175 | /* | 142 | /* |
176 | * Decrement ima counts | 143 | * Decrement ima counts |
177 | */ | 144 | */ |
178 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | 145 | static void ima_dec_counts(struct inode *inode, struct file *file) |
179 | struct file *file) | ||
180 | { | 146 | { |
181 | mode_t mode = file->f_mode; | 147 | mode_t mode = file->f_mode; |
182 | BUG_ON(!mutex_is_locked(&iint->mutex)); | ||
183 | 148 | ||
184 | iint->opencount--; | 149 | assert_spin_locked(&inode->i_lock); |
185 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 150 | |
186 | iint->readcount--; | 151 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { |
187 | if (mode & FMODE_WRITE) { | 152 | if (unlikely(inode->i_readcount == 0)) { |
188 | iint->writecount--; | 153 | if (!ima_limit_imbalance(file)) { |
189 | if (iint->writecount == 0) { | 154 | printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", |
190 | if (iint->version != inode->i_version) | 155 | __func__, inode->i_readcount); |
191 | iint->flags &= ~IMA_MEASURED; | 156 | dump_stack(); |
157 | } | ||
158 | return; | ||
192 | } | 159 | } |
160 | inode->i_readcount--; | ||
193 | } | 161 | } |
162 | } | ||
194 | 163 | ||
195 | if (((iint->opencount < 0) || | 164 | static void ima_check_last_writer(struct ima_iint_cache *iint, |
196 | (iint->readcount < 0) || | 165 | struct inode *inode, |
197 | (iint->writecount < 0)) && | 166 | struct file *file) |
198 | !ima_limit_imbalance(file)) { | 167 | { |
199 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", | 168 | mode_t mode = file->f_mode; |
200 | __func__, iint->readcount, iint->writecount, | 169 | |
201 | iint->opencount); | 170 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
202 | dump_stack(); | 171 | assert_spin_locked(&inode->i_lock); |
203 | } | 172 | |
173 | if (mode & FMODE_WRITE && | ||
174 | atomic_read(&inode->i_writecount) == 1 && | ||
175 | iint->version != inode->i_version) | ||
176 | iint->flags &= ~IMA_MEASURED; | ||
177 | } | ||
178 | |||
179 | static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode, | ||
180 | struct file *file) | ||
181 | { | ||
182 | mutex_lock(&iint->mutex); | ||
183 | spin_lock(&inode->i_lock); | ||
184 | |||
185 | ima_dec_counts(inode, file); | ||
186 | ima_check_last_writer(iint, inode, file); | ||
187 | |||
188 | spin_unlock(&inode->i_lock); | ||
189 | mutex_unlock(&iint->mutex); | ||
190 | } | ||
191 | |||
192 | static void ima_file_free_noiint(struct inode *inode, struct file *file) | ||
193 | { | ||
194 | spin_lock(&inode->i_lock); | ||
195 | |||
196 | ima_dec_counts(inode, file); | ||
197 | |||
198 | spin_unlock(&inode->i_lock); | ||
204 | } | 199 | } |
205 | 200 | ||
206 | /** | 201 | /** |
@@ -208,7 +203,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
208 | * @file: pointer to file structure being freed | 203 | * @file: pointer to file structure being freed |
209 | * | 204 | * |
210 | * Flag files that changed, based on i_version; | 205 | * Flag files that changed, based on i_version; |
211 | * and decrement the iint readcount/writecount. | 206 | * and decrement the i_readcount. |
212 | */ | 207 | */ |
213 | void ima_file_free(struct file *file) | 208 | void ima_file_free(struct file *file) |
214 | { | 209 | { |
@@ -217,14 +212,14 @@ void ima_file_free(struct file *file) | |||
217 | 212 | ||
218 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 213 | if (!iint_initialized || !S_ISREG(inode->i_mode)) |
219 | return; | 214 | return; |
220 | iint = ima_iint_find_get(inode); | ||
221 | if (!iint) | ||
222 | return; | ||
223 | 215 | ||
224 | mutex_lock(&iint->mutex); | 216 | iint = ima_iint_find(inode); |
225 | ima_dec_counts(iint, inode, file); | 217 | |
226 | mutex_unlock(&iint->mutex); | 218 | if (iint) |
227 | kref_put(&iint->refcount, iint_free); | 219 | ima_file_free_iint(iint, inode, file); |
220 | else | ||
221 | ima_file_free_noiint(inode, file); | ||
222 | |||
228 | } | 223 | } |
229 | 224 | ||
230 | static int process_measurement(struct file *file, const unsigned char *filename, | 225 | static int process_measurement(struct file *file, const unsigned char *filename, |
@@ -236,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
236 | 231 | ||
237 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 232 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
238 | return 0; | 233 | return 0; |
239 | iint = ima_iint_find_get(inode); | 234 | |
240 | if (!iint) | 235 | rc = ima_must_measure(NULL, inode, mask, function); |
241 | return -ENOMEM; | 236 | if (rc != 0) |
237 | return rc; | ||
238 | retry: | ||
239 | iint = ima_iint_find(inode); | ||
240 | if (!iint) { | ||
241 | rc = ima_inode_alloc(inode); | ||
242 | if (!rc || rc == -EEXIST) | ||
243 | goto retry; | ||
244 | return rc; | ||
245 | } | ||
242 | 246 | ||
243 | mutex_lock(&iint->mutex); | 247 | mutex_lock(&iint->mutex); |
248 | |||
244 | rc = ima_must_measure(iint, inode, mask, function); | 249 | rc = ima_must_measure(iint, inode, mask, function); |
245 | if (rc != 0) | 250 | if (rc != 0) |
246 | goto out; | 251 | goto out; |
@@ -250,7 +255,6 @@ static int process_measurement(struct file *file, const unsigned char *filename, | |||
250 | ima_store_measurement(iint, file, filename); | 255 | ima_store_measurement(iint, file, filename); |
251 | out: | 256 | out: |
252 | mutex_unlock(&iint->mutex); | 257 | mutex_unlock(&iint->mutex); |
253 | kref_put(&iint->refcount, iint_free); | ||
254 | return rc; | 258 | return rc; |
255 | } | 259 | } |
256 | 260 | ||
diff --git a/security/security.c b/security/security.c index b50f472061a4..3ef5e2a7a741 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -325,16 +325,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str); | |||
325 | 325 | ||
326 | int security_inode_alloc(struct inode *inode) | 326 | int security_inode_alloc(struct inode *inode) |
327 | { | 327 | { |
328 | int ret; | ||
329 | |||
330 | inode->i_security = NULL; | 328 | inode->i_security = NULL; |
331 | ret = security_ops->inode_alloc_security(inode); | 329 | return security_ops->inode_alloc_security(inode); |
332 | if (ret) | ||
333 | return ret; | ||
334 | ret = ima_inode_alloc(inode); | ||
335 | if (ret) | ||
336 | security_inode_free(inode); | ||
337 | return ret; | ||
338 | } | 330 | } |
339 | 331 | ||
340 | void security_inode_free(struct inode *inode) | 332 | void security_inode_free(struct inode *inode) |