From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f46.google.com (mail-pj1-f46.google.com [209.85.216.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 175253A16BD for ; Tue, 7 Jul 2026 19:02:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.46 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783450946; cv=none; b=L4osZ5yd3Piuk2RDGjH/W3cEAB4ZGlHjYlynk2qVL/unCE5qzcdghDVTQ7S8TroT3rH4+PyMlQ8muhXx2swboGb60VlDwewGC3KtKeIeA/T3L7Al6+ufv+/MWxT9a2rmZnKbJ7pNHCjAMCEeECK3pZJUY+YMRSBZ7Y+fphRfqIA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783450946; c=relaxed/simple; bh=QYUa20pIZh2wxiF+T5Z9fR8QFbYCIIP9R0h4qS+mLH4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XaE5I2jePWSZj7YKiS4hITe7vGiKklxvyYst1/q0TGCXMTydoXEikhKM/jsJyXV9+UV8Qcjv6E/nkSuh1EaZNjjczjUW/SVsA2JoX2NY53sfuwtZE6yiJxHQcKunP0f/vCYodt9Yp93zW96b58Yz0mPX4nzHoQw9SyxQ2wBqPBo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fQDRSxRh; arc=none smtp.client-ip=209.85.216.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fQDRSxRh" Received: by mail-pj1-f46.google.com with SMTP id 98e67ed59e1d1-3856d6fbcb3so2382487a91.2 for ; Tue, 07 Jul 2026 12:02:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783450944; x=1784055744; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fcqVoGIOsqHneznya0CjxdKSZ/9QYnIEWsldQdbwafY=; b=fQDRSxRhhfDQnouWeQJB+pOAunF2MMAq1smVgQ0SfCJcK6XKgimna0ccpnzeAu69f6 NjlxmNqpvPM7aB3mpPMx2lQm7D2w4JsbzCQMDXgZ7otZUIt8/8BI5cN6ng6fpm22DTc5 766TTwco4QdtCBDUxoKMgIzX17+v4SfqQSgnNs69ky8UP9tY2M8T8yR1LYoAoKh6rI3I jzNFeLGQG2Fk53aBX5kYTA3y/oDCBJ0EArAzANIImE2DZPI72e/egOzBUeUducmlXASf /3doIdqOSj3Iz6jpYH1ocD2wTd4R5+3nGW0dCA1T8A0xKOclgaVVxCdFX82yD5JCDchV SHDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783450944; x=1784055744; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=fcqVoGIOsqHneznya0CjxdKSZ/9QYnIEWsldQdbwafY=; b=osmwzZ1qthaZEfbW3twLPlyDVZ53Wk7++WatJuyFJjjBcasFlWo3xOw3e3u5cnoeSS WMVn19R+TLbtCHO7yLb59kNGt1C+OaZtv4VecU+ZJ4b/YTpvv24z2uH27oLhhQaDUT93 R8Z9b2B5LFJ1S9qX3mVoRSevWsKGSpRW8qNCpGtZlAOvmpaaElDhOnCUJ7SyX61UAjUa iaAxuUzxLk3Mw/YG6hK7cHyTcO3iARWS3RYRthpd/38QsikECRbvbqOJAyPsXu4R9w0k 8ezuFMoP4hNLhUx1bxtbe7g93+NjynGpNUPoz2UsxpGcNL2FyEnwaa+YVI3wftnSgyPV ITgw== X-Forwarded-Encrypted: i=1; AHgh+RrZDfpoN4G48Uv/+Ir4ubTy1rn5+L3cmnznyqLND4D/cWeIUoW4S4nXE6vF0rHfnjgdDv3hGQmhBieCj1M=@vger.kernel.org X-Gm-Message-State: AOJu0YyIW5G76g0QknobapfOv63wrVDMbDN/6fk5iY2Q22UQgnA8otAo ZOGS08VD00JxCKbSLHp/l33zqUWa5KMv9qGo/yq57pQERs3Wddvit7jL X-Gm-Gg: AfdE7cnyN1GrqkymtceSgzkNks20w2fK/xzT91IUP92+XSUnILP90dmKeHMysHfVVYD wfvBSc5/rD2sQNzCTLbA9spBUK+6bejkCKIGD/RNJ/mzE0+rkCeYp3LnHkaKQODrnntIPa4r0Go wWKkP6KTBYWOkJFw6DZOfRototclFn3COCIhokEKOWZrignR1qpZHYPZRVjiVSV2OCGL3ZN0DVa GCDgUOB/ExA24itom7TkqrpF842ol9O38bbAEMoArkcddb4f4L3EFB99sFp0eYRbwIQBiDJTXeF HJfyjFzVu+Td3fhcnRNdikKmLfb26GduHUR8/xI4PpNoGK8FeCic5fgQFMxKVVj1g34m1POfD0h fHptBdXDl9e22Qe/MJW57QxUBxSz2zxEcjypVQQH+JJ0hkhOc7j6l2BJc6Yb9fYycA0mZcBmHa8 qsDofpeXnZltK9Ndg= X-Received: by 2002:a17:90a:c2cb:b0:380:21b7:e727 with SMTP id 98e67ed59e1d1-3875547c4cbmr7015406a91.14.1783450944395; Tue, 07 Jul 2026 12:02:24 -0700 (PDT) Received: from beelink.. ([186.22.57.86]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31174839f89sm11375916eec.10.2026.07.07.12.02.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Jul 2026 12:02:24 -0700 (PDT) From: Aldo Ariel Panzardo To: linux-xfs@vger.kernel.org, Carlos Maiolino Cc: "Darrick J . Wong" , Chandan Babu R , linux-kernel@vger.kernel.org, Aldo Ariel Panzardo , stable@vger.kernel.org Subject: [PATCH v2] xfs: bound inode fork length against the fork size during log recovery Date: Tue, 7 Jul 2026 16:02:14 -0300 Message-ID: <20260707190214.3813321-1-qwe.aldo@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260707135843.3213352-1-qwe.aldo@gmail.com> References: <20260707135843.3213352-1-qwe.aldo@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit xlog_recover_inode_commit_pass2() copies an inode log item's data/attr fork region into the inode buffer using the on-log region length without bounding it against the fork capacity, e.g.: len = item->ri_buf[2].iov_len; memcpy(XFS_DFORK_DPTR(dip), src, len); The only guard is an ASSERT, which is a no-op on production kernels (CONFIG_XFS_DEBUG off), and xfs_dinode_verify() runs only after the copy. A crafted image with a dirty log can therefore drive a heap out-of-bounds write at mount time. The XFS_ILOG_DBROOT sibling already passes XFS_DFORK_DSIZE as a bound; the DDATA/DEXT and ADATA/AEXT memcpy paths did not. Bound each logged fork region against the destination fork size before copying it, and reject the log item with -EFSCORRUPTED when it does not fit. Because the recovered inode is only verified after the fork data has been copied in, the checks are done up front, before any memcpy into the on-disk inode. Fixes: 658fa68b6f34 ("xfs: refactor log recovery inode item dispatch for pass2 commit functions") Cc: # v5.8 Signed-off-by: Aldo Ariel Panzardo --- v2: cc stable # v5.8 (per Darrick). Move both fork-length checks to the top of the fork-copy block, before any memcpy into the on-disk inode, and drop the now-redundant ASSERT. fs/xfs/xfs_inode_item_recover.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c index 169a8fe3bf0a..6c7dd7dd7032 100644 --- a/fs/xfs/xfs_inode_item_recover.c +++ b/fs/xfs/xfs_inode_item_recover.c @@ -507,6 +507,25 @@ xlog_recover_inode_commit_pass2( ASSERT(!(fields & XFS_ILOG_DFORK) || (len == xlog_calc_iovec_len(in_f->ilf_dsize))); + /* + * The recovered inode is verified only after the fork data has been + * copied into it, so bound each logged fork region against the size of + * its fork now, before the memcpy below can overrun the on-disk inode. + * The DBROOT/ABROOT cases already bound their copies against the fork + * size. + */ + if ((fields & (XFS_ILOG_DDATA | XFS_ILOG_DEXT)) && + item->ri_buf[2].iov_len > XFS_DFORK_DSIZE(dip, mp)) { + error = -EFSCORRUPTED; + goto out_release; + } + if ((fields & (XFS_ILOG_ADATA | XFS_ILOG_AEXT)) && + item->ri_buf[(fields & XFS_ILOG_DFORK) ? 3 : 2].iov_len > + XFS_DFORK_ASIZE(dip, mp)) { + error = -EFSCORRUPTED; + goto out_release; + } + switch (fields & XFS_ILOG_DFORK) { case XFS_ILOG_DDATA: case XFS_ILOG_DEXT: @@ -546,7 +565,6 @@ xlog_recover_inode_commit_pass2( case XFS_ILOG_ADATA: case XFS_ILOG_AEXT: dest = XFS_DFORK_APTR(dip); - ASSERT(len <= XFS_DFORK_ASIZE(dip, mp)); memcpy(dest, src, len); break; -- 2.53.0