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>
This commit is contained in:
Helen Koike
2026-03-11 10:57:52 -05:00
committed by Dave Kleikamp
parent b15e431063
commit ca5848ae87
3 changed files with 24 additions and 9 deletions
+7 -9
View File
@@ -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);
}
}
+7
View File
@@ -402,6 +402,13 @@ struct jfs_log {
int no_integrity; /* 3: flag to disable journaling to disk */
};
/*
* 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
*/
+10
View File
@@ -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"
@@ -57,6 +58,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)
*/
@@ -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