IMA: update ima_counts_put

- As ima_counts_put() may be called after the inode has been freed,
verify that the inode is not NULL, before dereferencing it.

- Maintain the IMA file counters in may_open() properly, decrementing
any counter increments on subsequent errors.

Reported-by: Ciprian Docan <docan@eden.rutgers.edu>
Reported-by: J.R. Okajima <hooanon05@yahoo.co.jp>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Acked-by: Eric Paris <eparis@redhat.com
Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
Mimi Zohar 2009-09-04 13:08:46 -04:00 committed by James Morris
parent e07cccf404
commit acd0c93517
2 changed files with 20 additions and 8 deletions

View file

@ -1542,28 +1542,31 @@ int may_open(struct path *path, int acc_mode, int flag)
* An append-only file must be opened in append mode for writing. * An append-only file must be opened in append mode for writing.
*/ */
if (IS_APPEND(inode)) { if (IS_APPEND(inode)) {
error = -EPERM;
if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
return -EPERM; goto err_out;
if (flag & O_TRUNC) if (flag & O_TRUNC)
return -EPERM; goto err_out;
} }
/* O_NOATIME can only be set by the owner or superuser */ /* O_NOATIME can only be set by the owner or superuser */
if (flag & O_NOATIME) if (flag & O_NOATIME)
if (!is_owner_or_cap(inode)) if (!is_owner_or_cap(inode)) {
return -EPERM; error = -EPERM;
goto err_out;
}
/* /*
* Ensure there are no outstanding leases on the file. * Ensure there are no outstanding leases on the file.
*/ */
error = break_lease(inode, flag); error = break_lease(inode, flag);
if (error) if (error)
return error; goto err_out;
if (flag & O_TRUNC) { if (flag & O_TRUNC) {
error = get_write_access(inode); error = get_write_access(inode);
if (error) if (error)
return error; goto err_out;
/* /*
* Refuse to truncate files with mandatory locks held on them. * Refuse to truncate files with mandatory locks held on them.
@ -1581,12 +1584,17 @@ int may_open(struct path *path, int acc_mode, int flag)
} }
put_write_access(inode); put_write_access(inode);
if (error) if (error)
return error; goto err_out;
} else } else
if (flag & FMODE_WRITE) if (flag & FMODE_WRITE)
vfs_dq_init(inode); vfs_dq_init(inode);
return 0; return 0;
err_out:
ima_counts_put(path, acc_mode ?
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
ACC_MODE(flag) & (MAY_READ | MAY_WRITE));
return error;
} }
/* /*

View file

@ -249,7 +249,11 @@ void ima_counts_put(struct path *path, int mask)
struct inode *inode = path->dentry->d_inode; struct inode *inode = path->dentry->d_inode;
struct ima_iint_cache *iint; struct ima_iint_cache *iint;
if (!ima_initialized || !S_ISREG(inode->i_mode)) /* The inode may already have been freed, freeing the iint
* with it. Verify the inode is not NULL before dereferencing
* it.
*/
if (!ima_initialized || !inode || !S_ISREG(inode->i_mode))
return; return;
iint = ima_iint_find_insert_get(inode); iint = ima_iint_find_insert_get(inode);
if (!iint) if (!iint)