diff options
author | Tianjia Zhang <tianjia.zhang@linux.alibaba.com> | 2023-06-01 14:42:44 +0800 |
---|---|---|
committer | Mimi Zohar <zohar@linux.ibm.com> | 2023-06-01 07:25:04 -0400 |
commit | 9df6a4870dc371136e90330cfbbc51464ee66993 (patch) | |
tree | 7dd5e36322665b0ce299910dcea5758df8b32dc7 /security | |
parent | db1d1e8b9867aae5c3e61ad7859abfcc4a6fd6c7 (diff) | |
download | lwn-9df6a4870dc371136e90330cfbbc51464ee66993.tar.gz lwn-9df6a4870dc371136e90330cfbbc51464ee66993.zip |
integrity: Fix possible multiple allocation in integrity_inode_get()
When integrity_inode_get() is querying and inserting the cache, there
is a conditional race in the concurrent environment.
The race condition is the result of not properly implementing
"double-checked locking". In this case, it first checks to see if the
iint cache record exists before taking the lock, but doesn't check
again after taking the integrity_iint_lock.
Fixes: bf2276d10ce5 ("ima: allocating iint improvements")
Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
Cc: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
Cc: <stable@vger.kernel.org> # v3.10+
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/iint.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index c73858e8c6d5..a462df827de2 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -43,12 +43,10 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode) else if (inode > iint->inode) n = n->rb_right; else - break; + return iint; } - if (!n) - return NULL; - return iint; + return NULL; } /* @@ -113,10 +111,15 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) parent = *p; test_iint = rb_entry(parent, struct integrity_iint_cache, rb_node); - if (inode < test_iint->inode) + if (inode < test_iint->inode) { p = &(*p)->rb_left; - else + } else if (inode > test_iint->inode) { p = &(*p)->rb_right; + } else { + write_unlock(&integrity_iint_lock); + kmem_cache_free(iint_cache, iint); + return test_iint; + } } iint->inode = inode; |