aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMimi Zohar <zohar@linux.vnet.ibm.com>2009-09-04 13:08:46 -0400
committerJames Morris <jmorris@namei.org>2009-09-07 11:54:58 +1000
commitacd0c935178649f72c44ec49ca83bee35ce1f79e (patch)
treec0cb2f8fbbaa54567785b5430e5be8c8b51f5724
parente07cccf4046978df10f2e13fe2b99b2f9b3a65db (diff)
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>
-rw-r--r--fs/namei.c22
-rw-r--r--security/integrity/ima/ima_main.c6
2 files changed, 20 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index f3c5b278895..1f13751693a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -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.
*/
if (IS_APPEND(inode)) {
+ error = -EPERM;
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
- return -EPERM;
+ goto err_out;
if (flag & O_TRUNC)
- return -EPERM;
+ goto err_out;
}
/* O_NOATIME can only be set by the owner or superuser */
if (flag & O_NOATIME)
- if (!is_owner_or_cap(inode))
- return -EPERM;
+ if (!is_owner_or_cap(inode)) {
+ error = -EPERM;
+ goto err_out;
+ }
/*
* Ensure there are no outstanding leases on the file.
*/
error = break_lease(inode, flag);
if (error)
- return error;
+ goto err_out;
if (flag & O_TRUNC) {
error = get_write_access(inode);
if (error)
- return error;
+ goto err_out;
/*
* 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);
if (error)
- return error;
+ goto err_out;
} else
if (flag & FMODE_WRITE)
vfs_dq_init(inode);
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;
}
/*
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 4732f5e5d12..b85e61bcf24 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -249,7 +249,11 @@ void ima_counts_put(struct path *path, int mask)
struct inode *inode = path->dentry->d_inode;
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;
iint = ima_iint_find_insert_get(inode);
if (!iint)