]> www.infradead.org Git - users/hch/misc.git/commitdiff
exfat: combine iocharset and utf8 option setup
authorSang-Heon Jeon <ekffu200098@gmail.com>
Fri, 26 Sep 2025 15:35:22 +0000 (00:35 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Tue, 30 Sep 2025 04:41:22 +0000 (13:41 +0900)
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>
fs/exfat/super.c

index e1cffa46eb7370969d766c8cb36e95178f9e42f9..7f9592856bf78814afebfb06823b39f749c0034a 100644 (file)
@@ -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;