diff options
author | Sang-Heon Jeon <ekffu200098@gmail.com> | 2025-09-27 00:35:22 +0900 |
---|---|---|
committer | Namjae Jeon <linkinjeon@kernel.org> | 2025-09-30 13:41:22 +0900 |
commit | 29c063658d532dfad22d4ef8aea9a494037ceab1 (patch) | |
tree | dbc43eea4a49ac853ce0cac1bd68d7190e6b5353 | |
parent | e6fd5d3a431708df8f43d970bd3ba8a70a034fd5 (diff) |
exfat: combine iocharset and utf8 option setup
Currently, exfat utf8 mount option depends on the iocharset option
value. After exfat remount, utf8 option may become inconsistent with
iocharset option.
If the options are inconsistent; (specifically, iocharset=utf8 but
utf8=0) readdir may reference uninitalized NLS, leading to a null
pointer dereference.
Extract and combine utf8/iocharset setup logic into exfat_set_iocharset().
Then Replace iocharset setup logic to exfat_set_iocharset to prevent
utf8/iocharset option inconsistentcy after remount.
Reported-by: syzbot+3e9cb93e3c5f90d28e19@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3e9cb93e3c5f90d28e19
Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Fixes: acab02ffcd6b ("exfat: support modifying mount options via remount")
Tested-by: syzbot+3e9cb93e3c5f90d28e19@syzkaller.appspotmail.com
Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
-rw-r--r-- | fs/exfat/super.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/exfat/super.c b/fs/exfat/super.c index e1cffa46eb73..7f9592856bf7 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -31,6 +31,16 @@ static void exfat_free_iocharset(struct exfat_sb_info *sbi) kfree(sbi->options.iocharset); } +static void exfat_set_iocharset(struct exfat_mount_options *opts, + char *iocharset) +{ + opts->iocharset = iocharset; + if (!strcmp(opts->iocharset, "utf8")) + opts->utf8 = 1; + else + opts->utf8 = 0; +} + static void exfat_put_super(struct super_block *sb) { struct exfat_sb_info *sbi = EXFAT_SB(sb); @@ -292,7 +302,7 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) break; case Opt_charset: exfat_free_iocharset(sbi); - opts->iocharset = param->string; + exfat_set_iocharset(opts, param->string); param->string = NULL; break; case Opt_errors: @@ -664,8 +674,8 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) /* set up enough so that it can read an inode */ exfat_hash_init(sb); - if (!strcmp(sbi->options.iocharset, "utf8")) - opts->utf8 = 1; + if (sbi->options.utf8) + set_default_d_op(sb, &exfat_utf8_dentry_ops); else { sbi->nls_io = load_nls(sbi->options.iocharset); if (!sbi->nls_io) { @@ -674,12 +684,8 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) err = -EINVAL; goto free_table; } - } - - if (sbi->options.utf8) - set_default_d_op(sb, &exfat_utf8_dentry_ops); - else set_default_d_op(sb, &exfat_dentry_ops); + } root_inode = new_inode(sb); if (!root_inode) { @@ -809,8 +815,8 @@ static int exfat_init_fs_context(struct fs_context *fc) sbi->options.fs_fmask = current->fs->umask; sbi->options.fs_dmask = current->fs->umask; sbi->options.allow_utime = -1; - sbi->options.iocharset = exfat_default_iocharset; sbi->options.errors = EXFAT_ERRORS_RO; + exfat_set_iocharset(&sbi->options, exfat_default_iocharset); fc->s_fs_info = sbi; fc->ops = &exfat_context_ops; |