Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75fe2b26 authored by Eric Paris's avatar Eric Paris
Browse files

inotify: do not leak inode marks in inotify_add_watch



inotify_add_watch had a couple of problems.  The biggest being that if
inotify_add_watch was called on the same inode twice (to update or change the
event mask) a refence was taken on the original inode mark by
fsnotify_find_mark_entry but was not being dropped at the end of the
inotify_add_watch call.  Thus if inotify_rm_watch was called although the mark
was removed from the inode, the refcnt wouldn't hit zero and we would leak
memory.

Reported-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarEric Paris <eparis@redhat.com>
parent 5549f7cd
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -463,9 +463,6 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
			goto out_err;

		spin_lock(&group->inotify_data.idr_lock);
		/* if entry is added to the idr we keep the reference obtained
		 * through fsnotify_mark_add.  remember to drop this reference
		 * when entry is removed from idr */
		ret = idr_get_new_above(&group->inotify_data.idr, entry,
					++group->inotify_data.last_wd,
					&ientry->wd);
@@ -476,8 +473,13 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
			goto out_err;
		}
		atomic_inc(&group->inotify_data.user->inotify_watches);

		/* we put the mark on the idr, take a reference */
		fsnotify_get_mark(entry);
	}

	ret = ientry->wd;

	spin_lock(&entry->lock);

	old_mask = entry->mask;
@@ -508,7 +510,11 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
			fsnotify_recalc_group_mask(group);
	}

	return ientry->wd;
	/* this either matches fsnotify_find_mark_entry, or init_mark_entry
	 * depending on which path we took... */
	fsnotify_put_mark(entry);

	return ret;

out_err:
	/* see this isn't supposed to happen, just kill the watch */