From 51eb207822b359a333e551e568f2dcd33643ff69 Mon Sep 17 00:00:00 2001 From: a17671 Date: Mon, 18 Jan 2021 13:51:46 +0800 Subject: [PATCH] exfat:Fix panic of handlings of unhashed alias Unhashed alias is allowed to exist In the latest upstream kernel exfat driver It does not have to generate panic in this case Porting this handling to exfat-nofuse driver from url https://git.kernel.org/pub/scm/linux/kernel/git/ stable/linux.git/tree/fs/exfat/namei.c?h=v5.10.8#n724 Panic stack trace: kernel BUG at ../../motorola/kernel/modules/fs/exfat/exfat_super.c:874! [ 759.284483] pc : exfat_lookup+0x1dc/0x1e0 [exfat] [ 759.284496] lr : exfat_lookup+0x144/0x1e0 [exfat] [ 759.284502] sp : ffffff800ea2b9d0 [ 759.284507] x29: ffffff800ea2ba20 x28: fffffff6f3cf8000 [ 759.284515] x27: 0000000000000000 x26: 0000000000000000 [ 759.284523] x25: 0000000056000000 x24: fffffff7b8742d88 [ 759.284530] x23: 0000000000004000 x22: fffffff883b08390 [ 759.284538] x21: fffffff7b874b228 x20: fffffff86d375000 [ 759.284546] x19: fffffff883b08980 x18: 0000000007270df4 [ 759.284553] x17: 0000000000000000 x16: ffffff9bebd5c9b8 [ 759.284561] x15: fffffff6f976ba00 x14: 0000000000000041 [ 759.284569] x13: ffffff9bede96590 x12: fffffff6f89f7b00 [ 759.284576] x11: 2cf70e9f45774b00 x10: 0000000000000000 [ 759.284584] x9 : 0000000000000000 x8 : 0000000000000000 [ 759.284591] x7 : ffffff9bec02e394 x6 : 0000000000000000 [ 759.284599] x5 : 0000000000000000 x4 : 0000000000000001 [ 759.284606] x3 : 0000000000000000 x2 : ffffff9bebd5ca84 [ 759.284614] x1 : 0000000000000001 x0 : fffffff883b08390 [ 759.284622] Call trace: [ 759.284636] exfat_lookup+0x1dc/0x1e0 [exfat] [ 759.284650] __lookup_slow+0x9c/0x188 [ 759.284658] walk_component+0x1d0/0x868 [ 759.284665] path_lookupat+0xb8/0x210 [ 759.284672] filename_lookup+0x98/0x1c8 [ 759.284679] user_path_at_empty+0x54/0x68 [ 759.284688] vfs_statx+0x90/0x130 [ 759.284695] __arm64_sys_newfstatat+0x40/0x80 [ 759.284704] el0_svc_common+0xa0/0x170 [ 759.284711] el0_svc_handler+0x6c/0x88 [ 759.284719] el0_svc+0x8/0xc [ 759.284728] Code: 17ffffa7 92800176 17ffffec 940018f2 (d4210000) Change-Id: I5fb26e2416f70733fe2010484740513dc9a8c5d0 Signed-off-by: a17671 Reviewed-on: https://gerrit.mot.com/1853335 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Xiangpo Zhao Submit-Approved: Jira Key --- fs/exfat/exfat_super.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/fs/exfat/exfat_super.c b/fs/exfat/exfat_super.c index 2d584a860744..44bb26a87b1f 100644 --- a/fs/exfat/exfat_super.c +++ b/fs/exfat/exfat_super.c @@ -870,10 +870,34 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, } alias = d_find_alias(inode); - if (alias && !exfat_d_anon_disconn(alias)) { - CHECK_ERR(d_unhashed(alias)); - if (!S_ISDIR(i_mode)) + /* + * Checking "alias->d_parent == dentry->d_parent" to make sure + * FS is not corrupted (especially double linked dir). + */ + if (alias && alias->d_parent == dentry->d_parent && + !exfat_d_anon_disconn(alias)) { + /* + * Unhashed alias is able to exist because of revalidate() + * called by lookup_fast. You can easily make this status + * by calling create and lookup concurrently + * In such case, we reuse an alias instead of dentry + */ + if (d_unhashed(alias)) { + WARN_ON(alias->d_name.hash_len != + dentry->d_name.hash_len); + DPRINTK("rehashed a dentry(%p) in read lookup",alias); + d_drop(dentry); + d_rehash(alias); + } else if (!S_ISDIR(i_mode)) { + /* + * This inode has non anonymous-DCACHE_DISCONNECTED + * dentry. This means, the user did ->lookup() by an + * another name (longname vs 8.3 alias of it) in past. + * + * Switch to new one for reason of locality if possible + */ d_move(alias, dentry); + } iput(inode); __unlock_super(sb); DPRINTK("exfat_lookup exited 1\n");