mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
exfat: move freeing sbi, upcase table and dropping nls into rcu-delayed helper
That stuff can be accessed by ->d_hash()/->d_compare(); as it is, we have a hard-to-hit UAF if rcu pathwalk manages to get into ->d_hash() on a filesystem that is in process of getting shut down. Besides, having nls and upcase table cleanup moved from ->put_super() towards the place where sbi is freed makes for simpler failure exits. Acked-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
529f89a9e4
commit
a13d1a4de3
@ -275,6 +275,7 @@ struct exfat_sb_info {
|
|||||||
|
|
||||||
spinlock_t inode_hash_lock;
|
spinlock_t inode_hash_lock;
|
||||||
struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
|
struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EXFAT_CACHE_VALID 0
|
#define EXFAT_CACHE_VALID 0
|
||||||
|
@ -655,7 +655,6 @@ static int exfat_load_upcase_table(struct super_block *sb,
|
|||||||
unsigned int sect_size = sb->s_blocksize;
|
unsigned int sect_size = sb->s_blocksize;
|
||||||
unsigned int i, index = 0;
|
unsigned int i, index = 0;
|
||||||
u32 chksum = 0;
|
u32 chksum = 0;
|
||||||
int ret;
|
|
||||||
unsigned char skip = false;
|
unsigned char skip = false;
|
||||||
unsigned short *upcase_table;
|
unsigned short *upcase_table;
|
||||||
|
|
||||||
@ -673,8 +672,7 @@ static int exfat_load_upcase_table(struct super_block *sb,
|
|||||||
if (!bh) {
|
if (!bh) {
|
||||||
exfat_err(sb, "failed to read sector(0x%llx)",
|
exfat_err(sb, "failed to read sector(0x%llx)",
|
||||||
(unsigned long long)sector);
|
(unsigned long long)sector);
|
||||||
ret = -EIO;
|
return -EIO;
|
||||||
goto free_table;
|
|
||||||
}
|
}
|
||||||
sector++;
|
sector++;
|
||||||
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
|
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
|
||||||
@ -701,15 +699,12 @@ static int exfat_load_upcase_table(struct super_block *sb,
|
|||||||
|
|
||||||
exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
|
exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
|
||||||
index, chksum, utbl_checksum);
|
index, chksum, utbl_checksum);
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
free_table:
|
|
||||||
exfat_free_upcase_table(sbi);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exfat_load_default_upcase_table(struct super_block *sb)
|
static int exfat_load_default_upcase_table(struct super_block *sb)
|
||||||
{
|
{
|
||||||
int i, ret = -EIO;
|
int i;
|
||||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||||
unsigned char skip = false;
|
unsigned char skip = false;
|
||||||
unsigned short uni = 0, *upcase_table;
|
unsigned short uni = 0, *upcase_table;
|
||||||
@ -740,8 +735,7 @@ static int exfat_load_default_upcase_table(struct super_block *sb)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* FATAL error: default upcase table has error */
|
/* FATAL error: default upcase table has error */
|
||||||
exfat_free_upcase_table(sbi);
|
return -EIO;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int exfat_create_upcase_table(struct super_block *sb)
|
int exfat_create_upcase_table(struct super_block *sb)
|
||||||
|
@ -39,9 +39,6 @@ static void exfat_put_super(struct super_block *sb)
|
|||||||
exfat_free_bitmap(sbi);
|
exfat_free_bitmap(sbi);
|
||||||
brelse(sbi->boot_bh);
|
brelse(sbi->boot_bh);
|
||||||
mutex_unlock(&sbi->s_lock);
|
mutex_unlock(&sbi->s_lock);
|
||||||
|
|
||||||
unload_nls(sbi->nls_io);
|
|
||||||
exfat_free_upcase_table(sbi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exfat_sync_fs(struct super_block *sb, int wait)
|
static int exfat_sync_fs(struct super_block *sb, int wait)
|
||||||
@ -600,7 +597,7 @@ static int __exfat_fill_super(struct super_block *sb)
|
|||||||
ret = exfat_load_bitmap(sb);
|
ret = exfat_load_bitmap(sb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
exfat_err(sb, "failed to load alloc-bitmap");
|
exfat_err(sb, "failed to load alloc-bitmap");
|
||||||
goto free_upcase_table;
|
goto free_bh;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = exfat_count_used_clusters(sb, &sbi->used_clusters);
|
ret = exfat_count_used_clusters(sb, &sbi->used_clusters);
|
||||||
@ -613,8 +610,6 @@ static int __exfat_fill_super(struct super_block *sb)
|
|||||||
|
|
||||||
free_alloc_bitmap:
|
free_alloc_bitmap:
|
||||||
exfat_free_bitmap(sbi);
|
exfat_free_bitmap(sbi);
|
||||||
free_upcase_table:
|
|
||||||
exfat_free_upcase_table(sbi);
|
|
||||||
free_bh:
|
free_bh:
|
||||||
brelse(sbi->boot_bh);
|
brelse(sbi->boot_bh);
|
||||||
return ret;
|
return ret;
|
||||||
@ -701,12 +696,10 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||||||
sb->s_root = NULL;
|
sb->s_root = NULL;
|
||||||
|
|
||||||
free_table:
|
free_table:
|
||||||
exfat_free_upcase_table(sbi);
|
|
||||||
exfat_free_bitmap(sbi);
|
exfat_free_bitmap(sbi);
|
||||||
brelse(sbi->boot_bh);
|
brelse(sbi->boot_bh);
|
||||||
|
|
||||||
check_nls_io:
|
check_nls_io:
|
||||||
unload_nls(sbi->nls_io);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,13 +764,22 @@ static int exfat_init_fs_context(struct fs_context *fc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void delayed_free(struct rcu_head *p)
|
||||||
|
{
|
||||||
|
struct exfat_sb_info *sbi = container_of(p, struct exfat_sb_info, rcu);
|
||||||
|
|
||||||
|
unload_nls(sbi->nls_io);
|
||||||
|
exfat_free_upcase_table(sbi);
|
||||||
|
exfat_free_sbi(sbi);
|
||||||
|
}
|
||||||
|
|
||||||
static void exfat_kill_sb(struct super_block *sb)
|
static void exfat_kill_sb(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct exfat_sb_info *sbi = sb->s_fs_info;
|
struct exfat_sb_info *sbi = sb->s_fs_info;
|
||||||
|
|
||||||
kill_block_super(sb);
|
kill_block_super(sb);
|
||||||
if (sbi)
|
if (sbi)
|
||||||
exfat_free_sbi(sbi);
|
call_rcu(&sbi->rcu, delayed_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file_system_type exfat_fs_type = {
|
static struct file_system_type exfat_fs_type = {
|
||||||
|
Loading…
Reference in New Issue
Block a user