]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fanotify: update connector fsid cache on add mark
authorAmir Goldstein <amir73il@gmail.com>
Wed, 19 Jun 2019 10:34:44 +0000 (13:34 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2019 11:13:44 +0000 (13:13 +0200)
commit c285a2f01d692ef48d7243cf1072897bbd237407 upstream.

When implementing connector fsid cache, we only initialized the cache
when the first mark added to object was added by FAN_REPORT_FID group.
We forgot to update conn->fsid when the second mark is added by
FAN_REPORT_FID group to an already attached connector without fsid
cache.

Reported-and-tested-by: syzbot+c277e8e2f46414645508@syzkaller.appspotmail.com
Fixes: 77115225acc6 ("fanotify: cache fsid in fsnotify_mark_connector")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/notify/fanotify/fanotify.c
fs/notify/mark.c
include/linux/fsnotify_backend.h

index 63c6bb1f8c4dac2ed4025f070ca349ab1bc8c973..8c286f8228e5bc802a059716d08ed98f42e6c98e 100644 (file)
@@ -355,6 +355,10 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
                /* Mark is just getting destroyed or created? */
                if (!conn)
                        continue;
+               if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID))
+                       continue;
+               /* Pairs with smp_wmb() in fsnotify_add_mark_list() */
+               smp_rmb();
                fsid = conn->fsid;
                if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
                        continue;
index 22acb0a79b532eb7541e3f90a1b4753acd733518..e9d49191d39e14cb041aa2761a3d4081c5ebf35e 100644 (file)
@@ -495,10 +495,13 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
        conn->type = type;
        conn->obj = connp;
        /* Cache fsid of filesystem containing the object */
-       if (fsid)
+       if (fsid) {
                conn->fsid = *fsid;
-       else
+               conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID;
+       } else {
                conn->fsid.val[0] = conn->fsid.val[1] = 0;
+               conn->flags = 0;
+       }
        if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
                inode = igrab(fsnotify_conn_inode(conn));
        /*
@@ -573,7 +576,12 @@ restart:
                if (err)
                        return err;
                goto restart;
-       } else if (fsid && (conn->fsid.val[0] || conn->fsid.val[1]) &&
+       } else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) {
+               conn->fsid = *fsid;
+               /* Pairs with smp_rmb() in fanotify_get_fsid() */
+               smp_wmb();
+               conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID;
+       } else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) &&
                   (fsid->val[0] != conn->fsid.val[0] ||
                    fsid->val[1] != conn->fsid.val[1])) {
                /*
index 094b38f2d9a159596413f04e49a10940d628386c..0f67cabbbec815ccce2313ccb7d0ccffad27a565 100644 (file)
@@ -292,7 +292,9 @@ typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t;
  */
 struct fsnotify_mark_connector {
        spinlock_t lock;
-       unsigned int type;      /* Type of object [lock] */
+       unsigned short type;    /* Type of object [lock] */
+#define FSNOTIFY_CONN_FLAG_HAS_FSID    0x01
+       unsigned short flags;   /* flags [lock] */
        __kernel_fsid_t fsid;   /* fsid of filesystem containing object */
        union {
                /* Object pointer [lock] */