]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fanotify: fix false positive on permission events
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 10 Apr 2026 14:49:47 +0000 (16:49 +0200)
committerJan Kara <jack@suse.cz>
Thu, 16 Apr 2026 11:31:04 +0000 (13:31 +0200)
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: abc77577a669 ("fsnotify: Provide framework for dropping SRCU lock in ->handle_event")
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Link: https://patch.msgid.link/20260410144950.156160-1-mszeredi@redhat.com
Signed-off-by: Jan Kara <jack@suse.cz>
fs/notify/fsnotify.c
fs/notify/mark.c
include/linux/fsnotify_backend.h

index 9995de1710e59696ef708763488e739a2428ef4f..b646a861a84c64c94b13e8c8342224db9f13a7aa 100644 (file)
@@ -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;
 
index c2ed5b11b0fe63de9a148fe5f4b5891d930f038d..622f05977f86ac22dff879f180c0d0e787296461 100644 (file)
@@ -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])) {
-                       __release(&fsnotify_mark_srcu);
-                       goto fail;
+               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.
         */
index 95985400d3d8e2bcfe84387a13b01a1769112e44..e5cde39d6e85d6c2310283cea7073a8bfe3851e7 100644 (file)
@@ -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);