fsnotify: fix UAF from FS_ERROR event on a shutting down filesystem
authorAmir Goldstein <amir73il@gmail.com>
Tue, 16 Apr 2024 18:14:52 +0000 (21:14 +0300)
committerJan Kara <jack@suse.cz>
Wed, 17 Apr 2024 13:06:50 +0000 (15:06 +0200)
Protect against use after free when filesystem calls fsnotify_sb_error()
during fs shutdown.

Move freeing of sb->s_fsnotify_info to destroy_super_work(), because it
may be accessed from fs shutdown context.

Reported-by: syzbot+5e3f9b2a67b45f16d4e6@syzkaller.appspotmail.com
Suggested-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/linux-fsdevel/20240416173211.4lnmgctyo4jn5fha@quack3/
Fixes: 07a3b8d0bf72 ("fsnotify: lazy attach fsnotify_sb_info state to sb")
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Message-Id: <20240416181452.567070-1-amir73il@gmail.com>

fs/notify/fsnotify.c
fs/super.c
include/linux/fsnotify_backend.h

index 2ae965ef37e859976a997a9d0329e2094c03002b..ff69ae24c4e891d6901aa29bb8b442cb29d526ef 100644 (file)
@@ -103,7 +103,11 @@ void fsnotify_sb_delete(struct super_block *sb)
        WARN_ON(fsnotify_sb_has_priority_watchers(sb, FSNOTIFY_PRIO_CONTENT));
        WARN_ON(fsnotify_sb_has_priority_watchers(sb,
                                                  FSNOTIFY_PRIO_PRE_CONTENT));
-       kfree(sbinfo);
+}
+
+void fsnotify_sb_free(struct super_block *sb)
+{
+       kfree(sb->s_fsnotify_info);
 }
 
 /*
index 71d9779c42b10aca8bd4e0b7b667fc62386e2305..81656c7807db88aa60c5e0db3eeee0668c18d0bd 100644 (file)
@@ -274,6 +274,7 @@ static void destroy_super_work(struct work_struct *work)
 {
        struct super_block *s = container_of(work, struct super_block,
                                                        destroy_work);
+       fsnotify_sb_free(s);
        security_sb_free(s);
        put_user_ns(s->s_user_ns);
        kfree(s->s_subtype);
index 7f1ab8264e41d3961aff09befec6c2fce46b1f5f..4dd6143db27165dfdf70d01b6e83c3a35da8f7d0 100644 (file)
@@ -576,6 +576,7 @@ extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data
 extern void __fsnotify_inode_delete(struct inode *inode);
 extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
 extern void fsnotify_sb_delete(struct super_block *sb);
+extern void fsnotify_sb_free(struct super_block *sb);
 extern u32 fsnotify_get_cookie(void);
 
 static inline __u32 fsnotify_parent_needed_mask(__u32 mask)
@@ -880,6 +881,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 static inline void fsnotify_sb_delete(struct super_block *sb)
 {}
 
+static inline void fsnotify_sb_free(struct super_block *sb)
+{}
+
 static inline void fsnotify_update_flags(struct dentry *dentry)
 {}