inotify: race use after free/double free in inotify inode marks
There is a race in the inotify add/rm watch code. A task can find and remove a mark which doesn't have all of it's references. This can result in a use after free/double free situation. Task A Task B ------------ ----------- inotify_new_watch() allocate a mark (refcnt == 1) add it to the idr inotify_rm_watch() inotify_remove_from_idr() fsnotify_put_mark() refcnt hits 0, free take reference because we are on idr [at this point it is a use after free] [time goes on] refcnt may hit 0 again, double free The fix is to take the reference BEFORE the object can be found in the idr. Signed-off-by: Eric Paris <eparis@redhat.com> Cc: <stable@kernel.org>
This commit is contained in:
parent
3dbc6fb6a3
commit
e08733446e
@ -546,21 +546,24 @@ static int inotify_new_watch(struct fsnotify_group *group,
|
||||
if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
|
||||
goto out_err;
|
||||
|
||||
/* we are putting the mark on the idr, take a reference */
|
||||
fsnotify_get_mark(&tmp_ientry->fsn_entry);
|
||||
|
||||
spin_lock(&group->inotify_data.idr_lock);
|
||||
ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
|
||||
group->inotify_data.last_wd+1,
|
||||
&tmp_ientry->wd);
|
||||
spin_unlock(&group->inotify_data.idr_lock);
|
||||
if (ret) {
|
||||
/* we didn't get on the idr, drop the idr reference */
|
||||
fsnotify_put_mark(&tmp_ientry->fsn_entry);
|
||||
|
||||
/* idr was out of memory allocate and try again */
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* we put the mark on the idr, take a reference */
|
||||
fsnotify_get_mark(&tmp_ientry->fsn_entry);
|
||||
|
||||
/* we are on the idr, now get on the inode */
|
||||
ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
|
||||
if (ret) {
|
||||
|
Loading…
Reference in New Issue
Block a user