diff options
| author | Helen Koike <koike@igalia.com> | 2026-02-27 15:11:50 -0300 |
|---|---|---|
| committer | Dave Kleikamp <dave.kleikamp@oracle.com> | 2026-03-11 10:57:52 -0500 |
| commit | ca5848ae87d24886a7886f5a22278bd4045c15f8 (patch) | |
| tree | 2febb79e7e3857fe928feed921cdd5777ba3a07a /fs/jfs | |
| parent | b15e4310633f90072d66cc9b6692acbf6b4d7d00 (diff) | |
| download | linux-next-ca5848ae87d24886a7886f5a22278bd4045c15f8.tar.gz linux-next-ca5848ae87d24886a7886f5a22278bd4045c15f8.zip | |
jfs: hold LOG_LOCK on umount to avoid null-ptr-deref
write_special_inodes() function iterate through the log->sb_list and
access the sbi fields, which can be set to NULL concurrently by umount.
Fix concurrency issue by holding LOG_LOCK and checking for NULL.
Reported-by: syzbot+e14b1036481911ae4d77@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e14b1036481911ae4d77
Signed-off-by: Helen Koike <koike@igalia.com>
Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
Diffstat (limited to 'fs/jfs')
| -rw-r--r-- | fs/jfs/jfs_logmgr.c | 16 | ||||
| -rw-r--r-- | fs/jfs/jfs_logmgr.h | 7 | ||||
| -rw-r--r-- | fs/jfs/jfs_umount.c | 10 |
3 files changed, 24 insertions, 9 deletions
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 472b6500e817..306165e61438 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; static DEFINE_SPINLOCK(log_redrive_lock); -/* - * log read/write serialization (per log) - */ -#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) -#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) -#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) /* @@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, struct jfs_sb_info *sbi; list_for_each_entry(sbi, &log->sb_list, log_list) { - writer(sbi->ipbmap->i_mapping); - writer(sbi->ipimap->i_mapping); - writer(sbi->direct_inode->i_mapping); + /* These pointers can be NULL before list_del during umount */ + if (sbi->ipbmap) + writer(sbi->ipbmap->i_mapping); + if (sbi->ipimap) + writer(sbi->ipimap->i_mapping); + if (sbi->direct_inode) + writer(sbi->direct_inode->i_mapping); } } diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 8b8994e48cd0..09e0ef6aecce 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -403,6 +403,13 @@ struct jfs_log { }; /* + * log read/write serialization (per log) + */ +#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) + +/* * Log flag */ #define log_INLINELOG 1 diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index 8ec43f53f686..18569f1eaabd 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c @@ -20,6 +20,7 @@ #include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_imap.h" +#include "jfs_logmgr.h" #include "jfs_metapage.h" #include "jfs_debug.h" @@ -58,6 +59,12 @@ int jfs_umount(struct super_block *sb) jfs_flush_journal(log, 2); /* + * Hold log lock so write_special_inodes (lmLogSync) cannot see + * this sbi with a NULL inode pointer while iterating log->sb_list. + */ + if (log) + LOG_LOCK(log); + /* * close fileset inode allocation map (aka fileset inode) */ diUnmount(ipimap, 0); @@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) */ filemap_write_and_wait(sbi->direct_inode->i_mapping); + if (log) + LOG_UNLOCK(log); + /* * ensure all file system file pages are propagated to their * home blocks on disk (and their in-memory buffer pages are |
