Commit bc7d2a3e authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds

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: default avatarEric Paris <eparis@redhat.com>
Acked-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a178d202
...@@ -141,33 +141,62 @@ void ima_counts_get(struct file *file) ...@@ -141,33 +141,62 @@ void ima_counts_get(struct file *file)
/* /*
* Decrement ima counts * Decrement ima counts
*/ */
static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, static void ima_dec_counts(struct inode *inode, struct file *file)
struct file *file)
{ {
mode_t mode = file->f_mode; mode_t mode = file->f_mode;
bool dump = false;
BUG_ON(!mutex_is_locked(&iint->mutex));
assert_spin_locked(&inode->i_lock); assert_spin_locked(&inode->i_lock);
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
if (unlikely(inode->i_readcount == 0)) if (unlikely(inode->i_readcount == 0)) {
dump = true; 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--; 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)) { static void ima_check_last_writer(struct ima_iint_cache *iint,
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n", struct inode *inode,
__func__, inode->i_readcount); struct file *file)
dump_stack(); {
} 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);
} }
/** /**
...@@ -175,7 +204,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, ...@@ -175,7 +204,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
* @file: pointer to file structure being freed * @file: pointer to file structure being freed
* *
* Flag files that changed, based on i_version; * 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) void ima_file_free(struct file *file)
{ {
...@@ -185,17 +214,12 @@ void ima_file_free(struct file *file) ...@@ -185,17 +214,12 @@ void ima_file_free(struct file *file)
if (!iint_initialized || !S_ISREG(inode->i_mode)) if (!iint_initialized || !S_ISREG(inode->i_mode))
return; return;
iint = ima_iint_find_get(inode); iint = ima_iint_find_get(inode);
if (!iint)
return;
mutex_lock(&iint->mutex); if (iint)
spin_lock(&inode->i_lock); ima_file_free_iint(iint, inode, file);
else
ima_dec_counts(iint, inode, file); 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, 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, ...@@ -207,11 +231,21 @@ static int process_measurement(struct file *file, const unsigned char *filename,
if (!ima_initialized || !S_ISREG(inode->i_mode)) if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0; return 0;
rc = ima_must_measure(NULL, inode, mask, function);
if (rc != 0)
return rc;
retry:
iint = ima_iint_find_get(inode); iint = ima_iint_find_get(inode);
if (!iint) if (!iint) {
return -ENOMEM; rc = ima_inode_alloc(inode);
if (!rc || rc == -EEXIST)
goto retry;
return rc;
}
mutex_lock(&iint->mutex); mutex_lock(&iint->mutex);
rc = ima_must_measure(iint, inode, mask, function); rc = ima_must_measure(iint, inode, mask, function);
if (rc != 0) if (rc != 0)
goto out; goto out;
......
...@@ -333,16 +333,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str); ...@@ -333,16 +333,8 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
int security_inode_alloc(struct inode *inode) int security_inode_alloc(struct inode *inode)
{ {
int ret;
inode->i_security = NULL; inode->i_security = NULL;
ret = security_ops->inode_alloc_security(inode); return security_ops->inode_alloc_security(inode);
if (ret)
return ret;
ret = ima_inode_alloc(inode);
if (ret)
security_inode_free(inode);
return ret;
} }
void security_inode_free(struct inode *inode) void security_inode_free(struct inode *inode)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment