Skip to content

Commit

Permalink
IMA: only allocate iint when needed
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Mimi Zohar <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
eparis authored and torvalds committed Oct 26, 2010
1 parent a178d20 commit bc7d2a3
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 39 deletions.
94 changes: 64 additions & 30 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,41 +141,70 @@ void ima_counts_get(struct file *file)
/*
* Decrement ima counts
*/
static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
struct file *file)
static void ima_dec_counts(struct inode *inode, struct file *file)
{
mode_t mode = file->f_mode;
bool dump = false;

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

if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
if (unlikely(inode->i_readcount == 0))
dump = true;
if (unlikely(inode->i_readcount == 0)) {
if (!ima_limit_imbalance(file)) {
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
__func__, inode->i_readcount);
dump_stack();
}
return;
}
inode->i_readcount--;
}
if (mode & FMODE_WRITE) {
if (atomic_read(&inode->i_writecount) <= 0)
dump = true;
if (atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version)
iint->flags &= ~IMA_MEASURED;
}
}

if (dump && !ima_limit_imbalance(file)) {
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
__func__, inode->i_readcount);
dump_stack();
}
static void ima_check_last_writer(struct ima_iint_cache *iint,
struct inode *inode,
struct file *file)
{
mode_t mode = file->f_mode;

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

if (mode & FMODE_WRITE &&
atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version)
iint->flags &= ~IMA_MEASURED;
}

static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
struct file *file)
{
mutex_lock(&iint->mutex);
spin_lock(&inode->i_lock);

ima_dec_counts(inode, file);
ima_check_last_writer(iint, inode, file);

spin_unlock(&inode->i_lock);
mutex_unlock(&iint->mutex);

kref_put(&iint->refcount, iint_free);
}

static void ima_file_free_noiint(struct inode *inode, struct file *file)
{
spin_lock(&inode->i_lock);

ima_dec_counts(inode, file);

spin_unlock(&inode->i_lock);
}

/**
* ima_file_free - called on __fput()
* @file: pointer to file structure being freed
*
* Flag files that changed, based on i_version;
* and decrement the iint readcount/writecount.
* and decrement the i_readcount.
*/
void ima_file_free(struct file *file)
{
Expand All @@ -185,17 +214,12 @@ void ima_file_free(struct file *file)
if (!iint_initialized || !S_ISREG(inode->i_mode))
return;
iint = ima_iint_find_get(inode);
if (!iint)
return;

mutex_lock(&iint->mutex);
spin_lock(&inode->i_lock);

ima_dec_counts(iint, inode, file);
if (iint)
ima_file_free_iint(iint, inode, file);
else
ima_file_free_noiint(inode, file);

spin_unlock(&inode->i_lock);
mutex_unlock(&iint->mutex);
kref_put(&iint->refcount, iint_free);
}

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

if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;

rc = ima_must_measure(NULL, inode, mask, function);
if (rc != 0)
return rc;
retry:
iint = ima_iint_find_get(inode);
if (!iint)
return -ENOMEM;
if (!iint) {
rc = ima_inode_alloc(inode);
if (!rc || rc == -EEXIST)
goto retry;
return rc;
}

mutex_lock(&iint->mutex);

rc = ima_must_measure(iint, inode, mask, function);
if (rc != 0)
goto out;
Expand Down
10 changes: 1 addition & 9 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);

int security_inode_alloc(struct inode *inode)
{
int ret;

inode->i_security = NULL;
ret = security_ops->inode_alloc_security(inode);
if (ret)
return ret;
ret = ima_inode_alloc(inode);
if (ret)
security_inode_free(inode);
return ret;
return security_ops->inode_alloc_security(inode);
}

void security_inode_free(struct inode *inode)
Expand Down

0 comments on commit bc7d2a3

Please sign in to comment.