[PATCH 5.8 007/124] exfat: fix use of uninitialized spinlock on error path

From: Greg Kroah-Hartman
Date: Mon Oct 12 2020 - 09:55:23 EST


From: Namjae Jeon <namjae.jeon@xxxxxxxxxxx>

commit 8ff006e57ad3a25f909c456d053aa498b6673a39 upstream.

syzbot reported warning message:

Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x1d6/0x29e lib/dump_stack.c:118
register_lock_class+0xf06/0x1520 kernel/locking/lockdep.c:893
__lock_acquire+0xfd/0x2ae0 kernel/locking/lockdep.c:4320
lock_acquire+0x148/0x720 kernel/locking/lockdep.c:5029
__raw_spin_lock include/linux/spinlock_api_smp.h:142 [inline]
_raw_spin_lock+0x2a/0x40 kernel/locking/spinlock.c:151
spin_lock include/linux/spinlock.h:354 [inline]
exfat_cache_inval_inode+0x30/0x280 fs/exfat/cache.c:226
exfat_evict_inode+0x124/0x270 fs/exfat/inode.c:660
evict+0x2bb/0x6d0 fs/inode.c:576
exfat_fill_super+0x1e07/0x27d0 fs/exfat/super.c:681
get_tree_bdev+0x3e9/0x5f0 fs/super.c:1342
vfs_get_tree+0x88/0x270 fs/super.c:1547
do_new_mount fs/namespace.c:2875 [inline]
path_mount+0x179d/0x29e0 fs/namespace.c:3192
do_mount fs/namespace.c:3205 [inline]
__do_sys_mount fs/namespace.c:3413 [inline]
__se_sys_mount+0x126/0x180 fs/namespace.c:3390
do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
entry_SYSCALL_64_after_hwframe+0x44/0xa9

If exfat_read_root() returns an error, spinlock is used in
exfat_evict_inode() without initialization. This patch combines
exfat_cache_init_inode() with exfat_inode_init_once() to initialize
spinlock by slab constructor.

Fixes: c35b6810c495 ("exfat: add exfat cache")
Cc: stable@xxxxxxxxxxxxxxx # v5.7+
Reported-by: syzbot <syzbot+b91107320911a26c9a95@xxxxxxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Namjae Jeon <namjae.jeon@xxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
fs/exfat/cache.c | 11 -----------
fs/exfat/exfat_fs.h | 3 ++-
fs/exfat/inode.c | 2 --
fs/exfat/super.c | 5 ++++-
4 files changed, 6 insertions(+), 15 deletions(-)

--- a/fs/exfat/cache.c
+++ b/fs/exfat/cache.c
@@ -17,7 +17,6 @@
#include "exfat_raw.h"
#include "exfat_fs.h"

-#define EXFAT_CACHE_VALID 0
#define EXFAT_MAX_CACHE 16

struct exfat_cache {
@@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
kmem_cache_destroy(exfat_cachep);
}

-void exfat_cache_init_inode(struct inode *inode)
-{
- struct exfat_inode_info *ei = EXFAT_I(inode);
-
- spin_lock_init(&ei->cache_lru_lock);
- ei->nr_caches = 0;
- ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
- INIT_LIST_HEAD(&ei->cache_lru);
-}
-
static inline struct exfat_cache *exfat_cache_alloc(void)
{
return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -250,6 +250,8 @@ struct exfat_sb_info {
struct rcu_head rcu;
};

+#define EXFAT_CACHE_VALID 0
+
/*
* EXFAT file system inode in-memory data
*/
@@ -429,7 +431,6 @@ extern const struct dentry_operations ex
/* cache.c */
int exfat_cache_init(void);
void exfat_cache_shutdown(void);
-void exfat_cache_init_inode(struct inode *inode);
void exfat_cache_inval_inode(struct inode *inode);
int exfat_get_cluster(struct inode *inode, unsigned int cluster,
unsigned int *fclus, unsigned int *dclus,
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -610,8 +610,6 @@ static int exfat_fill_inode(struct inode
ei->i_crtime = info->crtime;
inode->i_atime = info->atime;

- exfat_cache_init_inode(inode);
-
return 0;
}

--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -361,7 +361,6 @@ static int exfat_read_root(struct inode
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
current_time(inode);
exfat_truncate_atime(&inode->i_atime);
- exfat_cache_init_inode(inode);
return 0;
}

@@ -747,6 +746,10 @@ static void exfat_inode_init_once(void *
{
struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;

+ spin_lock_init(&ei->cache_lru_lock);
+ ei->nr_caches = 0;
+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
+ INIT_LIST_HEAD(&ei->cache_lru);
INIT_HLIST_NODE(&ei->i_hash_fat);
inode_init_once(&ei->vfs_inode);
}