Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp1172902pxb; Fri, 20 Nov 2020 03:07:05 -0800 (PST) X-Google-Smtp-Source: ABdhPJxHMzFPRE/jbFCYTHgJoLuh3IhCYSmAfcs6utlqWgKWEIj9HrAwj53qyVCHsBthvxLDtwpf X-Received: by 2002:a17:906:f744:: with SMTP id jp4mr33245477ejb.122.1605870425482; Fri, 20 Nov 2020 03:07:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605870425; cv=none; d=google.com; s=arc-20160816; b=incn5pBNHbJiUJCvj59nR0t2yn3GIB0AzY+IJ/HMhkfMyPq1BCfN+UzeCI21JY3zWg /ikeV60Ahwezupa+SGga0kzXmhhqTgjVrISXrdW9oqbpffUXLTeaLDR8pM9p3HfFHHxv aRDVqTTQhvDdPGoW8oHIjiosAKO3ymUMhqYsn4F1ZiaU4SOTI2EMmlORvU0IKDGGgwdj ZLEWBPrSOSM1/UznbLtg+EIQlUPtW5W/Jm2oU4Es/aaNhKLd2jLlraawY7w2CgpWltph 4RplpFgymVAzLpYORwX1YPerfy6uha3tVoXyDGxyyyOyyb67WrF5Lp7I1zFlQHSNPygu Dlrw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=2aMSdNWB99aqzXkFNyhzhW20HVdw8Tt9EJyuW8iMHho=; b=cf9hKdnVPcp+dLE1JghicEnU9brC6Q0ZZiPDFHwUn5WQCQzSZsJ20hXRAPzm/Rvh8G A2vCJcNFiBm7u2U3zq3MJWKC8ye7nqGZwsZNnykaFUzPtILLDeBGcfebA8cXN25dC7ZT NNHX/VVSYQfQniKaoYDMeMXK5bjq+QXvYrahLnbHsq+xYE+4fVO46KXkT7OzJs1E22Ep ZckQ2qF/A2CiWjcs6w+06j4lhxWRVaN2GB62XORCBMYLQbP/2Ri3jMOkTVOMOV6Qxhlr eDYcZN3LurJ/NN4uscO11iVIkA1iITW0s0ZV2uvPietHIR3VnXcX9TqT6025KltIxu/G HnXA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=FkqqjdWc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y14si1582809eds.56.2020.11.20.03.06.42; Fri, 20 Nov 2020 03:07:05 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=FkqqjdWc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727777AbgKTLDs (ORCPT + 99 others); Fri, 20 Nov 2020 06:03:48 -0500 Received: from mail.kernel.org ([198.145.29.99]:50870 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727741AbgKTLDq (ORCPT ); Fri, 20 Nov 2020 06:03:46 -0500 Received: from localhost (83-86-74-64.cable.dynamic.v4.ziggo.nl [83.86.74.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 1022D2222F; Fri, 20 Nov 2020 11:03:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1605870225; bh=1Tg5jzgwoZxwmccl1AopzA5gfyHglXxx/I52qH2SzAE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FkqqjdWc2LHdEK47f/dRDNCxHUVOtBNShp5GvCE/vAnTqeDVhb52da5U5k/p9ixBb 67pYX+pLSrgrWVNJkWQ6vcFz+PbKzYG9SKjhHxu6oMbYBSO1ySvhnGiNr53Yw6w4kC kWg4y6Rr8QE2KJpLVx+gh1ktxb+QokN0ycxhdaUo= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dave Chinner , Carlos Maiolino , "Darrick J. Wong" , Sudip Mukherjee Subject: [PATCH 4.4 10/15] xfs: catch inode allocation state mismatch corruption Date: Fri, 20 Nov 2020 12:03:08 +0100 Message-Id: <20201120104540.065893304@linuxfoundation.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201120104539.534424264@linuxfoundation.org> References: <20201120104539.534424264@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Dave Chinner commit ee457001ed6c6f31ddad69c24c1da8f377d8472d upstream We recently came across a V4 filesystem causing memory corruption due to a newly allocated inode being setup twice and being added to the superblock inode list twice. From code inspection, the only way this could happen is if a newly allocated inode was not marked as free on disk (i.e. di_mode wasn't zero). Running the metadump on an upstream debug kernel fails during inode allocation like so: XFS: Assertion failed: ip->i_d.di_nblocks == 0, file: fs/xfs/xfs_inod= e.c, line: 838 ------------[ cut here ]------------ kernel BUG at fs/xfs/xfs_message.c:114! invalid opcode: 0000 [#1] PREEMPT SMP CPU: 11 PID: 3496 Comm: mkdir Not tainted 4.16.0-rc5-dgc #442 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/0= 1/2014 RIP: 0010:assfail+0x28/0x30 RSP: 0018:ffffc9000236fc80 EFLAGS: 00010202 RAX: 00000000ffffffea RBX: 0000000000004000 RCX: 0000000000000000 RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffff8227211b RBP: ffffc9000236fce8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000bec R11: f000000000000000 R12: ffffc9000236fd30 R13: ffff8805c76bab80 R14: ffff8805c77ac800 R15: ffff88083fb12e10 FS: 00007fac8cbff040(0000) GS:ffff88083fd00000(0000) knlGS:0000000000000= 000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fffa6783ff8 CR3: 00000005c6e2b003 CR4: 00000000000606e0 Call Trace: xfs_ialloc+0x383/0x570 xfs_dir_ialloc+0x6a/0x2a0 xfs_create+0x412/0x670 xfs_generic_create+0x1f7/0x2c0 ? capable_wrt_inode_uidgid+0x3f/0x50 vfs_mkdir+0xfb/0x1b0 SyS_mkdir+0xcf/0xf0 do_syscall_64+0x73/0x1a0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Extracting the inode number we crashed on from an event trace and looking at it with xfs_db: xfs_db> inode 184452204 xfs_db> p core.magic = 0x494e core.mode = 0100644 core.version = 2 core.format = 2 (extents) core.nlinkv2 = 1 core.onlink = 0 ..... Confirms that it is not a free inode on disk. xfs_repair also trips over this inode: ..... zero length extent (off = 0, fsbno = 0) in ino 184452204 correcting nextents for inode 184452204 bad attribute fork in inode 184452204, would clear attr fork bad nblocks 1 for inode 184452204, would reset to 0 bad anextents 1 for inode 184452204, would reset to 0 imap claims in-use inode 184452204 is free, would correct imap would have cleared inode 184452204 ..... disconnected inode 184452204, would move to lost+found And so we have a situation where the directory structure and the inobt thinks the inode is free, but the inode on disk thinks it is still in use. Where this corruption came from is not possible to diagnose, but we can detect it and prevent the kernel from oopsing on lookup. The reproducer now results in: $ sudo mkdir /mnt/scratch/{0,1,2,3,4,5}{0,1,2,3,4,5} mkdir: cannot create directory =E2=80=98/mnt/scratch/00=E2=80=99: File ex= ists mkdir: cannot create directory =E2=80=98/mnt/scratch/01=E2=80=99: File ex= ists mkdir: cannot create directory =E2=80=98/mnt/scratch/03=E2=80=99: Structu= re needs cleaning mkdir: cannot create directory =E2=80=98/mnt/scratch/04=E2=80=99: Input/o= utput error mkdir: cannot create directory =E2=80=98/mnt/scratch/05=E2=80=99: Input/o= utput error .... And this corruption shutdown: [ 54.843517] XFS (loop0): Corruption detected! Free inode 0xafe846c not= marked free on disk [ 54.845885] XFS (loop0): Internal error xfs_trans_cancel at line 1023 = of file fs/xfs/xfs_trans.c. Caller xfs_create+0x425/0x670 [ 54.848994] CPU: 10 PID: 3541 Comm: mkdir Not tainted 4.16.0-rc5-dgc #= 443 [ 54.850753] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIO= S 1.10.2-1 04/01/2014 [ 54.852859] Call Trace: [ 54.853531] dump_stack+0x85/0xc5 [ 54.854385] xfs_trans_cancel+0x197/0x1c0 [ 54.855421] xfs_create+0x425/0x670 [ 54.856314] xfs_generic_create+0x1f7/0x2c0 [ 54.857390] ? capable_wrt_inode_uidgid+0x3f/0x50 [ 54.858586] vfs_mkdir+0xfb/0x1b0 [ 54.859458] SyS_mkdir+0xcf/0xf0 [ 54.860254] do_syscall_64+0x73/0x1a0 [ 54.861193] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 54.862492] RIP: 0033:0x7fb73bddf547 [ 54.863358] RSP: 002b:00007ffdaa553338 EFLAGS: 00000246 ORIG_RAX: 0000= 000000000053 [ 54.865133] RAX: ffffffffffffffda RBX: 00007ffdaa55449a RCX: 00007fb73= bddf547 [ 54.866766] RDX: 0000000000000001 RSI: 00000000000001ff RDI: 00007ffda= a55449a [ 54.868432] RBP: 00007ffdaa55449a R08: 00000000000001ff R09: 00005623a= 8670dd0 [ 54.870110] R10: 00007fb73be72d5b R11: 0000000000000246 R12: 000000000= 00001ff [ 54.871752] R13: 00007ffdaa5534b0 R14: 0000000000000000 R15: 00007ffda= a553500 [ 54.873429] XFS (loop0): xfs_do_force_shutdown(0x8) called from line 1= 024 of file fs/xfs/xfs_trans.c. Return address = ffffffff814cd050 [ 54.882790] XFS (loop0): Corruption of in-memory data detected. Shutt= ing down filesystem [ 54.884597] XFS (loop0): Please umount the filesystem and rectify the = problem(s) Note that this crash is only possible on v4 filesystemsi or v5 filesystems mounted with the ikeep mount option. For all other V5 filesystems, this problem cannot occur because we don't read inodes we are allocating from disk - we simply overwrite them with the new inode information. Signed-Off-By: Dave Chinner Reviewed-by: Carlos Maiolino Tested-by: Carlos Maiolino Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong [sudip: use ip->i_d.di_mode instead of VFS_I(ip)->i_mode] Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_icache.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -298,7 +298,28 @@ xfs_iget_cache_miss( trace_xfs_iget_miss(ip); - if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) { + + /* + * If we are allocating a new inode, then check what was returned is + * actually a free, empty inode. If we are not allocating an inode, + * the check we didn't find a free inode. + */ + if (flags & XFS_IGET_CREATE) { + if (ip->i_d.di_mode != 0) { + xfs_warn(mp, +"Corruption detected! Free inode 0x%llx not marked free on disk", + ino); + error = -EFSCORRUPTED; + goto out_destroy; + } + if (ip->i_d.di_nblocks != 0) { + xfs_warn(mp, +"Corruption detected! Free inode 0x%llx has blocks allocated!", + ino); + error = -EFSCORRUPTED; + goto out_destroy; + } + } else if (ip->i_d.di_mode == 0) { error = -ENOENT; goto out_destroy; }