Skip to content

Commit bc7d2a3

Browse files
eparistorvalds
authored andcommitted
IMA: only allocate iint when needed
IMA always allocates an integrity structure to hold information about every inode, but only needed this structure to track the number of readers and writers currently accessing a given inode. Since that information was moved into struct inode instead of the integrity struct this patch stops allocating the integrity stucture until it is needed. Thus greatly reducing memory usage. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a178d20 commit bc7d2a3

File tree

2 files changed

+65
-39
lines changed

2 files changed

+65
-39
lines changed

security/integrity/ima/ima_main.c

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -141,41 +141,70 @@ void ima_counts_get(struct file *file)
141141
/*
142142
* Decrement ima counts
143143
*/
144-
static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
145-
struct file *file)
144+
static void ima_dec_counts(struct inode *inode, struct file *file)
146145
{
147146
mode_t mode = file->f_mode;
148-
bool dump = false;
149147

150-
BUG_ON(!mutex_is_locked(&iint->mutex));
151148
assert_spin_locked(&inode->i_lock);
152149

153150
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
154-
if (unlikely(inode->i_readcount == 0))
155-
dump = true;
151+
if (unlikely(inode->i_readcount == 0)) {
152+
if (!ima_limit_imbalance(file)) {
153+
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
154+
__func__, inode->i_readcount);
155+
dump_stack();
156+
}
157+
return;
158+
}
156159
inode->i_readcount--;
157160
}
158-
if (mode & FMODE_WRITE) {
159-
if (atomic_read(&inode->i_writecount) <= 0)
160-
dump = true;
161-
if (atomic_read(&inode->i_writecount) == 1 &&
162-
iint->version != inode->i_version)
163-
iint->flags &= ~IMA_MEASURED;
164-
}
161+
}
165162

166-
if (dump && !ima_limit_imbalance(file)) {
167-
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
168-
__func__, inode->i_readcount);
169-
dump_stack();
170-
}
163+
static void ima_check_last_writer(struct ima_iint_cache *iint,
164+
struct inode *inode,
165+
struct file *file)
166+
{
167+
mode_t mode = file->f_mode;
168+
169+
BUG_ON(!mutex_is_locked(&iint->mutex));
170+
assert_spin_locked(&inode->i_lock);
171+
172+
if (mode & FMODE_WRITE &&
173+
atomic_read(&inode->i_writecount) == 1 &&
174+
iint->version != inode->i_version)
175+
iint->flags &= ~IMA_MEASURED;
176+
}
177+
178+
static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
179+
struct file *file)
180+
{
181+
mutex_lock(&iint->mutex);
182+
spin_lock(&inode->i_lock);
183+
184+
ima_dec_counts(inode, file);
185+
ima_check_last_writer(iint, inode, file);
186+
187+
spin_unlock(&inode->i_lock);
188+
mutex_unlock(&iint->mutex);
189+
190+
kref_put(&iint->refcount, iint_free);
191+
}
192+
193+
static void ima_file_free_noiint(struct inode *inode, struct file *file)
194+
{
195+
spin_lock(&inode->i_lock);
196+
197+
ima_dec_counts(inode, file);
198+
199+
spin_unlock(&inode->i_lock);
171200
}
172201

173202
/**
174203
* ima_file_free - called on __fput()
175204
* @file: pointer to file structure being freed
176205
*
177206
* Flag files that changed, based on i_version;
178-
* and decrement the iint readcount/writecount.
207+
* and decrement the i_readcount.
179208
*/
180209
void ima_file_free(struct file *file)
181210
{
@@ -185,17 +214,12 @@ void ima_file_free(struct file *file)
185214
if (!iint_initialized || !S_ISREG(inode->i_mode))
186215
return;
187216
iint = ima_iint_find_get(inode);
188-
if (!iint)
189-
return;
190217

191-
mutex_lock(&iint->mutex);
192-
spin_lock(&inode->i_lock);
193-
194-
ima_dec_counts(iint, inode, file);
218+
if (iint)
219+
ima_file_free_iint(iint, inode, file);
220+
else
221+
ima_file_free_noiint(inode, file);
195222

196-
spin_unlock(&inode->i_lock);
197-
mutex_unlock(&iint->mutex);
198-
kref_put(&iint->refcount, iint_free);
199223
}
200224

201225
static int process_measurement(struct file *file, const unsigned char *filename,
@@ -207,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
207231

208232
if (!ima_initialized || !S_ISREG(inode->i_mode))
209233
return 0;
234+
235+
rc = ima_must_measure(NULL, inode, mask, function);
236+
if (rc != 0)
237+
return rc;
238+
retry:
210239
iint = ima_iint_find_get(inode);
211-
if (!iint)
212-
return -ENOMEM;
240+
if (!iint) {
241+
rc = ima_inode_alloc(inode);
242+
if (!rc || rc == -EEXIST)
243+
goto retry;
244+
return rc;
245+
}
213246

214247
mutex_lock(&iint->mutex);
248+
215249
rc = ima_must_measure(iint, inode, mask, function);
216250
if (rc != 0)
217251
goto out;

security/security.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -333,16 +333,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
333333

334334
int security_inode_alloc(struct inode *inode)
335335
{
336-
int ret;
337-
338336
inode->i_security = NULL;
339-
ret = security_ops->inode_alloc_security(inode);
340-
if (ret)
341-
return ret;
342-
ret = ima_inode_alloc(inode);
343-
if (ret)
344-
security_inode_free(inode);
345-
return ret;
337+
return security_ops->inode_alloc_security(inode);
346338
}
347339

348340
void security_inode_free(struct inode *inode)

0 commit comments

Comments
 (0)