Commit 7746e3bd authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Jan Kara
Browse files

fanotify: fix false positive on permission events



fsnotify_get_mark_safe() may return false for a mark on an unrelated group,
which results in bypassing the permission check.

Fix by skipping over detached marks that are not in the current group.

CC: stable@vger.kernel.org
Fixes: abc77577 ("fsnotify: Provide framework for dropping SRCU lock in ->handle_event")
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Link: https://patch.msgid.link/20260410144950.156160-1-mszeredi@redhat.com


Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 1d51b370
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -388,7 +388,7 @@ static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector
	return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
}

static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
{
	struct hlist_node *node = NULL;

+11 −7
Original line number Diff line number Diff line
@@ -457,9 +457,6 @@ EXPORT_SYMBOL_GPL(fsnotify_put_mark);
 */
static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
{
	if (!mark)
		return true;

	if (refcount_inc_not_zero(&mark->refcnt)) {
		spin_lock(&mark->lock);
		if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
@@ -500,15 +497,22 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
	int type;

	fsnotify_foreach_iter_type(type) {
		struct fsnotify_mark *mark = iter_info->marks[type];

		/* This can fail if mark is being removed */
		if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
		while (mark && !fsnotify_get_mark_safe(mark)) {
			if (mark->group == iter_info->current_group) {
				__release(&fsnotify_mark_srcu);
				goto fail;
			}
			/* This is a mark in an unrelated group, skip */
			mark = fsnotify_next_mark(mark);
			iter_info->marks[type] = mark;
		}
	}

	/*
	 * Now that both marks are pinned by refcount in the inode / vfsmount
	 * Now that all marks are pinned by refcount in the inode / vfsmount / etc
	 * lists, we can drop SRCU lock, and safely resume the list iteration
	 * once userspace returns.
	 */
+1 −0
Original line number Diff line number Diff line
@@ -915,6 +915,7 @@ extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
					  unsigned int obj_type);
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark);
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);