From patchwork Sun Mar 17 16:23:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594572 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4173F1CA96; Sun, 17 Mar 2024 16:23:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692620; cv=none; b=Qgxshj+/50/ft543xEyd1YzZvmVIpKxSnlEvVX0hzeAdSaVLiWCyuFRNnh+OO/p4gUTqWt20K1vIym9dGohklQZYkfAWaDIwMYfBK+qHNQijkfkWEI9NutscUzgD1dg4VXHIOmfMAUITR4gzInsyglkkkBtyqkstRrybUQ5zhrA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692620; c=relaxed/simple; bh=G2GRGQXP7Tmb/LqM7gCxfbjW3s4ehpMaBQYxFXH1REU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=R/8JCP1nq6w58jh23Nntg7kJOxtuVznUm1AhbjeYbskIU9joTpRHfNCPhIHkZSkZ8sSsK7gnFpzKFjTvsddner2XbPev0diuqefwCB89iKdfWCU6EPq5vV2C63Pq3UFlWehgD8ow3ZSC9KE+q7nGGfgINmKaH4Us2j+u2VNmYQQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NU/JWEFo; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NU/JWEFo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C9A4DC433F1; Sun, 17 Mar 2024 16:23:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692619; bh=G2GRGQXP7Tmb/LqM7gCxfbjW3s4ehpMaBQYxFXH1REU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NU/JWEFoprMjLcvGoIb0y9NorBrAqX6PJNVud1jaQyXtng0uxopix3UJpIl2AcSj8 mBBXNQ2BN5OyAAH46MVOzmQyQQ9D/0IGVYnREIeytPzz+vUGcDNvDj6drr9Mgft2Fh f3vBI6XZ7anGz69hj92+fwJNO/+6cfqW6wItT4mqSBuIBsZIXxqFp8n46Tzza0uAmu yQnv0ToZsa+yM/q29l3Zo7r9fJkYDHXi7UgW/B6E6tBr6XB7b08yYn/ELhXM4A9bHz ZObwk/Rs/Of57PvcjJY1u1+4128PvGbn+9d8A/9M/5/gGl72UzpC5IiIEHlcn8RoSM S1F6JdbHRPYaQ== Date: Sun, 17 Mar 2024 09:23:39 -0700 Subject: [PATCH 01/40] fsverity: remove hash page spin lock From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: Eric Biggers , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069245930.2684506.5907414878542517215.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn The spin lock is not necessary here as it can be replaced with memory barrier which should be better performance-wise. When Merkle tree block size differs from page size, in is_hash_block_verified() two things are modified during check - a bitmap and PG_checked flag of the page. Each bit in the bitmap represent verification status of the Merkle tree blocks. PG_checked flag tells if page was just re-instantiated or was in pagecache. Both of this states are shared between verification threads. Page which was re-instantiated can not have already verified blocks (bit set in bitmap). The spin lock was used to allow only one thread to modify both of these states and keep order of operations. The only requirement here is that PG_Checked is set strictly after bitmap is updated. This way other threads which see that PG_Checked=1 (page cached) knows that bitmap is up-to-date. Otherwise, if PG_Checked is set before bitmap is cleared, other threads can see bit=1 and therefore will not perform verification of that Merkle tree block. However, there's still the case when one thread is setting a bit in verify_data_block() and other thread is clearing it in is_hash_block_verified(). This can happen if two threads get to !PageChecked branch and one of the threads is rescheduled before resetting the bitmap. This is fine as at worst blocks are re-verified in each thread. Signed-off-by: Eric Biggers Reviewed-by: Andrey Albershteyn Signed-off-by: Andrey Albershteyn --- fs/verity/fsverity_private.h | 1 - fs/verity/open.c | 1 - fs/verity/verify.c | 48 +++++++++++++++++++++--------------------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index a6a6b2749241..b3506f56e180 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -69,7 +69,6 @@ struct fsverity_info { u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE]; const struct inode *inode; unsigned long *hash_block_verified; - spinlock_t hash_page_init_lock; }; #define FS_VERITY_MAX_SIGNATURE_SIZE (FS_VERITY_MAX_DESCRIPTOR_SIZE - \ diff --git a/fs/verity/open.c b/fs/verity/open.c index 6c31a871b84b..fdeb95eca3af 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -239,7 +239,6 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, err = -ENOMEM; goto fail; } - spin_lock_init(&vi->hash_page_init_lock); } return vi; diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 904ccd7e8e16..4fcad0825a12 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -19,7 +19,6 @@ static struct workqueue_struct *fsverity_read_workqueue; static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, unsigned long hblock_idx) { - bool verified; unsigned int blocks_per_page; unsigned int i; @@ -43,12 +42,20 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, * re-instantiated from the backing storage are re-verified. To do * this, we use PG_checked again, but now it doesn't really mean * "checked". Instead, now it just serves as an indicator for whether - * the hash page is newly instantiated or not. + * the hash page is newly instantiated or not. If the page is new, as + * indicated by PG_checked=0, we clear the bitmap bits for the page's + * blocks since they are untrustworthy, then set PG_checked=1. + * Otherwise we return the bitmap bit for the requested block. * - * The first thread that sees PG_checked=0 must clear the corresponding - * bitmap bits, then set PG_checked=1. This requires a spinlock. To - * avoid having to take this spinlock in the common case of - * PG_checked=1, we start with an opportunistic lockless read. + * Multiple threads may execute this code concurrently on the same page. + * This is safe because we use memory barriers to ensure that if a + * thread sees PG_checked=1, then it also sees the associated bitmap + * clearing to have occurred. Also, all writes and their corresponding + * reads are atomic, and all writes are safe to repeat in the event that + * multiple threads get into the PG_checked=0 section. (Clearing a + * bitmap bit again at worst causes a hash block to be verified + * redundantly. That event should be very rare, so it's not worth using + * a lock to avoid. Setting PG_checked again has no effect.) */ if (PageChecked(hpage)) { /* @@ -58,24 +65,17 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, smp_rmb(); return test_bit(hblock_idx, vi->hash_block_verified); } - spin_lock(&vi->hash_page_init_lock); - if (PageChecked(hpage)) { - verified = test_bit(hblock_idx, vi->hash_block_verified); - } else { - blocks_per_page = vi->tree_params.blocks_per_page; - hblock_idx = round_down(hblock_idx, blocks_per_page); - for (i = 0; i < blocks_per_page; i++) - clear_bit(hblock_idx + i, vi->hash_block_verified); - /* - * A write memory barrier is needed here to give RELEASE - * semantics to the below SetPageChecked() operation. - */ - smp_wmb(); - SetPageChecked(hpage); - verified = false; - } - spin_unlock(&vi->hash_page_init_lock); - return verified; + blocks_per_page = vi->tree_params.blocks_per_page; + hblock_idx = round_down(hblock_idx, blocks_per_page); + for (i = 0; i < blocks_per_page; i++) + clear_bit(hblock_idx + i, vi->hash_block_verified); + /* + * A write memory barrier is needed here to give RELEASE semantics to + * the below SetPageChecked() operation. + */ + smp_wmb(); + SetPageChecked(hpage); + return false; } /* From patchwork Sun Mar 17 16:23:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594573 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 060901CA96; Sun, 17 Mar 2024 16:23:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692636; cv=none; b=HpIqUJDYLAHgW5svPhfT7bRbYKoRAOjEkzUHpQWo8IplcyhHugdAB8BCC8RdKi19VBbwuBAe6OfXHOz2ogKOTqMwVfIcYWijsuXIVMq8pfm8rfPP71csvYD/NcYBrTjMQWWXJujAA7Nb8ICiqrsyLDYtpi+a0ZMLPE8oSniwf9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692636; c=relaxed/simple; bh=kJ2W8LeTyOMmKY5ie73ROB+4axcgcPYqLtLFh1tV8hw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bSQ1JBirhH5L0icDqQoneKEU7ZRq12WXVhS+z61GaAQTljPaWWoncDgGtPheULkeuNwWGBgcD2DaQM7N4Q+eE+7r2RM4WrJYUAFcbEAyjje7LbGrksGdShiAuZVHO+uW62VisL5sC7nsBZZ2DzRfDYDVgTY9C01Ih2aUiua2mL0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=au7794Xk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="au7794Xk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 766ECC433F1; Sun, 17 Mar 2024 16:23:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692635; bh=kJ2W8LeTyOMmKY5ie73ROB+4axcgcPYqLtLFh1tV8hw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=au7794XkXVizejX7lhU3Ksr8SHaam7+ll5RWHMJZYMptxFN0/ZtyMID1fLTgeUk1q yYh1O4lXlgyNMT5xBavfW7G/FWz2UEU7+n8mJTFxeT73dcpC2uW2fXmnbnkyqed0hd IjEi4rzNFosJWze0HzJvx9/RPMaFZEtwgb9+uTl+0cSFuyRPw3dgwot8AL5rVYnqY0 HxepvSt+QDDBghTXpmJ3zvAkQcB1A2wX2uqUxXVz7UjX5qJ4KI/BhtEh3UlFXRzlL3 4lrUCcqg9c1MhQJFR3juOdTIz1XyFpkHubooxyZRRt5xSa0JPM3TvJpNSUL0uD6BXn 9aUkOwKuoKWOg== Date: Sun, 17 Mar 2024 09:23:55 -0700 Subject: [PATCH 02/40] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: Mark Tinguely , Dave Chinner , Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069245946.2684506.1395632741759692429.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Add the new parent attribute type. XFS_ATTR_PARENT is used only for parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT. Signed-off-by: Mark Tinguely Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_attr.c | 3 ++- fs/xfs/libxfs/xfs_da_format.h | 5 ++++- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/scrub/attr.c | 2 +- fs/xfs/xfs_trace.h | 3 ++- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 673a4b6d2e8d..ff67a684a452 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -925,7 +925,8 @@ xfs_attr_set( struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_trans_res tres; - bool rsvd = (args->attr_filter & XFS_ATTR_ROOT); + bool rsvd = (args->attr_filter & (XFS_ATTR_ROOT | + XFS_ATTR_PARENT)); int error, local; int rmt_blks = 0; unsigned int total; diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 060e5c96b70f..5434d4d5b551 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -714,12 +714,15 @@ struct xfs_attr3_leafblock { #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ +#define XFS_ATTR_PARENT_BIT 3 /* parent pointer attrs */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1u << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1u << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1u << XFS_ATTR_SECURE_BIT) +#define XFS_ATTR_PARENT (1u << XFS_ATTR_PARENT_BIT) #define XFS_ATTR_INCOMPLETE (1u << XFS_ATTR_INCOMPLETE_BIT) -#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) +#define XFS_ATTR_NSP_ONDISK_MASK \ + (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT) /* * Alignment for namelist and valuelist entries (since they are mixed diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 16872972e1e9..9cbcba4bd363 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -974,6 +974,7 @@ struct xfs_icreate_log { */ #define XFS_ATTRI_FILTER_MASK (XFS_ATTR_ROOT | \ XFS_ATTR_SECURE | \ + XFS_ATTR_PARENT | \ XFS_ATTR_INCOMPLETE) /* diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 83c7feb38714..49f91cc85a65 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -494,7 +494,7 @@ xchk_xattr_rec( /* Retrieve the entry and check it. */ hash = be32_to_cpu(ent->hashval); badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE | - XFS_ATTR_INCOMPLETE); + XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT); if ((ent->flags & badflags) != 0) xchk_da_set_corrupt(ds, level); if (ent->flags & XFS_ATTR_LOCAL) { diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 56b07d8ed431..d4f1b2da21e7 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -86,7 +86,8 @@ struct xfs_bmap_intent; #define XFS_ATTR_FILTER_FLAGS \ { XFS_ATTR_ROOT, "ROOT" }, \ { XFS_ATTR_SECURE, "SECURE" }, \ - { XFS_ATTR_INCOMPLETE, "INCOMPLETE" } + { XFS_ATTR_INCOMPLETE, "INCOMPLETE" }, \ + { XFS_ATTR_PARENT, "PARENT" } DECLARE_EVENT_CLASS(xfs_attr_list_class, TP_PROTO(struct xfs_attr_list_context *ctx), From patchwork Sun Mar 17 16:24:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594574 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A50161CA96; Sun, 17 Mar 2024 16:24:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692651; cv=none; b=mSXASVZNpoK7c6BLkt48wT5dyIv4M3t+fEAhVNhVMQJA3PVIRV7egE0YmeR9QmXXpgcnW+d9tHojaSHSrAj+0InAy35c0HbK0cEBrOOlzj8/ASmsLIgtZT++Cp/v18oFWDKi/UYd8/ljY43cgsF1EDhWWDkje1P/a27Nrdez/Zw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692651; c=relaxed/simple; bh=3PiQWLCvQqjS7LPBm90t4SOaaoJMbpAwofTbsuxbe28=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DWtk4oTJDDxX+7oDALSuW7A9TUMDxo0ove844yo8sVJ44S1cb5ToRPQmxQylyx2bwu6Ml2ikYLmNf1Bb/2Vjt5xRaP/nrMR4dnIvtn//55O3z09rXwSr29TsvTVUGA0U5cm0dq9j5Re93Hz9dEK8qQ5Gf/9kIeV8HipfMJSg01Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hKuqLw8D; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hKuqLw8D" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 37E89C433F1; Sun, 17 Mar 2024 16:24:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692651; bh=3PiQWLCvQqjS7LPBm90t4SOaaoJMbpAwofTbsuxbe28=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hKuqLw8D1H067+gENLLH+BHtGWUS//ttnXOvOvCLgmPIOhoSuKuTOfaBNTrKrvSs/ onFmwpS2uvzFzV1pv4mWb7JK0xLHveO0VfZgFh1y6otAkpM9BiE0HAbjJDMcCcBPvT IMSAxADAh9XVSVQjRGyEvjy/2GoKVE00QNib/ssa5pvGSvpMgKjbWMkFY67G5tPg6b DTDpSsN/4JrcZF8W7JrSP0kj2dGkgSR81IEDgjA8ee/2umC/cByGkd5aP3VTWWrA1O vd8LjVhLos718KaSgnwtPDnijrY507RR4m2psmg4O2XxWbwMcEwPb2vBhREG6iym4e 3ZLnhOHUNSo7A== Date: Sun, 17 Mar 2024 09:24:10 -0700 Subject: [PATCH 03/40] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: Dave Chinner , Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069245962.2684506.1502973262362352509.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson We need to define the parent pointer attribute format before we start adding support for it into all the code that needs to use it. The EA format we will use encodes the following information: name={parent inode #, parent inode generation, dirent namehash} value={dirent name} The inode/gen gives all the information we need to reliably identify the parent without requiring child->parent lock ordering, and allows userspace to do pathname component level reconstruction without the kernel ever needing to verify the parent itself as part of ioctl calls. Storing the dirent name hash in the key reduces hash collisions if a file is hardlinked multiple times in the same directory. By using the NVLOOKUP mode in the extended attribute code to match parent pointers using both the xattr name and value, we can identify the exact parent pointer EA we need to modify/remove in rename/unlink operations without searching the entire EA space. By storing the dirent name, we have enough information to be able to validate and reconstruct damaged directory trees. Earlier iterations of this patchset encoded the directory offset in the parent pointer key, but this format required repair to keep that in sync across directory rebuilds, which is unnecessary complexity. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: replace diroffset with the namehash in the pptr key] Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 5434d4d5b551..67e8c33c4e82 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -878,4 +878,24 @@ static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp) xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, struct xfs_da3_blkinfo *hdr3); +/* + * Parent pointer attribute format definition + * + * The xattr name encodes the parent inode number, generation and the crc32c + * hash of the dirent name. + * + * The xattr value contains the dirent name. + */ +struct xfs_parent_name_rec { + __be64 p_ino; + __be32 p_gen; + __be32 p_namehash; +}; + +/* + * Maximum size of the dirent name that can be stored in a parent pointer. + * This matches the maximum dirent name length. + */ +#define XFS_PARENT_DIRENT_NAME_MAX_SIZE (MAXNAMELEN - 1) + #endif /* __XFS_DA_FORMAT_H__ */ From patchwork Sun Mar 17 16:24:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594575 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E4E21CD03; Sun, 17 Mar 2024 16:24:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692667; cv=none; b=QhXVs8zA3izyK5CF4+aL4Yy7abRDJ52Mm7GP7xzU0DxFI6PUMAjqmYhS1jwPcHbiZkysLLP93/a00TK+EWQ3WXsXmLN7lf/Wf8m7Nf3HDpZa6Icwni/GYO5GUw+d2iN4L1BfNNK2vwE19YRttqkuH2uL3h5LN1moP8BmE7Y21bE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692667; c=relaxed/simple; bh=QlJAa+uqVG2dhy6hqzccOs4xjxALGADksKWeBhfsQ3U=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ptrJbKeeYKon4S5qedK4qMivwGDYDNT2dOw2oc7EAiPseHcwaFhEzw8ngzj9BQY/Wu0n6JSqVAmiWozen8F3tdgJMaads/uYD+c9sT8pBM2zTAW1kqmSHTfwCV8P5R4FdtnEtvFNaCE+Jj8vb/oeBRFH0qXKMOrwhivY/IumxfM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GAEfzEwF; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GAEfzEwF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D05BDC433F1; Sun, 17 Mar 2024 16:24:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692666; bh=QlJAa+uqVG2dhy6hqzccOs4xjxALGADksKWeBhfsQ3U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GAEfzEwFTKWh6w5bOeCAdU5oVlPBKcGzZoiAE4kuk+AMreWE7IKCE0Y5lXa4y5wGC hd/xwOgtJfwuLvPMR4ptbb6Y+1KGQynCKb7UbO+Q0khIGqRTSOWmjRp4MXDpM15TIi 3r64U8OpQ/cbFdscuY8YMuu0JNcd+Qhyqa1bEUwFRD7Kw+1h8zU/GRRnZ3QNE6vlUa zTrK5WzG1cneP7az6V9DGjfy51nbntyoP9M6uQZdBjtpvdhBGLWjbhYhPz2HtPw1u4 IzOnwVAZAM/DP3pBM1DgcSY5likKvNQSWMCMTfKFyWAvMDOe9PBrTgGXpPIhieZrMv qhpurOLmwKK5A== Date: Sun, 17 Mar 2024 09:24:26 -0700 Subject: [PATCH 04/40] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069245977.2684506.7320994598272045734.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Attribute names of parent pointers are not strings. So we need to modify attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is set. At the same time, we need to validate attr values during log recovery if the xattr is really a parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move functions to xfs_parent.c, adjust for new disk format] Signed-off-by: Darrick J. Wong --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_attr.c | 10 +++- fs/xfs/libxfs/xfs_attr.h | 3 + fs/xfs/libxfs/xfs_da_format.h | 8 +++ fs/xfs/libxfs/xfs_parent.c | 113 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 19 +++++++ fs/xfs/scrub/attr.c | 2 - fs/xfs/xfs_attr_item.c | 6 +- fs/xfs/xfs_attr_list.c | 14 +++-- 9 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_parent.c create mode 100644 fs/xfs/libxfs/xfs_parent.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 76674ad5833e..f8845e65cac7 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -41,6 +41,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_inode_buf.o \ xfs_log_rlimit.o \ xfs_ag_resv.o \ + xfs_parent.o \ xfs_rmap.o \ xfs_rmap_btree.o \ xfs_refcount.o \ diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index ff67a684a452..f0b625d45aa4 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -26,6 +26,7 @@ #include "xfs_trace.h" #include "xfs_attr_item.h" #include "xfs_xattr.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1515,9 +1516,14 @@ xfs_attr_node_get( /* Returns true if the attribute entry name is valid. */ bool xfs_attr_namecheck( - const void *name, - size_t length) + struct xfs_mount *mp, + const void *name, + size_t length, + unsigned int flags) { + if (flags & XFS_ATTR_PARENT) + return xfs_parent_namecheck(mp, name, length, flags); + /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 81be9b3e4004..92711c8d2a9f 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -547,7 +547,8 @@ int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); -bool xfs_attr_namecheck(const void *name, size_t length); +bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, + unsigned int flags); int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 67e8c33c4e82..839df0e5401b 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -757,6 +757,14 @@ xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; } +static inline int +xfs_attr3_leaf_flags(xfs_attr_leafblock_t *leafp, int idx) +{ + struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); + + return entries[idx].flags; +} + static inline xfs_attr_leaf_name_remote_t * xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) { diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c new file mode 100644 index 000000000000..1d45f926c13a --- /dev/null +++ b/fs/xfs/libxfs/xfs_parent.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_log_format.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_trace.h" +#include "xfs_trans.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_dir2.h" +#include "xfs_dir2_priv.h" +#include "xfs_attr_sf.h" +#include "xfs_bmap.h" +#include "xfs_defer.h" +#include "xfs_log.h" +#include "xfs_xattr.h" +#include "xfs_parent.h" +#include "xfs_trans_space.h" + +/* + * Parent pointer attribute handling. + * + * Because the attribute value is a filename component, it will never be longer + * than 255 bytes. This means the attribute will always be a local format + * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will + * always be larger than this (max is 75% of block size). + * + * Creating a new parent attribute will always create a new attribute - there + * should never, ever be an existing attribute in the tree for a new inode. + * ENOSPC behavior is problematic - creating the inode without the parent + * pointer is effectively a corruption, so we allow parent attribute creation + * to dip into the reserve block pool to avoid unexpected ENOSPC errors from + * occurring. + */ + +/* Return true if parent pointer EA name is valid. */ +bool +xfs_parent_namecheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + size_t reclen, + unsigned int attr_flags) +{ + if (!(attr_flags & XFS_ATTR_PARENT)) + return false; + + /* pptr updates use logged xattrs, so we should never see this flag */ + if (attr_flags & XFS_ATTR_INCOMPLETE) + return false; + + if (reclen != sizeof(struct xfs_parent_name_rec)) + return false; + + /* Only one namespace bit allowed. */ + if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) + return false; + + return true; +} + +/* Return true if parent pointer EA value is valid. */ +bool +xfs_parent_valuecheck( + struct xfs_mount *mp, + const void *value, + size_t valuelen) +{ + if (valuelen == 0 || valuelen > XFS_PARENT_DIRENT_NAME_MAX_SIZE) + return false; + + if (value == NULL) + return false; + + return true; +} + +/* Return true if the ondisk parent pointer is consistent. */ +bool +xfs_parent_hashcheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + const void *value, + size_t valuelen) +{ + struct xfs_name dname = { + .name = value, + .len = valuelen, + }; + xfs_ino_t p_ino; + + /* Valid dirent name? */ + if (!xfs_dir2_namecheck(value, valuelen)) + return false; + + /* Valid inode number? */ + p_ino = be64_to_cpu(rec->p_ino); + if (!xfs_verify_dir_ino(mp, p_ino)) + return false; + + /* Namehash matches name? */ + return be32_to_cpu(rec->p_namehash) == xfs_dir2_hashname(mp, &dname); +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h new file mode 100644 index 000000000000..fcfeddb645f6 --- /dev/null +++ b/fs/xfs/libxfs/xfs_parent.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All Rights Reserved. + */ +#ifndef __XFS_PARENT_H__ +#define __XFS_PARENT_H__ + +/* Metadata validators */ +bool xfs_parent_namecheck(struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, size_t reclen, + unsigned int attr_flags); +bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, + size_t valuelen); +bool xfs_parent_hashcheck(struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, const void *value, + size_t valuelen); + +#endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 49f91cc85a65..9a1f59f7b5a4 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -195,7 +195,7 @@ xchk_xattr_listent( } /* Does this name make sense? */ - if (!xfs_attr_namecheck(name, namelen)) { + if (!xfs_attr_namecheck(sx->sc->mp, name, namelen, flags)) { xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); goto fail_xref; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 9b4c61e1c22e..703770cf1482 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -591,7 +591,8 @@ xfs_attr_recover_work( */ attrp = &attrip->attri_format; if (!xfs_attri_validate(mp, attrp) || - !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) + !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len, + attrp->alfi_attr_filter)) return -EFSCORRUPTED; attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv); @@ -731,7 +732,8 @@ xlog_recover_attri_commit_pass2( return -EFSCORRUPTED; } - if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { + if (!xfs_attr_namecheck(mp, attr_name, attri_formatp->alfi_name_len, + attri_formatp->alfi_attr_filter)) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, item->ri_buf[1].i_addr, item->ri_buf[1].i_len); return -EFSCORRUPTED; diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index a6819a642cc0..fa74378577c5 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -59,6 +59,7 @@ xfs_attr_shortform_list( struct xfs_attr_sf_sort *sbuf, *sbp; struct xfs_attr_sf_hdr *sf = dp->i_af.if_data; struct xfs_attr_sf_entry *sfe; + struct xfs_mount *mp = dp->i_mount; int sbsize, nsbuf, count, i; int error = 0; @@ -82,8 +83,9 @@ xfs_attr_shortform_list( (dp->i_af.if_bytes + sf->count * 16) < context->bufsize)) { for (i = 0, sfe = xfs_attr_sf_firstentry(sf); i < sf->count; i++) { if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sfe->nameval, - sfe->namelen))) { + !xfs_attr_namecheck(mp, sfe->nameval, + sfe->namelen, + sfe->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); return -EFSCORRUPTED; } @@ -177,8 +179,9 @@ xfs_attr_shortform_list( cursor->offset = 0; } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sbp->name, - sbp->namelen))) { + !xfs_attr_namecheck(mp, sbp->name, + sbp->namelen, + sbp->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); error = -EFSCORRUPTED; goto out; @@ -474,7 +477,8 @@ xfs_attr3_leaf_list_int( } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(name, namelen))) { + !xfs_attr_namecheck(mp, name, namelen, + entry->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); return -EFSCORRUPTED; } From patchwork Sun Mar 17 16:24:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594576 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E2D791CAB7; Sun, 17 Mar 2024 16:24:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692683; cv=none; b=HbpWi4aOFjrPHHHz/fsr3DEXVwv9U7qIIB07ca6ix+gGYNePpvq7FSlFyniHNtn08mf+FnIk6O8jbCH+E5DEJVCsCWImSbY+K1zDAxXCcxXLOLmIvh9WpsSmv82bHq5TY7QB2j/DnZ0l5HnjgrJknjd4lILjoNWSi/vNidts38s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692683; c=relaxed/simple; bh=dtKcdSScfcG6Cfxhp6/Ic3o355SRhRXikVozgstP7bA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XlfS+V5wf/P03KN4ibTuWGqC1C6zZJQKxsqULYcK0tOT4WfntB88ReiDolSrDgvyfwS3j7JgaEMcBDXCO3fN3icKdMGh0zNEUmIsmjmg9NYjPlVmJ8KnQohV0B9sbgsZ8MdTjL79UJoyJf1FuoPMWUgpY5rMlIcBGHY5ajirEnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=q+EfdoSt; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="q+EfdoSt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B8C6C433F1; Sun, 17 Mar 2024 16:24:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692682; bh=dtKcdSScfcG6Cfxhp6/Ic3o355SRhRXikVozgstP7bA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=q+EfdoStxZTs8bMadOIp/9nslW7ouw1l1882I95F/U9Q5qWjIFZ0Fudr0NQe0M7VR jzzNuaTCfgWTfA5WbM80BqB/OTKVvqaFP+5ZQ/UmdpmT7HmVJImqY9/US/KKPLMHfY v+VP3LQYYvIiepjNvaVXbLSa89666/+6YvRLtU3BadihkKAV+eA+mkQMU5iUpR4Tvx QJNchY1YAWOIhqDrB4wczIGLY7OaWBWIPrGNQDuqLh8+ISoqx0R5etZlCDrchuiHbK 92F0Zt4Ne6IQCiP5iwwtsnNndp4VivYhRE1SwhlDebZKrD9/n66qLIYpGs6A6RTz0E DJ48W/8yRLLAw== Date: Sun, 17 Mar 2024 09:24:42 -0700 Subject: [PATCH 05/40] fs: add FS_XFLAG_VERITY for verity files From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069245994.2684506.6726769743411488318.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn Add extended attribute FS_XFLAG_VERITY for inodes with fs-verity enabled. Signed-off-by: Andrey Albershteyn [djwong: fix broken verity flag checks] Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- Documentation/filesystems/fsverity.rst | 8 ++++++++ fs/ioctl.c | 11 +++++++++++ include/uapi/linux/fs.h | 1 + 3 files changed, 20 insertions(+) diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 13e4b18e5dbb..887cdaf162a9 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -326,6 +326,14 @@ the file has fs-verity enabled. This can perform better than FS_IOC_GETFLAGS and FS_IOC_MEASURE_VERITY because it doesn't require opening the file, and opening verity files can be expensive. +FS_IOC_FSGETXATTR +----------------- + +Since Linux v6.9, the FS_IOC_FSGETXATTR ioctl sets FS_XFLAG_VERITY (0x00020000) +in the returned flags when the file has verity enabled. Note that this attribute +cannot be set with FS_IOC_FSSETXATTR as enabling verity requires input +parameters. See FS_IOC_ENABLE_VERITY. + .. _accessing_verity_files: Accessing verity files diff --git a/fs/ioctl.c b/fs/ioctl.c index 76cf22ac97d7..fa30aae3903b 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -481,6 +481,8 @@ void fileattr_fill_xflags(struct fileattr *fa, u32 xflags) fa->flags |= FS_DAX_FL; if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) fa->flags |= FS_PROJINHERIT_FL; + if (fa->fsx_xflags & FS_XFLAG_VERITY) + fa->flags |= FS_VERITY_FL; } EXPORT_SYMBOL(fileattr_fill_xflags); @@ -511,6 +513,8 @@ void fileattr_fill_flags(struct fileattr *fa, u32 flags) fa->fsx_xflags |= FS_XFLAG_DAX; if (fa->flags & FS_PROJINHERIT_FL) fa->fsx_xflags |= FS_XFLAG_PROJINHERIT; + if (fa->flags & FS_VERITY_FL) + fa->fsx_xflags |= FS_XFLAG_VERITY; } EXPORT_SYMBOL(fileattr_fill_flags); @@ -641,6 +645,13 @@ static int fileattr_set_prepare(struct inode *inode, !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) return -EINVAL; + /* + * Verity cannot be changed through FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS. + * See FS_IOC_ENABLE_VERITY. + */ + if ((fa->fsx_xflags ^ old_ma->fsx_xflags) & FS_XFLAG_VERITY) + return -EINVAL; + /* Extent size hints of zero turn off the flags. */ if (fa->fsx_extsize == 0) fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 48ad69f7722e..b1d0e1169bc3 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -140,6 +140,7 @@ struct fsxattr { #define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ #define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ #define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */ +#define FS_XFLAG_VERITY 0x00020000 /* fs-verity enabled */ #define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ /* the read-only stuff doesn't really belong here, but any other place is From patchwork Sun Mar 17 16:24:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594577 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C474B1CA96; Sun, 17 Mar 2024 16:24:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692698; cv=none; b=YMpO47E9GGHBCcSwM8Y1TWO4VkSUBHlP/jg8AthqBFeAp09hko5tYg/uNZWwHnnAHyIiNFR/wD7R3ZaQQJZnjuIoxIl2Ea8azwZ9z1di++byH8tjlBMM1ZO4ug0hXXMuYe8FLP/XWbEDUPj0uUmK6gRDX63m2FWUThjXrrVkyVI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692698; c=relaxed/simple; bh=KcBxCsDbbHTMEwAn8JLG5V8IPCr3cER3Edi8B9kP5d4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Qqt1ySO+QY0TzntO+mgLXJ8fdJ6AYQRmOg/SM8Gs3m9JclDJPXw5zzBbmxjOSizzZF7ntoxLaqyhGRaiw+srabkZT+x9/vclSs7z05NBaCNnVN+74AHacf3sH75ojLakukM7rR9EaUpaqu1EuK5vjMK/Va+QoTKpoaLD82sZySM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p2qI/u5y; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p2qI/u5y" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3C0B4C433C7; Sun, 17 Mar 2024 16:24:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692698; bh=KcBxCsDbbHTMEwAn8JLG5V8IPCr3cER3Edi8B9kP5d4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=p2qI/u5yqsbst9V3SitrSav7V7IDu1VpK/tXnGxI/VNcPJvLowG5eAPcAHDXXIEUG qs0mggqndBIaZCedyISFcyYtHmnLBi1LCE4pwoKFCzoiuq33gZ6gTDuClcPjtr9k3J 68Kes3Yte7M6GHbM2cHjt2xbn4ILcnONphe84etq9rLa8J0RuYgtWA489MYUW7YCOr 1DrXIdEPjzCFEwPS5Zc0/J0+4MTQxdiNQZyNTlMyK+9GAkLecsyqr2z1stcbYauA4b VXLylyozp/4Y9UyhAOtYeddoH2f+qnzV6CJKh8F3lI8Bwa7WYhkVRtCXv7BhV+wceA 2MSCJoE2Fx0/w== Date: Sun, 17 Mar 2024 09:24:57 -0700 Subject: [PATCH 06/40] fsverity: pass tree_blocksize to end_enable_verity() From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246010.2684506.17931924061025315548.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn XFS will need to know tree_blocksize to remove the tree in case of an error. The size is needed to calculate offsets of particular Merkle tree blocks. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: I put ebiggers' suggested changes in a separate patch] Signed-off-by: Darrick J. Wong --- fs/btrfs/verity.c | 4 +++- fs/ext4/verity.c | 3 ++- fs/f2fs/verity.c | 3 ++- fs/verity/enable.c | 6 ++++-- include/linux/fsverity.h | 4 +++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index 66e2270b0dae..966630523502 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -621,6 +621,7 @@ static int btrfs_begin_enable_verity(struct file *filp) * @desc: verity descriptor to write out (NULL in error conditions) * @desc_size: size of the verity descriptor (variable with signatures) * @merkle_tree_size: size of the merkle tree in bytes + * @tree_blocksize: the Merkle tree block size * * If desc is null, then VFS is signaling an error occurred during verity * enable, and we should try to rollback. Otherwise, attempt to finish verity. @@ -628,7 +629,8 @@ static int btrfs_begin_enable_verity(struct file *filp) * Returns 0 on success, negative error code on error. */ static int btrfs_end_enable_verity(struct file *filp, const void *desc, - size_t desc_size, u64 merkle_tree_size) + size_t desc_size, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct btrfs_inode *inode = BTRFS_I(file_inode(filp)); int ret = 0; diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index 2f37e1ea3955..da2095a81349 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -189,7 +189,8 @@ static int ext4_write_verity_descriptor(struct inode *inode, const void *desc, } static int ext4_end_enable_verity(struct file *filp, const void *desc, - size_t desc_size, u64 merkle_tree_size) + size_t desc_size, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct inode *inode = file_inode(filp); const int credits = 2; /* superblock and inode for ext4_orphan_del() */ diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index 4fc95f353a7a..b4461b9f47a3 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -144,7 +144,8 @@ static int f2fs_begin_enable_verity(struct file *filp) } static int f2fs_end_enable_verity(struct file *filp, const void *desc, - size_t desc_size, u64 merkle_tree_size) + size_t desc_size, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); diff --git a/fs/verity/enable.c b/fs/verity/enable.c index c284f46d1b53..04e060880b79 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -274,7 +274,8 @@ static int enable_verity(struct file *filp, * Serialized with ->begin_enable_verity() by the inode lock. */ inode_lock(inode); - err = vops->end_enable_verity(filp, desc, desc_size, params.tree_size); + err = vops->end_enable_verity(filp, desc, desc_size, params.tree_size, + params.block_size); inode_unlock(inode); if (err) { fsverity_err(inode, "%ps() failed with err %d", @@ -300,7 +301,8 @@ static int enable_verity(struct file *filp, rollback: inode_lock(inode); - (void)vops->end_enable_verity(filp, NULL, 0, params.tree_size); + (void)vops->end_enable_verity(filp, NULL, 0, params.tree_size, + params.block_size); inode_unlock(inode); goto out; } diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 1eb7eae580be..ac58b19f23d3 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -51,6 +51,7 @@ struct fsverity_operations { * @desc: the verity descriptor to write, or NULL on failure * @desc_size: size of verity descriptor, or 0 on failure * @merkle_tree_size: total bytes the Merkle tree took up + * @tree_blocksize: the Merkle tree block size * * If desc == NULL, then enabling verity failed and the filesystem only * must do any necessary cleanups. Else, it must also store the given @@ -65,7 +66,8 @@ struct fsverity_operations { * Return: 0 on success, -errno on failure */ int (*end_enable_verity)(struct file *filp, const void *desc, - size_t desc_size, u64 merkle_tree_size); + size_t desc_size, u64 merkle_tree_size, + unsigned int tree_blocksize); /** * Get the verity descriptor of the given inode. From patchwork Sun Mar 17 16:25:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594578 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AD5B1CD03; Sun, 17 Mar 2024 16:25:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692714; cv=none; b=gpnJ8P0uzZQgrk70Y8s6hZZBl3Jh/NshmDV77pUom4DJew/covd1b7ox20t/o3wc2lmE/rXM/I8h2dPhKmyQILQHrVhMo48O9GywBvNBq9I2SYppO9SDhazmSmIbRksaVRahvkZoWM+GyZXwraDzozujnQFQl5d5uJjh3Ljw0Vo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692714; c=relaxed/simple; bh=FC+paGrNxsjCbjU/yjE7JUcL1xa0Tbz8cr6Qe2XCNhQ=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HN9tJvbkW+jWZHfMKfcTUCjD1dq6Uv3ynnPxIxTSWHUJhu8VYsXhCCt/nhYLQFR5wejo9yBkPUVRDgxtZYHsDqmYuaemTHKy+qnQCxJWiJSciF1rHzWiz1W9UIxvlAW+E8duEoHRaoIP5ciR4v9SYXedSe+CBL8mqaYyLA5/HR8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ADhOiyTg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ADhOiyTg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D5566C433C7; Sun, 17 Mar 2024 16:25:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692713; bh=FC+paGrNxsjCbjU/yjE7JUcL1xa0Tbz8cr6Qe2XCNhQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ADhOiyTgREpMgASelVKJOSPWm0Fi2fz6A37GdxQfpqs5zYJAulm2mn9fsRG1CfZHZ 2UtivqQ1aMzArUhJ/SisCsjpmdx7tQxkut9TxTwqfwd6N1WSAGKk8EczTgYcw+jc8+ MwrHcwf22OAGHeHssMzhlFW/TL4uyS7e9TlQaV/YsYuN49fAsCMUwfagI7ute/Tt6T ovcP7abgpi3UADR9fglhod/rPQfSldrOCMz77LKzWSauo1OUyMbq/d77/DcIeCq2az mKSwbarev6MB3+/ltqrFWOlQQYvPm3iH51USxF4U/bxs+HmQnPcsrGoKe5HvCbiUfu s9lod+rDqIPaw== Date: Sun, 17 Mar 2024 09:25:13 -0700 Subject: [PATCH 07/40] fsverity: support block-based Merkle tree caching From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246026.2684506.5885801786594980023.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn In the current implementation fs-verity expects filesystem to provide PAGEs filled with Merkle tree blocks. Then, when fs-verity is done with processing the blocks, reference to PAGE is freed. This doesn't fit well with the way XFS manages its memory. To allow XFS integrate fs-verity this patch adds ability to fs-verity verification code to take Merkle tree blocks instead of PAGE reference. This way ext4, f2fs, and btrfs are still able to pass PAGE references and XFS can pass reference to Merkle tree blocks stored in XFS's buffer infrastructure. Another addition is invalidation function which tells fs-verity to mark part of Merkle tree as not verified. This function is used by filesystem to tell fs-verity to invalidate block which was evicted from memory. Depending on Merkle tree block size fs-verity is using either bitmap or PG_checked flag to track "verified" status of the blocks. With a Merkle tree block caching (XFS) there is no PAGE to flag it as verified. fs-verity always uses bitmap to track verified blocks for filesystems which use block caching. Further this patch allows filesystem to make additional processing on verified pages via fsverity_drop_block() instead of just dropping a reference. This will be used by XFS for internal buffer cache manipulation in further patches. The btrfs, ext4, and f2fs just drop the reference. Signed-off-by: Andrey Albershteyn [djwong: fix uninit err variable] Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/verity/fsverity_private.h | 8 +++ fs/verity/open.c | 8 ++- fs/verity/read_metadata.c | 64 ++++++++++++++-------- fs/verity/verify.c | 125 ++++++++++++++++++++++++++++++++---------- include/linux/fsverity.h | 65 ++++++++++++++++++++++ 5 files changed, 217 insertions(+), 53 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index b3506f56e180..dad33e6ff0d6 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -154,4 +154,12 @@ static inline void fsverity_init_signature(void) void __init fsverity_init_workqueue(void); +/* + * Drop 'block' obtained with ->read_merkle_tree_block(). Calls out back to + * filesystem if ->drop_block() is set, otherwise, drop the reference in the + * block->context. + */ +void fsverity_drop_block(struct inode *inode, + struct fsverity_blockbuf *block); + #endif /* _FSVERITY_PRIVATE_H */ diff --git a/fs/verity/open.c b/fs/verity/open.c index fdeb95eca3af..6e6922b4b014 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -213,7 +213,13 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, if (err) goto fail; - if (vi->tree_params.block_size != PAGE_SIZE) { + /* + * If fs passes Merkle tree blocks to fs-verity (e.g. XFS), then + * fs-verity should use hash_block_verified bitmap as there's no page + * to mark it with PG_checked. + */ + if (vi->tree_params.block_size != PAGE_SIZE || + inode->i_sb->s_vop->read_merkle_tree_block) { /* * When the Merkle tree block size and page size differ, we use * a bitmap to keep track of which hash blocks have been diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c index f58432772d9e..5da40b5a81af 100644 --- a/fs/verity/read_metadata.c +++ b/fs/verity/read_metadata.c @@ -18,50 +18,68 @@ static int fsverity_read_merkle_tree(struct inode *inode, { const struct fsverity_operations *vops = inode->i_sb->s_vop; u64 end_offset; - unsigned int offs_in_page; + unsigned int offs_in_block; pgoff_t index, last_index; int retval = 0; int err = 0; + const unsigned int block_size = vi->tree_params.block_size; + const u8 log_blocksize = vi->tree_params.log_blocksize; end_offset = min(offset + length, vi->tree_params.tree_size); if (offset >= end_offset) return 0; - offs_in_page = offset_in_page(offset); - last_index = (end_offset - 1) >> PAGE_SHIFT; + offs_in_block = offset & (block_size - 1); + last_index = (end_offset - 1) >> log_blocksize; /* - * Iterate through each Merkle tree page in the requested range and copy - * the requested portion to userspace. Note that the Merkle tree block - * size isn't important here, as we are returning a byte stream; i.e., - * we can just work with pages even if the tree block size != PAGE_SIZE. + * Iterate through each Merkle tree block in the requested range and + * copy the requested portion to userspace. Note that we are returning + * a byte stream. */ - for (index = offset >> PAGE_SHIFT; index <= last_index; index++) { + for (index = offset >> log_blocksize; index <= last_index; index++) { unsigned long num_ra_pages = min_t(unsigned long, last_index - index + 1, inode->i_sb->s_bdi->io_pages); unsigned int bytes_to_copy = min_t(u64, end_offset - offset, - PAGE_SIZE - offs_in_page); - struct page *page; - const void *virt; + block_size - offs_in_block); + struct fsverity_blockbuf block = { + .size = block_size, + }; - page = vops->read_merkle_tree_page(inode, index, num_ra_pages); - if (IS_ERR(page)) { - err = PTR_ERR(page); + if (!vops->read_merkle_tree_block) { + unsigned int blocks_per_page = + vi->tree_params.blocks_per_page; + unsigned long page_idx = + round_down(index, blocks_per_page); + struct page *page = vops->read_merkle_tree_page(inode, + page_idx, num_ra_pages); + + if (IS_ERR(page)) { + err = PTR_ERR(page); + } else { + block.kaddr = kmap_local_page(page) + + ((index - page_idx) << log_blocksize); + block.context = page; + } + } else { + err = vops->read_merkle_tree_block(inode, + index << log_blocksize, + &block, log_blocksize, num_ra_pages); + } + + if (err) { fsverity_err(inode, - "Error %d reading Merkle tree page %lu", - err, index); + "Error %d reading Merkle tree block %lu", + err, index << log_blocksize); break; } - virt = kmap_local_page(page); - if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) { - kunmap_local(virt); - put_page(page); + if (copy_to_user(buf, block.kaddr + offs_in_block, bytes_to_copy)) { + fsverity_drop_block(inode, &block); err = -EFAULT; break; } - kunmap_local(virt); - put_page(page); + fsverity_drop_block(inode, &block); retval += bytes_to_copy; buf += bytes_to_copy; @@ -72,7 +90,7 @@ static int fsverity_read_merkle_tree(struct inode *inode, break; } cond_resched(); - offs_in_page = 0; + offs_in_block = 0; } return retval ? retval : err; } diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 4fcad0825a12..4ebdf9d2d7b6 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -13,14 +13,17 @@ static struct workqueue_struct *fsverity_read_workqueue; /* - * Returns true if the hash block with index @hblock_idx in the tree, located in - * @hpage, has already been verified. + * Returns true if the hash block with index @hblock_idx in the tree has + * already been verified. */ -static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, +static bool is_hash_block_verified(struct inode *inode, + struct fsverity_blockbuf *block, unsigned long hblock_idx) { unsigned int blocks_per_page; unsigned int i; + struct fsverity_info *vi = inode->i_verity_info; + struct page *hpage = (struct page *)block->context; /* * When the Merkle tree block size and page size are the same, then the @@ -34,6 +37,12 @@ static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, if (!vi->hash_block_verified) return PageChecked(hpage); + /* + * Filesystems which use block based caching (e.g. XFS) always use + * bitmap. + */ + if (inode->i_sb->s_vop->read_merkle_tree_block) + return test_bit(hblock_idx, vi->hash_block_verified); /* * When the Merkle tree block size and page size differ, we use a bitmap * to indicate whether each hash block has been verified. @@ -95,15 +104,15 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, const struct merkle_tree_params *params = &vi->tree_params; const unsigned int hsize = params->digest_size; int level; + int err = 0; + int num_ra_pages; u8 _want_hash[FS_VERITY_MAX_DIGEST_SIZE]; const u8 *want_hash; u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE]; /* The hash blocks that are traversed, indexed by level */ struct { - /* Page containing the hash block */ - struct page *page; - /* Mapped address of the hash block (will be within @page) */ - const void *addr; + /* Buffer containing the hash block */ + struct fsverity_blockbuf block; /* Index of the hash block in the tree overall */ unsigned long index; /* Byte offset of the wanted hash relative to @addr */ @@ -144,10 +153,11 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, unsigned long next_hidx; unsigned long hblock_idx; pgoff_t hpage_idx; + u64 hblock_pos; unsigned int hblock_offset_in_page; unsigned int hoffset; struct page *hpage; - const void *haddr; + struct fsverity_blockbuf *block = &hblocks[level].block; /* * The index of the block in the current level; also the index @@ -165,29 +175,49 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, hblock_offset_in_page = (hblock_idx << params->log_blocksize) & ~PAGE_MASK; + /* Offset of the Merkle tree block into the tree */ + hblock_pos = hblock_idx << params->log_blocksize; + /* Byte offset of the hash within the block */ hoffset = (hidx << params->log_digestsize) & (params->block_size - 1); - hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, - hpage_idx, level == 0 ? min(max_ra_pages, - params->tree_pages - hpage_idx) : 0); - if (IS_ERR(hpage)) { + num_ra_pages = level == 0 ? + min(max_ra_pages, params->tree_pages - hpage_idx) : 0; + + if (inode->i_sb->s_vop->read_merkle_tree_block) { + err = inode->i_sb->s_vop->read_merkle_tree_block( + inode, hblock_pos, block, params->log_blocksize, + num_ra_pages); + } else { + unsigned int blocks_per_page = + vi->tree_params.blocks_per_page; + hblock_idx = round_down(hblock_idx, blocks_per_page); + hpage = inode->i_sb->s_vop->read_merkle_tree_page( + inode, hpage_idx, (num_ra_pages << PAGE_SHIFT)); + + if (IS_ERR(hpage)) { + err = PTR_ERR(hpage); + } else { + block->kaddr = kmap_local_page(hpage) + + hblock_offset_in_page; + block->context = hpage; + } + } + + if (err) { fsverity_err(inode, - "Error %ld reading Merkle tree page %lu", - PTR_ERR(hpage), hpage_idx); + "Error %d reading Merkle tree block %lu", + err, hblock_idx); goto error; } - haddr = kmap_local_page(hpage) + hblock_offset_in_page; - if (is_hash_block_verified(vi, hpage, hblock_idx)) { - memcpy(_want_hash, haddr + hoffset, hsize); + + if (is_hash_block_verified(inode, block, hblock_idx)) { + memcpy(_want_hash, block->kaddr + hoffset, hsize); want_hash = _want_hash; - kunmap_local(haddr); - put_page(hpage); + fsverity_drop_block(inode, block); goto descend; } - hblocks[level].page = hpage; - hblocks[level].addr = haddr; hblocks[level].index = hblock_idx; hblocks[level].hoffset = hoffset; hidx = next_hidx; @@ -197,10 +227,11 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, descend: /* Descend the tree verifying hash blocks. */ for (; level > 0; level--) { - struct page *hpage = hblocks[level - 1].page; - const void *haddr = hblocks[level - 1].addr; + struct fsverity_blockbuf *block = &hblocks[level - 1].block; + const void *haddr = block->kaddr; unsigned long hblock_idx = hblocks[level - 1].index; unsigned int hoffset = hblocks[level - 1].hoffset; + struct page *hpage = (struct page *)block->context; if (fsverity_hash_block(params, inode, haddr, real_hash) != 0) goto error; @@ -217,8 +248,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, SetPageChecked(hpage); memcpy(_want_hash, haddr + hoffset, hsize); want_hash = _want_hash; - kunmap_local(haddr); - put_page(hpage); + fsverity_drop_block(inode, block); } /* Finally, verify the data block. */ @@ -235,10 +265,8 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, params->hash_alg->name, hsize, want_hash, params->hash_alg->name, hsize, real_hash); error: - for (; level > 0; level--) { - kunmap_local(hblocks[level - 1].addr); - put_page(hblocks[level - 1].page); - } + for (; level > 0; level--) + fsverity_drop_block(inode, &hblocks[level - 1].block); return false; } @@ -362,3 +390,42 @@ void __init fsverity_init_workqueue(void) if (!fsverity_read_workqueue) panic("failed to allocate fsverity_read_queue"); } + +/** + * fsverity_invalidate_block() - invalidate Merkle tree block + * @inode: inode to which this Merkle tree blocks belong + * @block: block to be invalidated + * + * This function invalidates/clears "verified" state of Merkle tree block + * in the fs-verity bitmap. The block needs to have ->offset set. + */ +void fsverity_invalidate_block(struct inode *inode, + struct fsverity_blockbuf *block) +{ + struct fsverity_info *vi = inode->i_verity_info; + const unsigned int log_blocksize = vi->tree_params.log_blocksize; + + if (block->offset > vi->tree_params.tree_size) { + fsverity_err(inode, +"Trying to invalidate beyond Merkle tree (tree %lld, offset %lld)", + vi->tree_params.tree_size, block->offset); + return; + } + + clear_bit(block->offset >> log_blocksize, vi->hash_block_verified); +} +EXPORT_SYMBOL_GPL(fsverity_invalidate_block); + +void fsverity_drop_block(struct inode *inode, + struct fsverity_blockbuf *block) +{ + if (inode->i_sb->s_vop->drop_block) + inode->i_sb->s_vop->drop_block(block); + else { + struct page *page = (struct page *)block->context; + + kunmap_local(block->kaddr); + put_page(page); + } + block->kaddr = NULL; +} diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index ac58b19f23d3..0973b521ac5a 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -26,6 +26,33 @@ /* Arbitrary limit to bound the kmalloc() size. Can be changed. */ #define FS_VERITY_MAX_DESCRIPTOR_SIZE 16384 +/** + * struct fsverity_blockbuf - Merkle Tree block buffer + * @kaddr: virtual address of the block's data + * @offset: block's offset into Merkle tree + * @size: the Merkle tree block size + * @context: filesystem private context + * + * Buffer containing single Merkle Tree block. These buffers are passed + * - to filesystem, when fs-verity is building merkel tree, + * - from filesystem, when fs-verity is reading merkle tree from a disk. + * Filesystems sets kaddr together with size to point to a memory which contains + * Merkle tree block. Same is done by fs-verity when Merkle tree is need to be + * written down to disk. + * + * While reading the tree, fs-verity calls ->read_merkle_tree_block followed by + * ->drop_block to let filesystem know that memory can be freed. + * + * The context is optional. This field can be used by filesystem to passthrough + * state from ->read_merkle_tree_block to ->drop_block. + */ +struct fsverity_blockbuf { + void *kaddr; + u64 offset; + unsigned int size; + void *context; +}; + /* Verity operations for filesystems */ struct fsverity_operations { @@ -107,6 +134,32 @@ struct fsverity_operations { pgoff_t index, unsigned long num_ra_pages); + /** + * Read a Merkle tree block of the given inode. + * @inode: the inode + * @pos: byte offset of the block within the Merkle tree + * @block: block buffer for filesystem to point it to the block + * @log_blocksize: log2 of the size of the expected block + * @ra_bytes: The number of bytes that should be + * prefetched starting at @pos if the page at @pos + * isn't already cached. Implementations may ignore this + * argument; it's only a performance optimization. + * + * This can be called at any time on an open verity file. It may be + * called by multiple processes concurrently. + * + * In case that block was evicted from the memory filesystem has to use + * fsverity_invalidate_block() to let fsverity know that block's + * verification state is not valid anymore. + * + * Return: 0 on success, -errno on failure + */ + int (*read_merkle_tree_block)(struct inode *inode, + u64 pos, + struct fsverity_blockbuf *block, + unsigned int log_blocksize, + u64 ra_bytes); + /** * Write a Merkle tree block to the given inode. * @@ -122,6 +175,16 @@ struct fsverity_operations { */ int (*write_merkle_tree_block)(struct inode *inode, const void *buf, u64 pos, unsigned int size); + + /** + * Release the reference to a Merkle tree block + * + * @block: the block to release + * + * This is called when fs-verity is done with a block obtained with + * ->read_merkle_tree_block(). + */ + void (*drop_block)(struct fsverity_blockbuf *block); }; #ifdef CONFIG_FS_VERITY @@ -175,6 +238,8 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg); bool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset); void fsverity_verify_bio(struct bio *bio); void fsverity_enqueue_verify_work(struct work_struct *work); +void fsverity_invalidate_block(struct inode *inode, + struct fsverity_blockbuf *block); #else /* !CONFIG_FS_VERITY */ From patchwork Sun Mar 17 16:25:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594579 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE1F71CA96; Sun, 17 Mar 2024 16:25:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692729; cv=none; b=C5BqTgtor5utUJgcA5KchhHRvNT+yxa8YW9uIf9jjHIdm6zjDQAtc5140DU6ToWMbjSVDjF1EQjnUXxIFwT7MKJurZhAeGRTeoT/yruDpnNXRypmt4pmqLWiFCrP6xxjuuBJs+rMrAeDgm+0DpUUSAE2C7sDDPSzf5GYhpmnZBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692729; c=relaxed/simple; bh=Jga8LsAuSK0NzpEyTkqZak5vw6dw9HXNVyIkYjY6U3U=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NQeFj0wEsFCaUw/8oX4U8lmEKfAUlTvIOv3dAvFzEkXsga5NopvcMNUl4cOvU/oADjhQVDZCrvNRq3+COaMI1JiKwDowDShqxGvmBp4ot0i2kGUUN0C23zwtdoWHjOAU+1nws12xdbCulYd/0JIltf+/j0TLi7cDVlrJnVeeiic= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GrcYiPzK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GrcYiPzK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 85AB5C433C7; Sun, 17 Mar 2024 16:25:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692729; bh=Jga8LsAuSK0NzpEyTkqZak5vw6dw9HXNVyIkYjY6U3U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GrcYiPzKJJPjCgQ8Ax70h1yS1k9o+AQRwblgBWMUX75n1ol3d2I2Cl1Lfnn+UJNWf joDSxSDrEJUdyQp4n+omFSMjWR+iXlP+uWrygzcWuaDU1mRcuH8qRtZJpztg0rYFf9 JQy9FGpeDvFmEHSr9AhQvzof0Hq3KXwz6z9eSWTDXop161Q0iabyJSojM5i8HjlHZf xxGBvWI+Q0219EjIcoOOhxvLZoeAfXqrPNp8TtYnIDBIzDnBEKttecOq5yK48IMsLG YRAfePD2YqSp2szB+3+Ld5xtgSqI8yNvNT7EHIJawMNYnU27yYZMUV8d9URJ7SMv0N +foZzot8X1ECA== Date: Sun, 17 Mar 2024 09:25:29 -0700 Subject: [PATCH 08/40] fsverity: add per-sb workqueue for post read processing From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246042.2684506.11798514410282707478.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn For XFS, fsverity's global workqueue is not really suitable due to: 1. High priority workqueues are used within XFS to ensure that data IO completion cannot stall processing of journal IO completions. Hence using a WQ_HIGHPRI workqueue directly in the user data IO path is a potential filesystem livelock/deadlock vector. 2. The fsverity workqueue is global - it creates a cross-filesystem contention point. This patch adds per-filesystem, per-cpu workqueue for fsverity work. This allows iomap to add verification work in the read path on BIO completion. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/super.c | 7 +++++++ include/linux/fs.h | 2 ++ include/linux/fsverity.h | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/fs/super.c b/fs/super.c index d35e85295489..338d86864200 100644 --- a/fs/super.c +++ b/fs/super.c @@ -642,6 +642,13 @@ void generic_shutdown_super(struct super_block *sb) sb->s_dio_done_wq = NULL; } +#ifdef CONFIG_FS_VERITY + if (sb->s_read_done_wq) { + destroy_workqueue(sb->s_read_done_wq); + sb->s_read_done_wq = NULL; + } +#endif + if (sop->put_super) sop->put_super(sb); diff --git a/include/linux/fs.h b/include/linux/fs.h index ed5966a70495..9db24a825d94 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1221,6 +1221,8 @@ struct super_block { #endif #ifdef CONFIG_FS_VERITY const struct fsverity_operations *s_vop; + /* Completion queue for post read verification */ + struct workqueue_struct *s_read_done_wq; #endif #if IS_ENABLED(CONFIG_UNICODE) struct unicode_map *s_encoding; diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 0973b521ac5a..45b7c613148a 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -241,6 +241,22 @@ void fsverity_enqueue_verify_work(struct work_struct *work); void fsverity_invalidate_block(struct inode *inode, struct fsverity_blockbuf *block); +static inline int fsverity_set_ops(struct super_block *sb, + const struct fsverity_operations *ops) +{ + sb->s_vop = ops; + + /* Create per-sb workqueue for post read bio verification */ + struct workqueue_struct *wq = alloc_workqueue( + "pread/%s", (WQ_FREEZABLE | WQ_MEM_RECLAIM), 0, sb->s_id); + if (!wq) + return -ENOMEM; + + sb->s_read_done_wq = wq; + + return 0; +} + #else /* !CONFIG_FS_VERITY */ static inline struct fsverity_info *fsverity_get_info(const struct inode *inode) @@ -318,6 +334,12 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work) WARN_ON_ONCE(1); } +static inline int fsverity_set_ops(struct super_block *sb, + const struct fsverity_operations *ops) +{ + return -EOPNOTSUPP; +} + #endif /* !CONFIG_FS_VERITY */ static inline bool fsverity_verify_folio(struct folio *folio) From patchwork Sun Mar 17 16:25:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594580 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C66B1CA96; Sun, 17 Mar 2024 16:25:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692745; cv=none; b=noUViSZSp8SvXusLi80lkWIkWA4XakSVLJcF1BWJ1sIfyp0awX/tsfqAyZkTkD7U29iShUDRhjSd+3K6HuHhM7icrpcHSnLQJOf3hpKyBnI2AqA9bz6lOyVNbxedveHsJs781SFKuzQ3ZK9RWZAjDz0ejT4IS68hpOywmhV0Tmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692745; c=relaxed/simple; bh=Cfc8Wh5ih1PbHmvtZBPxYw2Ha/gR/b+FltBbCXvcgOg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DLuDvA3/upwG6HJTCNxkUpxJlVxQ0bKqgMqT4JzwfIsP2gAZBNgFOYpRr+NjdKQWlBdNUcwF9J9WG51f8+NeF9rtLyVvUkNQuNnltT57TY1dr8pYCAC+XAFDVIve8j9rxWtELMqZT+t/lqvqZ25dB1osqcTfp9tB2CQRq3t7WF4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VRUnyVa+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VRUnyVa+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3353DC433F1; Sun, 17 Mar 2024 16:25:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692745; bh=Cfc8Wh5ih1PbHmvtZBPxYw2Ha/gR/b+FltBbCXvcgOg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=VRUnyVa++bUANWWVC2r5Y/H+XYAoP1N1Tumj+ZOkUK2G61tpHDWlzkKLxygy9Swsf fCP5DIGVVI6TjaCBFViqSkBmpBF99CwqbZx4U/VFmgYEhRsE40CpqD4n2IHbT9aUWt hanGEZZnj1Z8y9gJHHx86VRt53oIeIgR2ob2sEGiqMjbqLZsK+1X7i/PHux7VVsZek 4orZSy5mv+8Aika/Gd8f+jJGyPiWQToMwH2mbXROfpzI24R2y92XGiW5ylXbm00XY+ 92BuSwDwumETg+6iskx23U8HxD8Fv5NVsNk3XwjT/aL5xsTLa48GY6+2O/DPfjAQiT V0FiwRwKLUZfQ== Date: Sun, 17 Mar 2024 09:25:44 -0700 Subject: [PATCH 09/40] fsverity: add tracepoints From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246058.2684506.7555243071805760927.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn fs-verity previously had debug printk but it was removed. This patch adds trace points to the same places where printk were used (with a few additional ones). Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: fix formatting] Signed-off-by: Darrick J. Wong --- MAINTAINERS | 1 fs/verity/enable.c | 3 + fs/verity/fsverity_private.h | 2 fs/verity/init.c | 1 fs/verity/signature.c | 2 fs/verity/verify.c | 7 ++ include/trace/events/fsverity.h | 181 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 197 insertions(+) create mode 100644 include/trace/events/fsverity.h diff --git a/MAINTAINERS b/MAINTAINERS index 73d898383e51..f735d3e68514 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8740,6 +8740,7 @@ T: git https://git.kernel.org/pub/scm/fs/fsverity/linux.git F: Documentation/filesystems/fsverity.rst F: fs/verity/ F: include/linux/fsverity.h +F: include/trace/events/fsverity.h F: include/uapi/linux/fsverity.h FT260 FTDI USB-HID TO I2C BRIDGE DRIVER diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 04e060880b79..945eba0092ab 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -227,6 +227,8 @@ static int enable_verity(struct file *filp, if (err) goto out; + trace_fsverity_enable(inode, desc, ¶ms); + /* * Start enabling verity on this file, serialized by the inode lock. * Fail if verity is already enabled or is already being enabled. @@ -255,6 +257,7 @@ static int enable_verity(struct file *filp, fsverity_err(inode, "Error %d building Merkle tree", err); goto rollback; } + trace_fsverity_tree_done(inode, desc, ¶ms); /* * Create the fsverity_info. Don't bother trying to save work by diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index dad33e6ff0d6..fd8f5a8d1f6a 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -162,4 +162,6 @@ void __init fsverity_init_workqueue(void); void fsverity_drop_block(struct inode *inode, struct fsverity_blockbuf *block); +#include + #endif /* _FSVERITY_PRIVATE_H */ diff --git a/fs/verity/init.c b/fs/verity/init.c index cb2c9aac61ed..3769d2dc9e3b 100644 --- a/fs/verity/init.c +++ b/fs/verity/init.c @@ -5,6 +5,7 @@ * Copyright 2019 Google LLC */ +#define CREATE_TRACE_POINTS #include "fsverity_private.h" #include diff --git a/fs/verity/signature.c b/fs/verity/signature.c index 90c07573dd77..c1f08bb32ed1 100644 --- a/fs/verity/signature.c +++ b/fs/verity/signature.c @@ -53,6 +53,8 @@ int fsverity_verify_signature(const struct fsverity_info *vi, struct fsverity_formatted_digest *d; int err; + trace_fsverity_verify_signature(inode, signature, sig_size); + if (sig_size == 0) { if (fsverity_require_signatures) { fsverity_err(inode, diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 4ebdf9d2d7b6..aa1763e8b723 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -118,6 +118,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, /* Byte offset of the wanted hash relative to @addr */ unsigned int hoffset; } hblocks[FS_VERITY_MAX_LEVELS]; + trace_fsverity_verify_block(inode, data_pos); /* * The index of the previous level's block within that level; also the * index of that block's hash within the current level. @@ -215,6 +216,8 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, if (is_hash_block_verified(inode, block, hblock_idx)) { memcpy(_want_hash, block->kaddr + hoffset, hsize); want_hash = _want_hash; + trace_fsverity_merkle_tree_block_verified(inode, + block, FSVERITY_TRACE_DIR_ASCEND); fsverity_drop_block(inode, block); goto descend; } @@ -248,6 +251,8 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, SetPageChecked(hpage); memcpy(_want_hash, haddr + hoffset, hsize); want_hash = _want_hash; + trace_fsverity_merkle_tree_block_verified(inode, block, + FSVERITY_TRACE_DIR_DESCEND); fsverity_drop_block(inode, block); } @@ -405,6 +410,8 @@ void fsverity_invalidate_block(struct inode *inode, struct fsverity_info *vi = inode->i_verity_info; const unsigned int log_blocksize = vi->tree_params.log_blocksize; + trace_fsverity_invalidate_block(inode, block); + if (block->offset > vi->tree_params.tree_size) { fsverity_err(inode, "Trying to invalidate beyond Merkle tree (tree %lld, offset %lld)", diff --git a/include/trace/events/fsverity.h b/include/trace/events/fsverity.h new file mode 100644 index 000000000000..763890e47358 --- /dev/null +++ b/include/trace/events/fsverity.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM fsverity + +#if !defined(_TRACE_FSVERITY_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FSVERITY_H + +#include + +struct fsverity_descriptor; +struct merkle_tree_params; +struct fsverity_info; + +#define FSVERITY_TRACE_DIR_ASCEND (1ul << 0) +#define FSVERITY_TRACE_DIR_DESCEND (1ul << 1) +#define FSVERITY_HASH_SHOWN_LEN 20 + +TRACE_EVENT(fsverity_enable, + TP_PROTO(struct inode *inode, struct fsverity_descriptor *desc, + struct merkle_tree_params *params), + TP_ARGS(inode, desc, params), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(u64, data_size) + __field(unsigned int, block_size) + __field(unsigned int, num_levels) + __field(u64, tree_size) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->data_size = desc->data_size; + __entry->block_size = params->block_size; + __entry->num_levels = params->num_levels; + __entry->tree_size = params->tree_size; + ), + TP_printk("ino %lu data size %llu tree size %llu block size %u levels %u", + (unsigned long) __entry->ino, + __entry->data_size, + __entry->tree_size, + __entry->block_size, + __entry->num_levels) +); + +TRACE_EVENT(fsverity_tree_done, + TP_PROTO(struct inode *inode, struct fsverity_descriptor *desc, + struct merkle_tree_params *params), + TP_ARGS(inode, desc, params), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(unsigned int, levels) + __field(unsigned int, tree_blocks) + __field(u64, tree_size) + __array(u8, tree_hash, 64) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->levels = params->num_levels; + __entry->tree_blocks = + params->tree_size >> params->log_blocksize; + __entry->tree_size = params->tree_size; + memcpy(__entry->tree_hash, desc->root_hash, 64); + ), + TP_printk("ino %lu levels %d tree_blocks %d tree_size %lld root_hash %s", + (unsigned long) __entry->ino, + __entry->levels, + __entry->tree_blocks, + __entry->tree_size, + __print_hex(__entry->tree_hash, 64)) +); + +TRACE_EVENT(fsverity_verify_block, + TP_PROTO(struct inode *inode, u64 offset), + TP_ARGS(inode, offset), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(u64, offset) + __field(unsigned int, block_size) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->offset = offset; + __entry->block_size = + inode->i_verity_info->tree_params.block_size; + ), + TP_printk("ino %lu data offset %lld data block size %u", + (unsigned long) __entry->ino, + __entry->offset, + __entry->block_size) +); + +TRACE_EVENT(fsverity_merkle_tree_block_verified, + TP_PROTO(struct inode *inode, + struct fsverity_blockbuf *block, + u8 direction), + TP_ARGS(inode, block, direction), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(u64, offset) + __field(u8, direction) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->offset = block->offset; + __entry->direction = direction; + ), + TP_printk("ino %lu block offset %llu %s", + (unsigned long) __entry->ino, + __entry->offset, + __entry->direction == 0 ? "ascend" : "descend") +); + +TRACE_EVENT(fsverity_invalidate_block, + TP_PROTO(struct inode *inode, struct fsverity_blockbuf *block), + TP_ARGS(inode, block), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(u64, offset) + __field(unsigned int, block_size) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->offset = block->offset; + __entry->block_size = block->size; + ), + TP_printk("ino %lu block position %llu block size %u", + (unsigned long) __entry->ino, + __entry->offset, + __entry->block_size) +); + +TRACE_EVENT(fsverity_read_merkle_tree_block, + TP_PROTO(struct inode *inode, u64 offset, unsigned int log_blocksize), + TP_ARGS(inode, offset, log_blocksize), + TP_STRUCT__entry( + __field(ino_t, ino) + __field(u64, offset) + __field(u64, index) + __field(unsigned int, block_size) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + __entry->offset = offset; + __entry->index = offset >> log_blocksize; + __entry->block_size = 1 << log_blocksize; + ), + TP_printk("ino %lu tree offset %llu block index %llu block hize %u", + (unsigned long) __entry->ino, + __entry->offset, + __entry->index, + __entry->block_size) +); + +TRACE_EVENT(fsverity_verify_signature, + TP_PROTO(const struct inode *inode, const u8 *signature, size_t sig_size), + TP_ARGS(inode, signature, sig_size), + TP_STRUCT__entry( + __field(ino_t, ino) + __dynamic_array(u8, signature, sig_size) + __field(size_t, sig_size) + __field(size_t, sig_size_show) + ), + TP_fast_assign( + __entry->ino = inode->i_ino; + memcpy(__get_dynamic_array(signature), signature, sig_size); + __entry->sig_size = sig_size; + __entry->sig_size_show = (sig_size > FSVERITY_HASH_SHOWN_LEN ? + FSVERITY_HASH_SHOWN_LEN : sig_size); + ), + TP_printk("ino %lu sig_size %zu %s%s%s", + (unsigned long) __entry->ino, + __entry->sig_size, + (__entry->sig_size ? "sig " : ""), + __print_hex(__get_dynamic_array(signature), + __entry->sig_size_show), + (__entry->sig_size ? "..." : "")) +); + +#endif /* _TRACE_FSVERITY_H */ + +/* This part must be outside protection */ +#include From patchwork Sun Mar 17 16:26:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594581 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F36661CA96; Sun, 17 Mar 2024 16:26:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692761; cv=none; b=Ktk0fv+dTvW5Cj9a1K/MBCbXKGQrp9S0/m0P0JK3nGbHnFK9L8S5Nb9KxBhu1Ki8kpyIQXWN0uAkimnJlYqcEUlCi4CFs55HUg4RiJvJZ3yghL1Xsb/WXxj5ZSBJbqCFwzDqh5UUuX+aCn54PwOZCmZPgYkhh0JFX2hNq42ldRA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692761; c=relaxed/simple; bh=8uxd87nDK26U75DT/QB9AwLkCWL2IwnONr4z5q81X38=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jftauzkGxaC6LBlCOHwyCBskGslU+W+ceEjW2l4JV25iQDNkr+uDKboi4vED5jc7kehkEZVn2zkVUG/XpWRlUr/WSZ1zO40T5F0w+N/0G6/fHyp3dtRWTZrOa6W7KH9JhJDCoovT93EEjuipJwRMx1MXrQ4/YdwHX4OENXErRK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=swpRlvi9; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="swpRlvi9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C508FC433C7; Sun, 17 Mar 2024 16:26:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692760; bh=8uxd87nDK26U75DT/QB9AwLkCWL2IwnONr4z5q81X38=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=swpRlvi9g/mDv4wdGEEts48igsmFQrfDKD8C+BGTQH0/8oqBYlbrUBH1EmC+hhRFX H77n1kgZEUSIOMlUt7m3VwnqsiDkNtPZoa9tB56NF+JYh12Vpxk/KLUemy6Uc5Uikd nPyjav4LVzuEjhf9kXmbT3ZYRRU/nK7qNegLFGR4/Ncm1t/gHaizzscO9rMhFstgBa jwOWNKzWgDi7ap/nLQOTQxuVEsVsdWPwyE/iba4lZTnCa5EHMnCZ+vS0m06f60JU2c wUJcRdcXyvWruG2fxKA5oAw5oUXHklZLDScA4Pyz07qKCkCbOMljG9mD7z7PSiWF28 B9jGJIyMWOYUg== Date: Sun, 17 Mar 2024 09:26:00 -0700 Subject: [PATCH 10/40] fsverity: fix "support block-based Merkle tree caching" From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246075.2684506.7773764773347292529.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Various fixes recommended by the maintainer. Signed-off-by: Darrick J. Wong --- fs/verity/fsverity_private.h | 36 ++++++++++- fs/verity/open.c | 9 +-- fs/verity/read_metadata.c | 63 ++++++------------- fs/verity/verify.c | 141 ++++++++++++++++++++++++------------------ include/linux/fsverity.h | 24 +++++-- 5 files changed, 151 insertions(+), 122 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index fd8f5a8d1f6a..0a4381acb394 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -154,13 +154,41 @@ static inline void fsverity_init_signature(void) void __init fsverity_init_workqueue(void); +static inline bool fsverity_caches_blocks(const struct inode *inode) +{ + const struct fsverity_operations *vops = inode->i_sb->s_vop; + + WARN_ON_ONCE(vops->read_merkle_tree_block && + !vops->drop_merkle_tree_block); + + return vops->read_merkle_tree_block != NULL; +} + +static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi, + const struct inode *inode) +{ + /* + * If fs uses block-based Merkle tree caching, then fs-verity must use + * hash_block_verified bitmap as there's no page to mark it with + * PG_checked. + */ + if (vi->tree_params.block_size != PAGE_SIZE) + return true; + return fsverity_caches_blocks(inode); +} + +int fsverity_read_merkle_tree_block(struct inode *inode, + const struct merkle_tree_params *params, + u64 pos, unsigned long ra_bytes, + struct fsverity_blockbuf *block); + /* * Drop 'block' obtained with ->read_merkle_tree_block(). Calls out back to - * filesystem if ->drop_block() is set, otherwise, drop the reference in the - * block->context. + * filesystem if ->drop_merkle_tree_block() is set, otherwise, drop the + * reference in the block->context. */ -void fsverity_drop_block(struct inode *inode, - struct fsverity_blockbuf *block); +void fsverity_drop_merkle_tree_block(struct inode *inode, + struct fsverity_blockbuf *block); #include diff --git a/fs/verity/open.c b/fs/verity/open.c index 6e6922b4b014..9603b3a404f7 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -214,12 +214,11 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, goto fail; /* - * If fs passes Merkle tree blocks to fs-verity (e.g. XFS), then - * fs-verity should use hash_block_verified bitmap as there's no page - * to mark it with PG_checked. + * If fs uses block-based Merkle tree cachin, then fs-verity must use + * hash_block_verified bitmap as there's no page to mark it with + * PG_checked. */ - if (vi->tree_params.block_size != PAGE_SIZE || - inode->i_sb->s_vop->read_merkle_tree_block) { + if (fsverity_uses_bitmap(vi, inode)) { /* * When the Merkle tree block size and page size differ, we use * a bitmap to keep track of which hash blocks have been diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c index 5da40b5a81af..94fffa060f82 100644 --- a/fs/verity/read_metadata.c +++ b/fs/verity/read_metadata.c @@ -14,76 +14,53 @@ static int fsverity_read_merkle_tree(struct inode *inode, const struct fsverity_info *vi, - void __user *buf, u64 offset, int length) + void __user *buf, u64 pos, int length) { - const struct fsverity_operations *vops = inode->i_sb->s_vop; - u64 end_offset; - unsigned int offs_in_block; - pgoff_t index, last_index; + const u64 end_pos = min(pos + length, vi->tree_params.tree_size); + const struct merkle_tree_params *params = &vi->tree_params; + unsigned int offs_in_block = pos & (params->block_size - 1); int retval = 0; int err = 0; - const unsigned int block_size = vi->tree_params.block_size; - const u8 log_blocksize = vi->tree_params.log_blocksize; - end_offset = min(offset + length, vi->tree_params.tree_size); - if (offset >= end_offset) + if (pos >= end_pos) return 0; - offs_in_block = offset & (block_size - 1); - last_index = (end_offset - 1) >> log_blocksize; /* * Iterate through each Merkle tree block in the requested range and * copy the requested portion to userspace. Note that we are returning * a byte stream. */ - for (index = offset >> log_blocksize; index <= last_index; index++) { - unsigned long num_ra_pages = - min_t(unsigned long, last_index - index + 1, - inode->i_sb->s_bdi->io_pages); - unsigned int bytes_to_copy = min_t(u64, end_offset - offset, - block_size - offs_in_block); + while (pos < end_pos) { + unsigned long ra_bytes; + unsigned int bytes_to_copy; struct fsverity_blockbuf block = { - .size = block_size, + .size = params->block_size, }; - if (!vops->read_merkle_tree_block) { - unsigned int blocks_per_page = - vi->tree_params.blocks_per_page; - unsigned long page_idx = - round_down(index, blocks_per_page); - struct page *page = vops->read_merkle_tree_page(inode, - page_idx, num_ra_pages); - - if (IS_ERR(page)) { - err = PTR_ERR(page); - } else { - block.kaddr = kmap_local_page(page) + - ((index - page_idx) << log_blocksize); - block.context = page; - } - } else { - err = vops->read_merkle_tree_block(inode, - index << log_blocksize, - &block, log_blocksize, num_ra_pages); - } + ra_bytes = min_t(unsigned long, end_pos - pos + 1, + inode->i_sb->s_bdi->io_pages << PAGE_SHIFT); + bytes_to_copy = min_t(u64, end_pos - pos, + params->block_size - offs_in_block); + err = fsverity_read_merkle_tree_block(inode, &vi->tree_params, + pos - offs_in_block, ra_bytes, &block); if (err) { fsverity_err(inode, - "Error %d reading Merkle tree block %lu", - err, index << log_blocksize); + "Error %d reading Merkle tree block %llu", + err, pos); break; } if (copy_to_user(buf, block.kaddr + offs_in_block, bytes_to_copy)) { - fsverity_drop_block(inode, &block); + fsverity_drop_merkle_tree_block(inode, &block); err = -EFAULT; break; } - fsverity_drop_block(inode, &block); + fsverity_drop_merkle_tree_block(inode, &block); retval += bytes_to_copy; buf += bytes_to_copy; - offset += bytes_to_copy; + pos += bytes_to_copy; if (fatal_signal_pending(current)) { err = -EINTR; diff --git a/fs/verity/verify.c b/fs/verity/verify.c index aa1763e8b723..6c4c73eeccea 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -23,7 +23,18 @@ static bool is_hash_block_verified(struct inode *inode, unsigned int blocks_per_page; unsigned int i; struct fsverity_info *vi = inode->i_verity_info; - struct page *hpage = (struct page *)block->context; + struct page *hpage; + + /* + * If the filesystem uses block-based caching, then + * ->hash_block_verified is always used and the filesystem pushes + * invalidations to it as needed. + */ + if (fsverity_caches_blocks(inode)) + return test_bit(hblock_idx, vi->hash_block_verified); + + /* Otherwise, the filesystem uses page-based caching. */ + hpage = (struct page *)block->context; /* * When the Merkle tree block size and page size are the same, then the @@ -34,15 +45,9 @@ static bool is_hash_block_verified(struct inode *inode, * get evicted and re-instantiated from the backing storage, as new * pages always start out with PG_checked cleared. */ - if (!vi->hash_block_verified) + if (!fsverity_uses_bitmap(vi, inode)) return PageChecked(hpage); - /* - * Filesystems which use block based caching (e.g. XFS) always use - * bitmap. - */ - if (inode->i_sb->s_vop->read_merkle_tree_block) - return test_bit(hblock_idx, vi->hash_block_verified); /* * When the Merkle tree block size and page size differ, we use a bitmap * to indicate whether each hash block has been verified. @@ -99,13 +104,13 @@ static bool is_hash_block_verified(struct inode *inode, */ static bool verify_data_block(struct inode *inode, struct fsverity_info *vi, - const void *data, u64 data_pos, unsigned long max_ra_pages) + const void *data, u64 data_pos, unsigned long max_ra_bytes) { const struct merkle_tree_params *params = &vi->tree_params; const unsigned int hsize = params->digest_size; int level; int err = 0; - int num_ra_pages; + unsigned long ra_bytes; u8 _want_hash[FS_VERITY_MAX_DIGEST_SIZE]; const u8 *want_hash; u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE]; @@ -153,11 +158,8 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, for (level = 0; level < params->num_levels; level++) { unsigned long next_hidx; unsigned long hblock_idx; - pgoff_t hpage_idx; u64 hblock_pos; - unsigned int hblock_offset_in_page; unsigned int hoffset; - struct page *hpage; struct fsverity_blockbuf *block = &hblocks[level].block; /* @@ -169,47 +171,25 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, /* Index of the hash block in the tree overall */ hblock_idx = params->level_start[level] + next_hidx; - /* Index of the hash page in the tree overall */ - hpage_idx = hblock_idx >> params->log_blocks_per_page; - - /* Byte offset of the hash block within the page */ - hblock_offset_in_page = - (hblock_idx << params->log_blocksize) & ~PAGE_MASK; - - /* Offset of the Merkle tree block into the tree */ + /* Byte offset of the hash block in the tree overall */ hblock_pos = hblock_idx << params->log_blocksize; /* Byte offset of the hash within the block */ hoffset = (hidx << params->log_digestsize) & (params->block_size - 1); - num_ra_pages = level == 0 ? - min(max_ra_pages, params->tree_pages - hpage_idx) : 0; - - if (inode->i_sb->s_vop->read_merkle_tree_block) { - err = inode->i_sb->s_vop->read_merkle_tree_block( - inode, hblock_pos, block, params->log_blocksize, - num_ra_pages); - } else { - unsigned int blocks_per_page = - vi->tree_params.blocks_per_page; - hblock_idx = round_down(hblock_idx, blocks_per_page); - hpage = inode->i_sb->s_vop->read_merkle_tree_page( - inode, hpage_idx, (num_ra_pages << PAGE_SHIFT)); - - if (IS_ERR(hpage)) { - err = PTR_ERR(hpage); - } else { - block->kaddr = kmap_local_page(hpage) + - hblock_offset_in_page; - block->context = hpage; - } - } + if (level == 0) + ra_bytes = min(max_ra_bytes, + params->tree_size - hblock_pos); + else + ra_bytes = 0; + err = fsverity_read_merkle_tree_block(inode, params, hblock_pos, + ra_bytes, block); if (err) { fsverity_err(inode, - "Error %d reading Merkle tree block %lu", - err, hblock_idx); + "Error %d reading Merkle tree block %llu", + err, hblock_pos); goto error; } @@ -218,7 +198,7 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, want_hash = _want_hash; trace_fsverity_merkle_tree_block_verified(inode, block, FSVERITY_TRACE_DIR_ASCEND); - fsverity_drop_block(inode, block); + fsverity_drop_merkle_tree_block(inode, block); goto descend; } hblocks[level].index = hblock_idx; @@ -234,7 +214,6 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, const void *haddr = block->kaddr; unsigned long hblock_idx = hblocks[level - 1].index; unsigned int hoffset = hblocks[level - 1].hoffset; - struct page *hpage = (struct page *)block->context; if (fsverity_hash_block(params, inode, haddr, real_hash) != 0) goto error; @@ -245,15 +224,15 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, * idempotent, as the same hash block might be verified by * multiple threads concurrently. */ - if (vi->hash_block_verified) + if (fsverity_uses_bitmap(vi, inode)) set_bit(hblock_idx, vi->hash_block_verified); else - SetPageChecked(hpage); + SetPageChecked((struct page *)block->context); memcpy(_want_hash, haddr + hoffset, hsize); want_hash = _want_hash; trace_fsverity_merkle_tree_block_verified(inode, block, FSVERITY_TRACE_DIR_DESCEND); - fsverity_drop_block(inode, block); + fsverity_drop_merkle_tree_block(inode, block); } /* Finally, verify the data block. */ @@ -271,13 +250,13 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, params->hash_alg->name, hsize, real_hash); error: for (; level > 0; level--) - fsverity_drop_block(inode, &hblocks[level - 1].block); + fsverity_drop_merkle_tree_block(inode, &hblocks[level - 1].block); return false; } static bool verify_data_blocks(struct folio *data_folio, size_t len, size_t offset, - unsigned long max_ra_pages) + unsigned long max_ra_bytes) { struct inode *inode = data_folio->mapping->host; struct fsverity_info *vi = inode->i_verity_info; @@ -295,7 +274,7 @@ verify_data_blocks(struct folio *data_folio, size_t len, size_t offset, data = kmap_local_folio(data_folio, offset); valid = verify_data_block(inode, vi, data, pos + offset, - max_ra_pages); + max_ra_bytes); kunmap_local(data); if (!valid) return false; @@ -358,7 +337,7 @@ void fsverity_verify_bio(struct bio *bio) bio_for_each_folio_all(fi, bio) { if (!verify_data_blocks(fi.folio, fi.length, fi.offset, - max_ra_pages)) { + max_ra_pages << PAGE_SHIFT)) { bio->bi_status = BLK_STS_IOERR; break; } @@ -412,7 +391,7 @@ void fsverity_invalidate_block(struct inode *inode, trace_fsverity_invalidate_block(inode, block); - if (block->offset > vi->tree_params.tree_size) { + if (block->offset >= vi->tree_params.tree_size) { fsverity_err(inode, "Trying to invalidate beyond Merkle tree (tree %lld, offset %lld)", vi->tree_params.tree_size, block->offset); @@ -423,16 +402,54 @@ void fsverity_invalidate_block(struct inode *inode, } EXPORT_SYMBOL_GPL(fsverity_invalidate_block); -void fsverity_drop_block(struct inode *inode, - struct fsverity_blockbuf *block) +/** + * fsverity_read_merkle_tree_block() - read Merkle tree block + * @inode: inode to which this Merkle tree blocks belong + * @params: merkle tree parameters + * @pos: byte position within merkle tree + * @ra_bytes: try to read ahead this many btes + * @block: block to be loaded + * + * This function loads data from a merkle tree. + */ +int fsverity_read_merkle_tree_block(struct inode *inode, + const struct merkle_tree_params *params, + u64 pos, unsigned long ra_bytes, + struct fsverity_blockbuf *block) { - if (inode->i_sb->s_vop->drop_block) - inode->i_sb->s_vop->drop_block(block); - else { - struct page *page = (struct page *)block->context; + const struct fsverity_operations *vops = inode->i_sb->s_vop; + unsigned long page_idx; + struct page *page; + unsigned long index; + unsigned int offset_in_page; + if (fsverity_caches_blocks(inode)) + return vops->read_merkle_tree_block(inode, pos, ra_bytes, + params->log_blocksize, block); + + index = pos >> params->log_blocksize; + page_idx = round_down(index, params->blocks_per_page); + offset_in_page = pos & ~PAGE_MASK; + + page = vops->read_merkle_tree_page(inode, page_idx, + ra_bytes >> PAGE_SHIFT); + if (IS_ERR(page)) + return PTR_ERR(page); + + block->kaddr = kmap_local_page(page) + offset_in_page; + block->context = page; + return 0; +} + +void fsverity_drop_merkle_tree_block(struct inode *inode, + struct fsverity_blockbuf *block) +{ + if (fsverity_caches_blocks(inode)) { + inode->i_sb->s_vop->drop_merkle_tree_block(block); + } else { kunmap_local(block->kaddr); - put_page(page); + put_page((struct page *)block->context); } block->kaddr = NULL; + block->context = NULL; } diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 45b7c613148a..0af2cd1860e4 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -41,10 +41,10 @@ * written down to disk. * * While reading the tree, fs-verity calls ->read_merkle_tree_block followed by - * ->drop_block to let filesystem know that memory can be freed. + * ->drop_merkle_tree_block to let filesystem know that memory can be freed. * * The context is optional. This field can be used by filesystem to passthrough - * state from ->read_merkle_tree_block to ->drop_block. + * state from ->read_merkle_tree_block to ->drop_merkle_tree_block. */ struct fsverity_blockbuf { void *kaddr; @@ -128,6 +128,9 @@ struct fsverity_operations { * * Note that this must retrieve a *page*, not necessarily a *block*. * + * If this function is implemented, do not implement + * ->read_merkle_tree_block or ->drop_merkle_tree_block. + * * Return: the page on success, ERR_PTR() on failure */ struct page *(*read_merkle_tree_page)(struct inode *inode, @@ -138,12 +141,12 @@ struct fsverity_operations { * Read a Merkle tree block of the given inode. * @inode: the inode * @pos: byte offset of the block within the Merkle tree - * @block: block buffer for filesystem to point it to the block - * @log_blocksize: log2 of the size of the expected block * @ra_bytes: The number of bytes that should be * prefetched starting at @pos if the page at @pos * isn't already cached. Implementations may ignore this * argument; it's only a performance optimization. + * @log_blocksize: log2 of the size of the expected block + * @block: block buffer for filesystem to point it to the block * * This can be called at any time on an open verity file. It may be * called by multiple processes concurrently. @@ -152,13 +155,15 @@ struct fsverity_operations { * fsverity_invalidate_block() to let fsverity know that block's * verification state is not valid anymore. * + * If this function is implemented, ->drop_merkle_tree_block must also + * be implemented. + * * Return: 0 on success, -errno on failure */ int (*read_merkle_tree_block)(struct inode *inode, - u64 pos, - struct fsverity_blockbuf *block, + u64 pos, unsigned long ra_bytes, unsigned int log_blocksize, - u64 ra_bytes); + struct fsverity_blockbuf *block); /** * Write a Merkle tree block to the given inode. @@ -183,8 +188,11 @@ struct fsverity_operations { * * This is called when fs-verity is done with a block obtained with * ->read_merkle_tree_block(). + * + * If this function is implemented, ->read_merkle_tree_block must also + * be implemented. */ - void (*drop_block)(struct fsverity_blockbuf *block); + void (*drop_merkle_tree_block)(struct fsverity_blockbuf *block); }; #ifdef CONFIG_FS_VERITY From patchwork Sun Mar 17 16:26:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594582 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F5A71CA96; Sun, 17 Mar 2024 16:26:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692776; cv=none; b=t/LfEoo0tfodiW84jK3BlKwrYzxQuisypagjeXPpG5kTbKnDZCft2L5+rzpc7qgviqjkt7ZJau8Bl9nTJ7mp3ntFbnFEcEYh3ECwEu6XjadwSLHH5PTctd0UG7KqgzAnkAX5TzkVZsTPovcKrppojpWTSOFjiZkmCOhVc4h8EaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692776; c=relaxed/simple; bh=1MnT1ZpW/vtlTpR5rEaheiz7VcBK8zfu40pO4zxZE80=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RMimkdm/pWv+eBnnsH3X1KlRNwuYGXII0h5OBsH2+k7w9pASahdW4KzpMYDOkRDUZAnhXfIbhEcDqd8PG94gVRoivBChJtkosaNh5p9rUhkBt4mqBAXapDMx2K5d+/GJRLpoLhpH+QWfqLCglO3ynSe7lLdKRRcxL+1igJ6iK2g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DE3ViPr6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DE3ViPr6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 72D63C433C7; Sun, 17 Mar 2024 16:26:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692776; bh=1MnT1ZpW/vtlTpR5rEaheiz7VcBK8zfu40pO4zxZE80=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=DE3ViPr6L+WX8jwJCwfE1dRLWF6rjUlgaJe9+uRDM1696nJlNoNbtyPZ5VN+RS8V7 zeDf0dWFUAkghBjFeVpsL+PS0VEPXIZW7IIAdajwYPHzl5+PQoW9SkLQOboOlbLvuH NM80a0KjegHZSy+WOO0GzKCWeZNQ5Ygy4fSYbEhhQ4kplIf4cfL4qn5zx7STMqnwFg NQbEIX5OHxrz+uVQ92+zEECPsnDelxIxZ7qHl/+4nDzLPk1zRc4c9AHoQiiG13sT3d 4atiw2ygmYBfQ9sLtxJNDp5GEI+S1e2BJVfvVf/zR5XUKCgsc5q/bdzRLk7JslyIDz ca32dHj6HzxMw== Date: Sun, 17 Mar 2024 09:26:15 -0700 Subject: [PATCH 11/40] fsverity: send the level of the merkle tree block to ->read_merkle_tree_block From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246091.2684506.5112587026905062339.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong When fsverity needs to pull in a merkle tree block for file data verification, it knows the level of the block within the tree. For XFS, we will cache the blocks in memory ourselves, and it is advantageous to make higher level nodes more resistant to memory reclamation. Therefore, we need to pass the anticipated level to the ->read_merkle_tree_block functions to enable this kind of caching. Establish level == -1 to mean streaming read (e.g. downloading the merkle tree). Signed-off-by: Darrick J. Wong --- fs/verity/fsverity_private.h | 2 +- fs/verity/read_metadata.c | 2 +- fs/verity/verify.c | 25 +++++++++++++++++++------ include/linux/fsverity.h | 32 ++++++++++++++++++++++---------- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index 0a4381acb394..b01343113e8b 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -179,7 +179,7 @@ static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi, int fsverity_read_merkle_tree_block(struct inode *inode, const struct merkle_tree_params *params, - u64 pos, unsigned long ra_bytes, + int level, u64 pos, unsigned long ra_bytes, struct fsverity_blockbuf *block); /* diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c index 94fffa060f82..87cc6f289663 100644 --- a/fs/verity/read_metadata.c +++ b/fs/verity/read_metadata.c @@ -43,7 +43,7 @@ static int fsverity_read_merkle_tree(struct inode *inode, params->block_size - offs_in_block); err = fsverity_read_merkle_tree_block(inode, &vi->tree_params, - pos - offs_in_block, ra_bytes, &block); + -1, pos - offs_in_block, ra_bytes, &block); if (err) { fsverity_err(inode, "Error %d reading Merkle tree block %llu", diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 6c4c73eeccea..cd84182f5e43 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -184,8 +184,8 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, else ra_bytes = 0; - err = fsverity_read_merkle_tree_block(inode, params, hblock_pos, - ra_bytes, block); + err = fsverity_read_merkle_tree_block(inode, params, level, + hblock_pos, ra_bytes, block); if (err) { fsverity_err(inode, "Error %d reading Merkle tree block %llu", @@ -406,6 +406,8 @@ EXPORT_SYMBOL_GPL(fsverity_invalidate_block); * fsverity_read_merkle_tree_block() - read Merkle tree block * @inode: inode to which this Merkle tree blocks belong * @params: merkle tree parameters + * @level: expected level of the block; level 0 are the leaves, -1 means a + * streaming read * @pos: byte position within merkle tree * @ra_bytes: try to read ahead this many btes * @block: block to be loaded @@ -414,7 +416,7 @@ EXPORT_SYMBOL_GPL(fsverity_invalidate_block); */ int fsverity_read_merkle_tree_block(struct inode *inode, const struct merkle_tree_params *params, - u64 pos, unsigned long ra_bytes, + int level, u64 pos, unsigned long ra_bytes, struct fsverity_blockbuf *block) { const struct fsverity_operations *vops = inode->i_sb->s_vop; @@ -423,9 +425,20 @@ int fsverity_read_merkle_tree_block(struct inode *inode, unsigned long index; unsigned int offset_in_page; - if (fsverity_caches_blocks(inode)) - return vops->read_merkle_tree_block(inode, pos, ra_bytes, - params->log_blocksize, block); + block->offset = pos; + block->size = params->block_size; + + if (fsverity_caches_blocks(inode)) { + struct fsverity_readmerkle req = { + .inode = inode, + .level = level, + .num_levels = params->num_levels, + .log_blocksize = params->log_blocksize, + .ra_bytes = ra_bytes, + }; + + return vops->read_merkle_tree_block(&req, block); + } index = pos >> params->log_blocksize; page_idx = round_down(index, params->blocks_per_page); diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 0af2cd1860e4..d12a95623614 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -53,6 +53,26 @@ struct fsverity_blockbuf { void *context; }; +/** + * struct fsverity_readmerkle - Request to read a Merkle Tree block buffer + * @inode: the inode to read + * @level: expected level of the block; level 0 are the leaves, -1 means a + * streaming read + * @num_levels: number of levels in the tree total + * @log_blocksize: log2 of the size of the expected block + * @ra_bytes: The number of bytes that should be prefetched starting at pos + * if the page at @block->offset isn't already cached. + * Implementations may ignore this argument; it's only a + * performance optimization. + */ +struct fsverity_readmerkle { + struct inode *inode; + unsigned long ra_bytes; + int level; + int num_levels; + u8 log_blocksize; +}; + /* Verity operations for filesystems */ struct fsverity_operations { @@ -139,13 +159,7 @@ struct fsverity_operations { /** * Read a Merkle tree block of the given inode. - * @inode: the inode - * @pos: byte offset of the block within the Merkle tree - * @ra_bytes: The number of bytes that should be - * prefetched starting at @pos if the page at @pos - * isn't already cached. Implementations may ignore this - * argument; it's only a performance optimization. - * @log_blocksize: log2 of the size of the expected block + * @req: read request; see struct fsverity_readmerkle * @block: block buffer for filesystem to point it to the block * * This can be called at any time on an open verity file. It may be @@ -160,9 +174,7 @@ struct fsverity_operations { * * Return: 0 on success, -errno on failure */ - int (*read_merkle_tree_block)(struct inode *inode, - u64 pos, unsigned long ra_bytes, - unsigned int log_blocksize, + int (*read_merkle_tree_block)(const struct fsverity_readmerkle *req, struct fsverity_blockbuf *block); /** From patchwork Sun Mar 17 16:26:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594583 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F43C1CD03; Sun, 17 Mar 2024 16:26:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692792; cv=none; b=b5al7jHJKUPN2FDsbksbTt9zBZdQZDQ3p6/x8eDEAdcqM84d/X7SYr7hqTkkdbTFgMD++Tyvi8g59auDTHswgtzeq6eqPqE1YRV7bcs7iUfO6hTTmjcAoAPYrZJRtS8g2mj5DfTLnhgc90u+CUVMGt9NvpFuJ2XYn88W9+d57n0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692792; c=relaxed/simple; bh=RWvS6hYxLBMDy+8cpkZisjZ45FWaV2WRXSY+F3T1zmE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lHD/spy0ukzALNOu8uDMExloG3GPA4BhSysgw26FeYPmQiwNbHRmpLd9tfUfgtHCNLB3/PvIqYTrPEOpK4SBwe38RoV/VnOCxnbf50YmtWeOYQ2MsUMSpqARwSPENuyigaNObGfCbx6ouZwNmQnINpPkzNmcDkN1fi2Wh0LsuL4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YBeExkEl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YBeExkEl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 238E7C433C7; Sun, 17 Mar 2024 16:26:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692792; bh=RWvS6hYxLBMDy+8cpkZisjZ45FWaV2WRXSY+F3T1zmE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=YBeExkEl7o9MoPb0fHR7H4RoHzqptejFdRXmeyw2G9u3p7yGSd5lfvJlqGAo3fbje wkAyoZuAMeJV2DkWw6M0Q/yUbQrzhzHfH9ch6Xh8qp8l1kTNQ+8GAUZIzvhBg9RYvt nm5/OpD5v1jLhAL1XPbHzjSSvhqGU3BHUnfkwG7phnJTLJxUC4u+2sE7ZM8gXtd1/V JMWfsqWMlH2mrKzCqlEP4rb96LdJCacoSoJG4VEB9r1F4RNIWbphNVMBfUXPiniGJM lTmYAVIYK6vGDunPMMg4yEujvP0+nlv6Y1OC/CAN0CzYetqL97Of0tkpo+iXkNRpBE jVsILZ0hllX0Q== Date: Sun, 17 Mar 2024 09:26:31 -0700 Subject: [PATCH 12/40] fsverity: pass the new tree size and block size to ->begin_enable_verity From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246107.2684506.3326500566486167316.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong When starting up the process of enabling fsverity on a file, pass the new size of the merkle tree and the merkle tree block size to the fs implementation. XFS will want this information later to try to clean out a failed previous enablement attempt. Signed-off-by: Darrick J. Wong --- fs/btrfs/verity.c | 3 ++- fs/ext4/verity.c | 3 ++- fs/f2fs/verity.c | 3 ++- fs/verity/enable.c | 3 ++- include/linux/fsverity.h | 5 ++++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index 966630523502..c52f32bd43c7 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -579,7 +579,8 @@ static int finish_verity(struct btrfs_inode *inode, const void *desc, * * Returns 0 on success, negative error code on failure. */ -static int btrfs_begin_enable_verity(struct file *filp) +static int btrfs_begin_enable_verity(struct file *filp, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct btrfs_inode *inode = BTRFS_I(file_inode(filp)); struct btrfs_root *root = inode->root; diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index da2095a81349..a8ae8c912cb5 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -99,7 +99,8 @@ static int pagecache_write(struct inode *inode, const void *buf, size_t count, return 0; } -static int ext4_begin_enable_verity(struct file *filp) +static int ext4_begin_enable_verity(struct file *filp, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct inode *inode = file_inode(filp); const int credits = 2; /* superblock and inode for ext4_orphan_add() */ diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index b4461b9f47a3..f6ad6523ce95 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -115,7 +115,8 @@ struct fsverity_descriptor_location { __le64 pos; }; -static int f2fs_begin_enable_verity(struct file *filp) +static int f2fs_begin_enable_verity(struct file *filp, u64 merkle_tree_size, + unsigned int tree_blocksize) { struct inode *inode = file_inode(filp); int err; diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 945eba0092ab..496a361c0a81 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -237,7 +237,8 @@ static int enable_verity(struct file *filp, if (IS_VERITY(inode)) err = -EEXIST; else - err = vops->begin_enable_verity(filp); + err = vops->begin_enable_verity(filp, params.tree_size, + params.block_size); inode_unlock(inode); if (err) goto out; diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index d12a95623614..c5f3564f2cb8 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -80,6 +80,8 @@ struct fsverity_operations { * Begin enabling verity on the given file. * * @filp: a readonly file descriptor for the file + * @merkle_tree_size: total bytes the new Merkle tree will take up + * @tree_blocksize: the new Merkle tree block size * * The filesystem must do any needed filesystem-specific preparations * for enabling verity, e.g. evicting inline data. It also must return @@ -89,7 +91,8 @@ struct fsverity_operations { * * Return: 0 on success, -errno on failure */ - int (*begin_enable_verity)(struct file *filp); + int (*begin_enable_verity)(struct file *filp, u64 merkle_tree_size, + unsigned int tree_blocksize); /** * End enabling verity on the given file. From patchwork Sun Mar 17 16:26:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594617 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EBF4D1CA96; Sun, 17 Mar 2024 16:26:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692808; cv=none; b=ZCG5ncbELTBdf9lwRZAspffmRmYKXswt+mU9OKc1196shy1fVIqbZ7R3CBzON4jbcIGXAPxeiG7lq4nXxySBlPjMp3/HngHnfCqqKhPM+6nHw5+bVMidyzRXNH4bGt4zhDSYcQoVVy+OOmoe/Vrq1mJW+oWoHR/Ic1ViMLVoTzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692808; c=relaxed/simple; bh=f4vax+lrizWDzm1uCMSeA/R3941ZYwTYCDp1kZmtEIA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dejL24F1k5hz1/1dB9slQL7QlyC/pAjDiwvz8L07sxcb/9eQLgf1Ad+LXH261RqYdmTjUX6AKJfK68malHnFawHVeuQlXG7KwjUfQpB7CNaBSRZPCSTRG58ZhylLRFJkM2Mq9zcASpMIbU94snQWt9zfwPASM4mKKW4g0ghLbxE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K7JsmQ4N; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K7JsmQ4N" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C6530C433C7; Sun, 17 Mar 2024 16:26:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692807; bh=f4vax+lrizWDzm1uCMSeA/R3941ZYwTYCDp1kZmtEIA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=K7JsmQ4NpSiT/lX3EkzOsHb8jH5UWDacn+ehSkJLjYPLWmbZeguPYY384S00ngByV APl8EmwRItB/ta67egBWckXRNqG3F23DszpKwqjvRg59EXg/Oaul1qDQeMiYQ4FuoE knw4D6uJPewl+ozyAN20bTH4byWFAmHut5FA/pwxXZlkD9TCEqL1eqjazuWPINZgeY 52OeG1Run6Hg1xFGlj+NQTO3Obu4HbCLOUmg8TZk+gtFmi9+2XbuKvA5iEGCvb38on Ss17C2YN/lpeMtkNlTyhgSXMPP81HJ/A1h9zGtONQvSfnxOMGwJXbOTUTj9NnY/4N/ 7Viem1g+RUeQQ== Date: Sun, 17 Mar 2024 09:26:47 -0700 Subject: [PATCH 13/40] fsverity: expose merkle tree geometry to callers From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246123.2684506.17802014697868839609.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a function that will return selected information about the geometry of the merkle tree. Online fsck for XFS will need this piece to perform basic checks of the merkle tree. Signed-off-by: Darrick J. Wong --- fs/verity/open.c | 26 ++++++++++++++++++++++++++ include/linux/fsverity.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/fs/verity/open.c b/fs/verity/open.c index 9603b3a404f7..7a86407732c4 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -412,6 +412,32 @@ void __fsverity_cleanup_inode(struct inode *inode) } EXPORT_SYMBOL_GPL(__fsverity_cleanup_inode); +/** + * fsverity_merkle_tree_geometry() - return Merkle tree geometry + * @inode: the inode for which the Merkle tree is being built + * @block_size: size of a merkle tree block, in bytes + * @tree_size: size of the merkle tree, in bytes + */ +int fsverity_merkle_tree_geometry(struct inode *inode, unsigned int *block_size, + u64 *tree_size) +{ + struct fsverity_info *vi; + int error; + + if (!IS_VERITY(inode)) + return -EOPNOTSUPP; + + error = ensure_verity_info(inode); + if (error) + return error; + + vi = fsverity_get_info(inode); + *block_size = vi->tree_params.block_size; + *tree_size = vi->tree_params.tree_size; + return 0; +} +EXPORT_SYMBOL_GPL(fsverity_merkle_tree_geometry); + void __init fsverity_init_info_cache(void) { fsverity_info_cachep = KMEM_CACHE_USERCOPY( diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index c5f3564f2cb8..17bc0729119c 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -240,6 +240,9 @@ int __fsverity_file_open(struct inode *inode, struct file *filp); int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); void __fsverity_cleanup_inode(struct inode *inode); +int fsverity_merkle_tree_geometry(struct inode *inode, unsigned int *block_size, + u64 *tree_size); + /** * fsverity_cleanup_inode() - free the inode's verity info, if present * @inode: an inode being evicted From patchwork Sun Mar 17 16:27:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594618 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 016651CAB7; Sun, 17 Mar 2024 16:27:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692824; cv=none; b=ZUrMD/p7jBNwe0bA5rhgJgRjd9svAxraux3K+fHdm638aO14A0bsWgwi/HiMSOnMstUmo/PImVkNAQy3AU2KHp/ZaPsbsLzASsa8OejXEClxQgiXu2qxKokQDYIV2GUenJdO4iHhO8yY2au79Vubh5jEaTPX6vHxaX4usZCsi1M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692824; c=relaxed/simple; bh=jRGedbeIlRods6JQW2PoaB61wTVKCCEInceyvQG3spU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oXdQTVUXAv5OezPUAXNgZnyCgZiF+ziOg2vuUliOZnQH48qUNrkHEMO/kK2hccaw8Xvf60gAutgGeBO4cefTbdYWRH4r+uFdcFqYR8e8OIC+Gj1V5q5TV3HhPc0xv+bOzlznAXbflGh64cHV7tAKvYyqnOHcwEF7jIhmcpGiPgU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nBKBbxg1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nBKBbxg1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D4FAC433F1; Sun, 17 Mar 2024 16:27:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692823; bh=jRGedbeIlRods6JQW2PoaB61wTVKCCEInceyvQG3spU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=nBKBbxg1jaTqwZ1U98Vlo5oc11n32IJf0olwWEJuWWn96+UQR4FXVqFEB1pneF8Dz M7iZJxZD48VSJYGL9w0g+oSp//QJehweBKMRj2QUGbRrwgkh7ieATZwh8vbSFRusAl DF3lcP0edaSF2zngXHWGL89Jxm3aZ5YFL2VWst9tuWXdOuszSRLN/qQlKyb3QkqegD UN+ryCTevqeHO9VoF+HDwBFxmJLQeV15bYJe8D5nFEupJZKokI9YUNlHfajezljZCe 4n50oyyi+tQlEQsLWSYH1iOF7Yky5/2C4TAliGbE9RuJtrfuF+zPAGiH3OP6681XNF ZThrddWnOLzdQ== Date: Sun, 17 Mar 2024 09:27:02 -0700 Subject: [PATCH 14/40] fsverity: rely on cached block callers to retain verified state From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246138.2684506.8836637841022003817.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Using a single contiguous bitmap to record merkle tree block verification state is unnecessary when we can retain that state in the merkle tree block cache. Worse, it doesn't scale well to large verity files and stresses the memory allocator. Therefore, add a state bit to fsverity_blockbuf and let the implementation retain the validated state. Signed-off-by: Darrick J. Wong --- fs/verity/fsverity_private.h | 7 ++++--- fs/verity/verify.c | 39 +++++++-------------------------------- include/linux/fsverity.h | 13 ++++++++----- include/trace/events/fsverity.h | 19 ------------------- 4 files changed, 19 insertions(+), 59 deletions(-) diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index b01343113e8b..de8798f141d4 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -167,14 +167,15 @@ static inline bool fsverity_caches_blocks(const struct inode *inode) static inline bool fsverity_uses_bitmap(const struct fsverity_info *vi, const struct inode *inode) { + if (fsverity_caches_blocks(inode)) + return false; + /* * If fs uses block-based Merkle tree caching, then fs-verity must use * hash_block_verified bitmap as there's no page to mark it with * PG_checked. */ - if (vi->tree_params.block_size != PAGE_SIZE) - return true; - return fsverity_caches_blocks(inode); + return vi->tree_params.block_size != PAGE_SIZE; } int fsverity_read_merkle_tree_block(struct inode *inode, diff --git a/fs/verity/verify.c b/fs/verity/verify.c index cd84182f5e43..a61d1c99c485 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -26,12 +26,11 @@ static bool is_hash_block_verified(struct inode *inode, struct page *hpage; /* - * If the filesystem uses block-based caching, then - * ->hash_block_verified is always used and the filesystem pushes - * invalidations to it as needed. + * If the filesystem uses block-based caching, then rely on the + * implementation to retain verified status. */ if (fsverity_caches_blocks(inode)) - return test_bit(hblock_idx, vi->hash_block_verified); + return block->verified; /* Otherwise, the filesystem uses page-based caching. */ hpage = (struct page *)block->context; @@ -224,7 +223,9 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, * idempotent, as the same hash block might be verified by * multiple threads concurrently. */ - if (fsverity_uses_bitmap(vi, inode)) + if (fsverity_caches_blocks(inode)) + block->verified = true; + else if (fsverity_uses_bitmap(vi, inode)) set_bit(hblock_idx, vi->hash_block_verified); else SetPageChecked((struct page *)block->context); @@ -375,33 +376,6 @@ void __init fsverity_init_workqueue(void) panic("failed to allocate fsverity_read_queue"); } -/** - * fsverity_invalidate_block() - invalidate Merkle tree block - * @inode: inode to which this Merkle tree blocks belong - * @block: block to be invalidated - * - * This function invalidates/clears "verified" state of Merkle tree block - * in the fs-verity bitmap. The block needs to have ->offset set. - */ -void fsverity_invalidate_block(struct inode *inode, - struct fsverity_blockbuf *block) -{ - struct fsverity_info *vi = inode->i_verity_info; - const unsigned int log_blocksize = vi->tree_params.log_blocksize; - - trace_fsverity_invalidate_block(inode, block); - - if (block->offset >= vi->tree_params.tree_size) { - fsverity_err(inode, -"Trying to invalidate beyond Merkle tree (tree %lld, offset %lld)", - vi->tree_params.tree_size, block->offset); - return; - } - - clear_bit(block->offset >> log_blocksize, vi->hash_block_verified); -} -EXPORT_SYMBOL_GPL(fsverity_invalidate_block); - /** * fsverity_read_merkle_tree_block() - read Merkle tree block * @inode: inode to which this Merkle tree blocks belong @@ -436,6 +410,7 @@ int fsverity_read_merkle_tree_block(struct inode *inode, .log_blocksize = params->log_blocksize, .ra_bytes = ra_bytes, }; + block->verified = false; return vops->read_merkle_tree_block(&req, block); } diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 17bc0729119c..026e4f72290e 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -32,6 +32,7 @@ * @offset: block's offset into Merkle tree * @size: the Merkle tree block size * @context: filesystem private context + * @verified: has this buffer been validated? * * Buffer containing single Merkle Tree block. These buffers are passed * - to filesystem, when fs-verity is building merkel tree, @@ -49,6 +50,7 @@ struct fsverity_blockbuf { void *kaddr; u64 offset; + unsigned int verified:1; unsigned int size; void *context; }; @@ -168,9 +170,9 @@ struct fsverity_operations { * This can be called at any time on an open verity file. It may be * called by multiple processes concurrently. * - * In case that block was evicted from the memory filesystem has to use - * fsverity_invalidate_block() to let fsverity know that block's - * verification state is not valid anymore. + * Implementations may cache the @block->verified state in + * ->drop_merkle_tree_block. They must clear the @block->verified + * flag for a cache miss. * * If this function is implemented, ->drop_merkle_tree_block must also * be implemented. @@ -204,6 +206,9 @@ struct fsverity_operations { * This is called when fs-verity is done with a block obtained with * ->read_merkle_tree_block(). * + * Implementations should cache a @block->verified==1 state to avoid + * unnecessary revalidations during later accesses. + * * If this function is implemented, ->read_merkle_tree_block must also * be implemented. */ @@ -264,8 +269,6 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg); bool fsverity_verify_blocks(struct folio *folio, size_t len, size_t offset); void fsverity_verify_bio(struct bio *bio); void fsverity_enqueue_verify_work(struct work_struct *work); -void fsverity_invalidate_block(struct inode *inode, - struct fsverity_blockbuf *block); static inline int fsverity_set_ops(struct super_block *sb, const struct fsverity_operations *ops) diff --git a/include/trace/events/fsverity.h b/include/trace/events/fsverity.h index 763890e47358..1a6ee2a2c3ce 100644 --- a/include/trace/events/fsverity.h +++ b/include/trace/events/fsverity.h @@ -109,25 +109,6 @@ TRACE_EVENT(fsverity_merkle_tree_block_verified, __entry->direction == 0 ? "ascend" : "descend") ); -TRACE_EVENT(fsverity_invalidate_block, - TP_PROTO(struct inode *inode, struct fsverity_blockbuf *block), - TP_ARGS(inode, block), - TP_STRUCT__entry( - __field(ino_t, ino) - __field(u64, offset) - __field(unsigned int, block_size) - ), - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->offset = block->offset; - __entry->block_size = block->size; - ), - TP_printk("ino %lu block position %llu block size %u", - (unsigned long) __entry->ino, - __entry->offset, - __entry->block_size) -); - TRACE_EVENT(fsverity_read_merkle_tree_block, TP_PROTO(struct inode *inode, u64 offset, unsigned int log_blocksize), TP_ARGS(inode, offset, log_blocksize), From patchwork Sun Mar 17 16:27:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594619 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F4DA1CAB7; Sun, 17 Mar 2024 16:27:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692839; cv=none; b=jLmIRHCwkitBL9ge8tc4gpBhqFAHJCZQQGNL2lHn4JetyWZvZIRfm+LNXEJoNIGl5+8lFKS/k+CZNFrMoAZYlwtuHIR01SXDUh1Y9xD3qPaArfvolZBMWRzx4m5OQkAduHuPoMR/lioln+xAnHrctVLrS8u5HHf34GlNmTl16QU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692839; c=relaxed/simple; bh=pz1WkH8YrDy95nDuH+ySTVsbKCgRz/nDS0YNxRP4rSY=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=af+FtcUgqqN+ynFcZV/snYF+rnCRN88ZACilS8RBoUQPwB7GuFFqaBqty/56qvs+T3l4Xyyv+XxViDeDtGuHfwnk+KPMySmSTvAcDxf6vyea/dqr/ues3MLHEHSSrX5tr5RX5XXizHcblIbWjwnuNyS4vHJ7rPRJBxGHoRxWFUo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YAqrtJo+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YAqrtJo+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 07403C433C7; Sun, 17 Mar 2024 16:27:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692839; bh=pz1WkH8YrDy95nDuH+ySTVsbKCgRz/nDS0YNxRP4rSY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=YAqrtJo+N4FbpnXJ/IZhw/5r0zcS7ARcqYWjDre0NnUuy412hitvV0mLGGZZLonpY fKoKi9sjaG85fMLJgDCqxXmwjz5K5z1NZmAmMER7Ik1+yGdOz1C+bvHYCa9dngudtS Qh6kOrEVEiQZuemHsVRgs6wf2ymdJ03BuNxHZ4Igzdaz4YgFLYhRPAQPMAjyHC/WJG IZN38Cm29uh/ymCdLCD14gpGV7wn9tU+S5LWgvqayXxZfyT623iEYj1asAtcPJS6Oz SbuPny1jLV5uNjouaIQtYRFPpZyAQrirSrBdgrBkJoBbMaE3FW0RWRhCZzzTPWDeM/ H0817I4S/o03A== Date: Sun, 17 Mar 2024 09:27:18 -0700 Subject: [PATCH 15/40] fsverity: box up the write_merkle_tree_block parameters too From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246154.2684506.12184706714215752733.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Box up the tree write request parameters into a structure so that we can add more in the next few patches. Signed-off-by: Darrick J. Wong --- fs/btrfs/verity.c | 6 ++++-- fs/ext4/verity.c | 7 +++++-- fs/f2fs/verity.c | 7 +++++-- fs/verity/enable.c | 5 ++++- include/linux/fsverity.h | 21 ++++++++++++++++++--- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index c52f32bd43c7..70794c608581 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -791,9 +791,11 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode, * * Returns 0 on success or negative error code on failure */ -static int btrfs_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 pos, unsigned int size) +static int btrfs_write_merkle_tree_block(const struct fsverity_writemerkle *req, + const void *buf, u64 pos, + unsigned int size) { + struct inode *inode = req->inode; loff_t merkle_pos = merkle_file_pos(inode); if (merkle_pos < 0) diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index a8ae8c912cb5..27eb2d51cce2 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -382,9 +382,12 @@ static struct page *ext4_read_merkle_tree_page(struct inode *inode, return folio_file_page(folio, index); } -static int ext4_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 pos, unsigned int size) +static int ext4_write_merkle_tree_block(const struct fsverity_writemerkle *req, + const void *buf, u64 pos, + unsigned int size) { + struct inode *inode = req->inode; + pos += ext4_verity_metadata_pos(inode); return pagecache_write(inode, buf, size, pos); diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index f6ad6523ce95..923d7a09b2f4 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -277,9 +277,12 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode, return page; } -static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 pos, unsigned int size) +static int f2fs_write_merkle_tree_block(const struct fsverity_writemerkle *req, + const void *buf, u64 pos, + unsigned int size) { + struct inode *inode = req->inode; + pos += f2fs_verity_metadata_pos(inode); return pagecache_write(inode, buf, size, pos); diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 496a361c0a81..8dcfefc848ee 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -50,10 +50,13 @@ static int write_merkle_tree_block(struct inode *inode, const u8 *buf, unsigned long index, const struct merkle_tree_params *params) { + struct fsverity_writemerkle req = { + .inode = inode, + }; u64 pos = (u64)index << params->log_blocksize; int err; - err = inode->i_sb->s_vop->write_merkle_tree_block(inode, buf, pos, + err = inode->i_sb->s_vop->write_merkle_tree_block(&req, buf, pos, params->block_size); if (err) fsverity_err(inode, "Error %d writing Merkle tree block %lu", diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 026e4f72290e..0dded1fcf2b1 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -75,6 +75,20 @@ struct fsverity_readmerkle { u8 log_blocksize; }; +/** + * struct fsverity_writemerkle - Request to write a Merkle Tree block buffer + * @inode: the inode to read + * @level: level of the block; level 0 are the leaves + * @num_levels: number of levels in the tree total + * @log_blocksize: log2 of the size of the block + */ +struct fsverity_writemerkle { + struct inode *inode; + int level; + int num_levels; + u8 log_blocksize; +}; + /* Verity operations for filesystems */ struct fsverity_operations { @@ -185,7 +199,7 @@ struct fsverity_operations { /** * Write a Merkle tree block to the given inode. * - * @inode: the inode for which the Merkle tree is being built + * @req: write request; see struct fsverity_writemerkle * @buf: the Merkle tree block to write * @pos: the position of the block in the Merkle tree (in bytes) * @size: the Merkle tree block size (in bytes) @@ -195,8 +209,9 @@ struct fsverity_operations { * * Return: 0 on success, -errno on failure */ - int (*write_merkle_tree_block)(struct inode *inode, const void *buf, - u64 pos, unsigned int size); + int (*write_merkle_tree_block)(const struct fsverity_writemerkle *req, + const void *buf, u64 pos, + unsigned int size); /** * Release the reference to a Merkle tree block From patchwork Sun Mar 17 16:27:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594620 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3584A20334; Sun, 17 Mar 2024 16:27:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692855; cv=none; b=kVahut/qJ9A2goXz0mahGeCMgHUVv3p5lXnGAAZwHIVD4AMzy46zLnBs2qdkp+24efj+SPgUZuw47gqoIISsM/D2opFUrOBPvr5hCkMb1OS99mKglA/ESHkN4Hwh+qbVntKK7YtkCmJNVT6xbBcGTlGNalgF5YRpSP5XTAn52BI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692855; c=relaxed/simple; bh=c1vdnxhyPun7CrTbGxk929f0S+WGN8I99JUAs57DDe8=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FRX8zyZGHaln0fVHEDufyfguGVBe7D5Mm3UUuj/jGYT6gWQ75geyeqxJAoHlcj+n/FjZVehMri2KAArryZ2Lj5lAZrkqLhblnq+uCpErdmKpiYOFTJXG32IwMryZdgyx3onDN5iauhGGrNYj0U4+xOYnVrsoU/1wMPqXAsnfi+Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iwIwpuhY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iwIwpuhY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A2575C433C7; Sun, 17 Mar 2024 16:27:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692854; bh=c1vdnxhyPun7CrTbGxk929f0S+WGN8I99JUAs57DDe8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iwIwpuhYCNW0cTGfBRYHqRxVJgbpCib7S7bdYEyl8fR9Ra+F3UtE6cVClrIDDcrdi JbNUp1n7gbSzrY0rcvSGT+T7fB6J94CIba88QELKmp0wX4sy1vNT6Ag9xpKhOpZo2s skR7D2BIO9vcuekBYmsRBL5CO55ne+C9Wn48MGb1QnollrDW3swaxjer6/h59A5Vb9 4tJlgjqvCXQMVJdO1i9U7xRym+S89F6rsn97m2Fm13bVvB5cp/CwY5YWtByiFnukdT igKiTwXhoJtVyG5yLFdl41h0StGOclbQZ+FuDO/NFRHmDdebvE+nhu/EvZmCKp1gZj VZA+gH0VH/cCQ== Date: Sun, 17 Mar 2024 09:27:34 -0700 Subject: [PATCH 16/40] fsverity: pass the zero-hash value to the implementation From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246170.2684506.16175333193381403848.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Compute the hash of a data block full of zeros, and then supply this to the merkle tree read and write methods. A subsequent xfs patch will use this to reduce the size of the merkle tree when dealing with sparse gold master disk images and the like. Signed-off-by: Darrick J. Wong --- fs/verity/enable.c | 2 ++ fs/verity/fsverity_private.h | 2 ++ fs/verity/open.c | 7 +++++++ fs/verity/verify.c | 2 ++ include/linux/fsverity.h | 8 ++++++++ 5 files changed, 21 insertions(+) diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 8dcfefc848ee..06b769dd1bdf 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -52,6 +52,8 @@ static int write_merkle_tree_block(struct inode *inode, const u8 *buf, { struct fsverity_writemerkle req = { .inode = inode, + .zero_digest = params->zero_digest, + .digest_size = params->digest_size, }; u64 pos = (u64)index << params->log_blocksize; int err; diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index de8798f141d4..195a92f203bb 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -47,6 +47,8 @@ struct merkle_tree_params { u64 tree_size; /* Merkle tree size in bytes */ unsigned long tree_pages; /* Merkle tree size in pages */ + u8 zero_digest[FS_VERITY_MAX_DIGEST_SIZE]; /* hash of zeroed data block */ + /* * Starting block index for each tree level, ordered from leaf level (0) * to root level ('num_levels - 1') diff --git a/fs/verity/open.c b/fs/verity/open.c index 7a86407732c4..433a70eeca55 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -144,6 +144,13 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, goto out_err; } + err = fsverity_hash_buffer(params->hash_alg, page_address(ZERO_PAGE(0)), + i_blocksize(inode), params->zero_digest); + if (err) { + fsverity_err(inode, "Error %d computing zero digest", err); + goto out_err; + } + params->tree_size = offset << log_blocksize; params->tree_pages = PAGE_ALIGN(params->tree_size) >> PAGE_SHIFT; return 0; diff --git a/fs/verity/verify.c b/fs/verity/verify.c index a61d1c99c485..494225f60608 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -409,6 +409,8 @@ int fsverity_read_merkle_tree_block(struct inode *inode, .num_levels = params->num_levels, .log_blocksize = params->log_blocksize, .ra_bytes = ra_bytes, + .zero_digest = params->zero_digest, + .digest_size = params->digest_size, }; block->verified = false; diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 0dded1fcf2b1..da23f1e30151 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -66,6 +66,8 @@ struct fsverity_blockbuf { * if the page at @block->offset isn't already cached. * Implementations may ignore this argument; it's only a * performance optimization. + * @zero_digest: the hash for a data block of zeroes + * @digest_size: size of zero_digest */ struct fsverity_readmerkle { struct inode *inode; @@ -73,6 +75,8 @@ struct fsverity_readmerkle { int level; int num_levels; u8 log_blocksize; + const u8 *zero_digest; + unsigned int digest_size; }; /** @@ -81,12 +85,16 @@ struct fsverity_readmerkle { * @level: level of the block; level 0 are the leaves * @num_levels: number of levels in the tree total * @log_blocksize: log2 of the size of the block + * @zero_digest: the hash for a data block of zeroes + * @digest_size: size of zero_digest */ struct fsverity_writemerkle { struct inode *inode; int level; int num_levels; u8 log_blocksize; + const u8 *zero_digest; + unsigned int digest_size; }; /* Verity operations for filesystems */ From patchwork Sun Mar 17 16:27:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594621 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C60FB1DFCB; Sun, 17 Mar 2024 16:27:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692870; cv=none; b=JffoTxjubDua9tXYVTRH3YYT8bXcXdok4fT024iPpaXuNHmov0c1BTZTrZVbKJ3Npc56TyG9uoU+Q9ctSfwNeWGQAmx2cJ9MeGuHcWWOBcEnW4p6hYJ5z8dLnttxcILwiJk2vI/midZsdMMqsG51/sTcNGcSLmbDlVVsOT8GisQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692870; c=relaxed/simple; bh=BKMI6UCt/jv/2gfwrIZH16FTO2HTxLbioRJjZsYziBU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Dr36W1z2Sq75R70g2l9c+Uepu96EalpOBocdkqPS2aXF0DQY5F+h3NMyqw6X1CTf9J7mKfdkMdfeg61iAu9OdV4+eAbggY2FLoWHGgaTUZfPJDyfmOEmvngfk7ipMa/e7w6fI+ttGD3L0/xuhxAOG8YroqE34GXbV409tCWSvZc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g+gnZfy7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g+gnZfy7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 45D85C433F1; Sun, 17 Mar 2024 16:27:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692870; bh=BKMI6UCt/jv/2gfwrIZH16FTO2HTxLbioRJjZsYziBU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=g+gnZfy7Bmsi7lEUku9rd2iqJqyP+dCAFd/JI0Vu6/1nOuO9YJChkNQhCOBicmnx2 i+opRODLDdwHb/OGaweRkQuFnU/0L9L0Z6715SeDPmjwn6PYvr3bdUfyGtI4gXE1L1 dv7MDFH/AlaL21JQuN2w5cjGbl3o03MjPS3qyorKKFnMepp8fhp2dj40VKdGnFi8po 9W4xgBocDh4Eyto1RCvk6lNzQgEE9j6DRvtd5J7GBOGFNmq3E9+PBaHSrIjhM+GjtT PiLud0DDGwDpbfGWChouhAKj7IrD3KhO8dF3JLlCR59LVvX5WxYsO5m/RVVup3ibkv 7urJ8YohQFXwQ== Date: Sun, 17 Mar 2024 09:27:49 -0700 Subject: [PATCH 17/40] fsverity: report validation errors back to the filesystem From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246186.2684506.3303872607648084354.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Provide a new function call so that validation errors can be reported back to the filesystem. Signed-off-by: Darrick J. Wong --- fs/verity/verify.c | 14 +++++++++++++- include/linux/fsverity.h | 11 +++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 494225f60608..0782e94bc818 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -255,6 +255,15 @@ verify_data_block(struct inode *inode, struct fsverity_info *vi, return false; } +static void fsverity_fail_validation(struct inode *inode, loff_t pos, + size_t len) +{ + const struct fsverity_operations *vops = inode->i_sb->s_vop; + + if (vops->fail_validation) + vops->fail_validation(inode, pos, len); +} + static bool verify_data_blocks(struct folio *data_folio, size_t len, size_t offset, unsigned long max_ra_bytes) @@ -277,8 +286,11 @@ verify_data_blocks(struct folio *data_folio, size_t len, size_t offset, valid = verify_data_block(inode, vi, data, pos + offset, max_ra_bytes); kunmap_local(data); - if (!valid) + if (!valid) { + fsverity_fail_validation(inode, pos + offset, + block_size); return false; + } offset += block_size; len -= block_size; } while (len); diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index da23f1e30151..57df509295f4 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -236,6 +236,17 @@ struct fsverity_operations { * be implemented. */ void (*drop_merkle_tree_block)(struct fsverity_blockbuf *block); + + /** + * Notify the filesystem that file data validation failed + * + * @inode: the inode being validated + * @pos: the file position of the invalid data + * @len: the length of the invalid data + * + * This is called when fs-verity cannot validate the file contents. + */ + void (*fail_validation)(struct inode *inode, loff_t pos, size_t len); }; #ifdef CONFIG_FS_VERITY From patchwork Sun Mar 17 16:28:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594622 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62DE31D556; Sun, 17 Mar 2024 16:28:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692886; cv=none; b=D9CnU+ghqkqeXDa+jI0n9xh1CXpcmxlA77COWAU2dmZXHPVB6WSRoMw/KD+n/Z2qVWgzY7g2Pi9zFoYe63VQ7ARBjag8ReSJiH9dg4SPXd08SIcNckZqGzXyleVZtWk+h+c9orthk/nhTUtp84DIPGQJSs17MmlOIa2h+vkAzO4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692886; c=relaxed/simple; bh=kMdqz7RLV569ab/XXjmmU/XwIDmkNbuvXEq3UWvjaMk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pbtQ/YPeBPZBtCirH0sSktAyZDJATA/NFo+EukwbmC9QiguQyLSLF+njNckngqOL9d3fNzAQwRIz2oKTGjFPCkRz4s98Uv1Fv5OWha6HhpUthh5XhaRqvoSzPIMyNsVJ86UYAuap0I0K5REKyU6JLmq1VOXkOGlFIl6gXrBDjag= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UohMoUpH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UohMoUpH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DBF54C433F1; Sun, 17 Mar 2024 16:28:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692885; bh=kMdqz7RLV569ab/XXjmmU/XwIDmkNbuvXEq3UWvjaMk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UohMoUpHCpJyl+F1XaH46qosTb7fM7vyxiVQRRok2WdSZqMWyp4fRxb5lR1KIoDjd pTBGm4D5NIOV3IhLFPuMfuEhljZuYVQSeH9niln2tKn8K6JO7VH1UxgRrijMTw5ToX aN0ch3RSSzg/E8vsYinu0JbH1j+0TBE3iBkpoZd+yJtHvgCydwcDZ7p5blRFjHpWUJ bhyKu4NiI4oQnASTewzrznIuZJfQa93kOgKyI28QQwJZCVxXo/7FqA6yL8ga1IG7R8 P7EPVt8ha7jFyJZFUT0A1fqHd7tDMtBA3K8NJUMnk+6nNx1R/C+p/Ww4Zt0zy9FuHn iNGge02hC7JFA== Date: Sun, 17 Mar 2024 09:28:05 -0700 Subject: [PATCH 18/40] iomap: integrate fs-verity verification into iomap's read path From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: Christoph Hellwig , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246202.2684506.10370751871434901402.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn This patch adds fs-verity verification into iomap's read path. After BIO's io operation is complete the data are verified against fs-verity's Merkle tree. Verification work is done in a separate workqueue. The read path ioend iomap_read_ioend are stored side by side with BIOs if FS_VERITY is enabled. Signed-off-by: Andrey Albershteyn Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong [djwong: fix doc warning] Signed-off-by: Darrick J. Wong --- fs/iomap/buffered-io.c | 91 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 9 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 093c4515b22a..c708a93d6a02 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -330,6 +331,56 @@ static inline bool iomap_block_needs_zeroing(const struct iomap_iter *iter, pos >= i_size_read(iter->inode); } +#ifdef CONFIG_FS_VERITY +struct iomap_fsverity_bio { + struct work_struct work; + struct bio bio; +}; +static struct bio_set iomap_fsverity_bioset; + +static void +iomap_read_fsverify_end_io_work(struct work_struct *work) +{ + struct iomap_fsverity_bio *fbio = + container_of(work, struct iomap_fsverity_bio, work); + + fsverity_verify_bio(&fbio->bio); + iomap_read_end_io(&fbio->bio); +} + +static void +iomap_read_fsverity_end_io(struct bio *bio) +{ + struct iomap_fsverity_bio *fbio = + container_of(bio, struct iomap_fsverity_bio, bio); + + INIT_WORK(&fbio->work, iomap_read_fsverify_end_io_work); + queue_work(bio->bi_private, &fbio->work); +} +#endif /* CONFIG_FS_VERITY */ + +static struct bio *iomap_read_bio_alloc(struct inode *inode, + struct block_device *bdev, int nr_vecs, gfp_t gfp) +{ + struct bio *bio; + +#ifdef CONFIG_FS_VERITY + if (fsverity_active(inode)) { + bio = bio_alloc_bioset(bdev, nr_vecs, REQ_OP_READ, gfp, + &iomap_fsverity_bioset); + if (bio) { + bio->bi_private = inode->i_sb->s_read_done_wq; + bio->bi_end_io = iomap_read_fsverity_end_io; + } + return bio; + } +#endif + bio = bio_alloc(bdev, nr_vecs, REQ_OP_READ, gfp); + if (bio) + bio->bi_end_io = iomap_read_end_io; + return bio; +} + static loff_t iomap_readpage_iter(const struct iomap_iter *iter, struct iomap_readpage_ctx *ctx, loff_t offset) { @@ -353,6 +404,12 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter, if (iomap_block_needs_zeroing(iter, pos)) { folio_zero_range(folio, poff, plen); + if (fsverity_active(iter->inode) && + !fsverity_verify_blocks(folio, plen, poff)) { + folio_set_error(folio); + goto done; + } + iomap_set_range_uptodate(folio, poff, plen); goto done; } @@ -370,28 +427,29 @@ static loff_t iomap_readpage_iter(const struct iomap_iter *iter, !bio_add_folio(ctx->bio, folio, plen, poff)) { gfp_t gfp = mapping_gfp_constraint(folio->mapping, GFP_KERNEL); gfp_t orig_gfp = gfp; - unsigned int nr_vecs = DIV_ROUND_UP(length, PAGE_SIZE); if (ctx->bio) submit_bio(ctx->bio); if (ctx->rac) /* same as readahead_gfp_mask */ gfp |= __GFP_NORETRY | __GFP_NOWARN; - ctx->bio = bio_alloc(iomap->bdev, bio_max_segs(nr_vecs), - REQ_OP_READ, gfp); + + ctx->bio = iomap_read_bio_alloc(iter->inode, iomap->bdev, + bio_max_segs(DIV_ROUND_UP(length, PAGE_SIZE)), + gfp); + /* * If the bio_alloc fails, try it again for a single page to * avoid having to deal with partial page reads. This emulates * what do_mpage_read_folio does. */ if (!ctx->bio) { - ctx->bio = bio_alloc(iomap->bdev, 1, REQ_OP_READ, - orig_gfp); + ctx->bio = iomap_read_bio_alloc(iter->inode, + iomap->bdev, 1, orig_gfp); } if (ctx->rac) ctx->bio->bi_opf |= REQ_RAHEAD; ctx->bio->bi_iter.bi_sector = sector; - ctx->bio->bi_end_io = iomap_read_end_io; bio_add_folio_nofail(ctx->bio, folio, plen, poff); } @@ -1996,10 +2054,25 @@ iomap_writepages(struct address_space *mapping, struct writeback_control *wbc, } EXPORT_SYMBOL_GPL(iomap_writepages); +#define IOMAP_POOL_SIZE (4 * (PAGE_SIZE / SECTOR_SIZE)) + static int __init iomap_init(void) { - return bioset_init(&iomap_ioend_bioset, 4 * (PAGE_SIZE / SECTOR_SIZE), - offsetof(struct iomap_ioend, io_inline_bio), - BIOSET_NEED_BVECS); + int error; + + error = bioset_init(&iomap_ioend_bioset, IOMAP_POOL_SIZE, + offsetof(struct iomap_ioend, io_inline_bio), + BIOSET_NEED_BVECS); +#ifdef CONFIG_FS_VERITY + if (error) + return error; + + error = bioset_init(&iomap_fsverity_bioset, IOMAP_POOL_SIZE, + offsetof(struct iomap_fsverity_bio, bio), + BIOSET_NEED_BVECS); + if (error) + bioset_exit(&iomap_ioend_bioset); +#endif + return error; } fs_initcall(iomap_init); From patchwork Sun Mar 17 16:28:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594623 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B43DA1E527; Sun, 17 Mar 2024 16:28:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692901; cv=none; b=YGPN4Hj+1wylIY3uFB06TOndxFcgQZAS/4g9vMOFCJuU5+dN13q9v4bvhMcWPjNI9iKV/DjkKnmLCh/bH1dCgVyskZ8fnixGZK7AifV0q+J4yutLHnx08xFqg5pKPuGrpCD+5N1xJ7zkgA3Dqr1DmtqQotXsQn8Zcv5g44U6g/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692901; c=relaxed/simple; bh=YV2FpcHp1T9nZAjzqj8IXFCQoFgRWZQjMLPyND0pLlc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZLunEslmyFxRamxmDdeFzM8rrTVdCx582JCWUTMbVoGX5isUlmUMjgXczmSMSklFOku7XyBEPYzpmXMgJbIs88Q2Ye85AVsDUmlWvp1KJnCgVOVpxyOcQjpfBWnl8gfkfFvcVT6WdoE+Gai/F/0Xg5KMfRKzyF3x+3aR6sgrHB8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=imoxCkaB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="imoxCkaB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8DF4CC433C7; Sun, 17 Mar 2024 16:28:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692901; bh=YV2FpcHp1T9nZAjzqj8IXFCQoFgRWZQjMLPyND0pLlc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=imoxCkaB5uzwb3AbG0LnzD/W/7H8rZ0WIp7XDIT3i1CbaYayS9TbN18Kk7XkvV1ZM u3hjDGvmDZ2XlWzeOV5z+QHj/IX4e0eCuaoHPjL3FOXg60LREtcJygTlVQTA103FU5 Ayy60FEweJElomtrNj9MXFf3DFUDdEbTpyPVp42kzsUgAi1o9cjIlj4tVf3mlWRVV/ P2eIOvvCQ5WbuiL3yEO+r+GaGJogteVAseuhoDOEYdE3nozkOsoUy4/YVCLoi0xFXB qL8N7uU7tlmAtcrK+QYciOhqr/oCeIZXCP0vaGg6z+GreGNrdLFPtzDp8HJxFHilxk T1Z60IVj3liug== Date: Sun, 17 Mar 2024 09:28:21 -0700 Subject: [PATCH 19/40] xfs: add attribute type for fs-verity From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246218.2684506.7049031355830726932.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn The Merkle tree blocks and descriptor are stored in the extended attributes of the inode. Add new attribute type for fs-verity metadata. Add XFS_ATTR_INTERNAL_MASK to skip parent pointer and fs-verity attributes as those are only for internal use. While we're at it add a few comments in relevant places that internally visible attributes are not suppose to be handled via interface defined in xfs_xattr.c. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 10 +++++++++- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/xfs_ioctl.c | 5 +++++ fs/xfs/xfs_trace.h | 3 ++- fs/xfs/xfs_xattr.c | 10 ++++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 839df0e5401b..28d4ac6fa156 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -715,14 +715,22 @@ struct xfs_attr3_leafblock { #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ #define XFS_ATTR_PARENT_BIT 3 /* parent pointer attrs */ +#define XFS_ATTR_VERITY_BIT 4 /* verity merkle tree and descriptor */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1u << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1u << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1u << XFS_ATTR_SECURE_BIT) #define XFS_ATTR_PARENT (1u << XFS_ATTR_PARENT_BIT) +#define XFS_ATTR_VERITY (1u << XFS_ATTR_VERITY_BIT) #define XFS_ATTR_INCOMPLETE (1u << XFS_ATTR_INCOMPLETE_BIT) #define XFS_ATTR_NSP_ONDISK_MASK \ - (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT) + (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT | \ + XFS_ATTR_VERITY) + +/* + * Internal attributes not exposed to the user + */ +#define XFS_ATTR_INTERNAL_MASK (XFS_ATTR_PARENT | XFS_ATTR_VERITY) /* * Alignment for namelist and valuelist entries (since they are mixed diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 9cbcba4bd363..407fadfb5c06 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -975,6 +975,7 @@ struct xfs_icreate_log { #define XFS_ATTRI_FILTER_MASK (XFS_ATTR_ROOT | \ XFS_ATTR_SECURE | \ XFS_ATTR_PARENT | \ + XFS_ATTR_VERITY | \ XFS_ATTR_INCOMPLETE) /* diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index d0e2cec6210d..ab61d7d552fb 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -352,6 +352,11 @@ static unsigned int xfs_attr_filter( u32 ioc_flags) { + /* + * Only externally visible attributes should be specified here. + * Internally used attributes (such as parent pointers or fs-verity) + * should not be exposed to userspace. + */ if (ioc_flags & XFS_IOC_ATTR_ROOT) return XFS_ATTR_ROOT; if (ioc_flags & XFS_IOC_ATTR_SECURE) diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index d4f1b2da21e7..9d4ae05abfc8 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -87,7 +87,8 @@ struct xfs_bmap_intent; { XFS_ATTR_ROOT, "ROOT" }, \ { XFS_ATTR_SECURE, "SECURE" }, \ { XFS_ATTR_INCOMPLETE, "INCOMPLETE" }, \ - { XFS_ATTR_PARENT, "PARENT" } + { XFS_ATTR_PARENT, "PARENT" }, \ + { XFS_ATTR_VERITY, "VERITY" } DECLARE_EVENT_CLASS(xfs_attr_list_class, TP_PROTO(struct xfs_attr_list_context *ctx), diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 364104e1b38a..e4c88dde4e44 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -20,6 +20,13 @@ #include +/* + * This file defines interface to work with externally visible extended + * attributes, such as those in user, system or security namespaces. This + * interface should not be used for internally used attributes (consider + * xfs_attr.c). + */ + /* * Get permission to use log-assisted atomic exchange of file extents. * @@ -244,6 +251,9 @@ xfs_xattr_put_listent( ASSERT(context->count >= 0); + if (flags & XFS_ATTR_INTERNAL_MASK) + return; + if (flags & XFS_ATTR_ROOT) { #ifdef CONFIG_XFS_POSIX_ACL if (namelen == SGI_ACL_FILE_SIZE && From patchwork Sun Mar 17 16:28:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594624 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B50221EB56; Sun, 17 Mar 2024 16:28:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692917; cv=none; b=p4b1yeCgTcnEhe/Ve5Hfo8F5cjplYbMnf8FR9mcwnT/7aeCOJzOhxamg8Fz0Vk0V5MlLbM55biDmk9nPMWglNCIzaU14zlURDudAprPKDvKBvFN42IAh+0IQoicKeEsS6+V7zfQn+rbrb49vSPwH/8/DTi6SUlxwAk85k1VCuNc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692917; c=relaxed/simple; bh=FzNl6nZ5sppQ85tcUujB6tjeJo5nqun0Z4MKseE0oes=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WN5U6bBObbcTGUp/FZgdt7CbRYR4NnGl2rGlGa0yEDFQdsY6e39DgXJ8ERIH2zIrij4jUQNrU31hUluC71g9RTIWLdvqU3SnI0QbPbotTRr+ie+/5YGbV2rehvW6BPsIdHCUJycILkBse9zrkjT+kB8yXsmbjuDZ91+No4bbcBs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mtWJuWOs; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mtWJuWOs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 31EB8C433F1; Sun, 17 Mar 2024 16:28:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692917; bh=FzNl6nZ5sppQ85tcUujB6tjeJo5nqun0Z4MKseE0oes=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mtWJuWOs+lIMzUww0gKx7FlGFVVkXM8zXszpDr/pZkiI8BSCBdKaX6SSL2Y+ARVfY jkxpYCpBM17MRbB3WBIPoh8OA+tbaqoZpuE6WtD2qVIsEjqH1ZLxA/NAiK2sD1vBtI p7T7XguGg2HiGTIoNHPMMf8d91eLU3uXHzHpYbi3tySz4VQJgAAHZvLPLiJobqyBAR 7C+xeKbvpC+CzXwijvB19kUhuyT7fmqa4iCqB2h09lyc4Z72ZWi+s18g7fOGqxLOko kwatXxWKGeZajVIjxtPAPrli9FtKytJTwlbA2mn8BFkced+sEM88mHNK3Agp77BFRj xKcc/o7gVcpSw== Date: Sun, 17 Mar 2024 09:28:36 -0700 Subject: [PATCH 20/40] xfs: add fs-verity ro-compat flag From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246234.2684506.12074345100441947797.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn To mark inodes with fs-verity enabled the new XFS_DIFLAG2_VERITY flag will be added in further patch. This requires ro-compat flag to let older kernels know that fs with fs-verity can not be modified. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_format.h | 1 + fs/xfs/libxfs/xfs_sb.c | 2 ++ fs/xfs/xfs_mount.h | 2 ++ 3 files changed, 5 insertions(+) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 2b2f9050fbfb..93d280eb8451 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -353,6 +353,7 @@ xfs_sb_has_compat_feature( #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ #define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3) /* inobt block counts */ +#define XFS_SB_FEAT_RO_COMPAT_VERITY (1 << 4) /* fs-verity */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index d991eec05436..a845cbe3f539 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -163,6 +163,8 @@ xfs_sb_version_to_features( features |= XFS_FEAT_REFLINK; if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_INOBTCNT) features |= XFS_FEAT_INOBTCNT; + if (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_VERITY) + features |= XFS_FEAT_VERITY; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_FTYPE) features |= XFS_FEAT_FTYPE; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES) diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index e880aa48de68..f198d7c82552 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -292,6 +292,7 @@ typedef struct xfs_mount { #define XFS_FEAT_BIGTIME (1ULL << 24) /* large timestamps */ #define XFS_FEAT_NEEDSREPAIR (1ULL << 25) /* needs xfs_repair */ #define XFS_FEAT_NREXT64 (1ULL << 26) /* large extent counters */ +#define XFS_FEAT_VERITY (1ULL << 27) /* fs-verity */ /* Mount features */ #define XFS_FEAT_NOATTR2 (1ULL << 48) /* disable attr2 creation */ @@ -355,6 +356,7 @@ __XFS_HAS_FEAT(inobtcounts, INOBTCNT) __XFS_HAS_FEAT(bigtime, BIGTIME) __XFS_HAS_FEAT(needsrepair, NEEDSREPAIR) __XFS_HAS_FEAT(large_extent_counts, NREXT64) +__XFS_HAS_FEAT(verity, VERITY) /* * Mount features From patchwork Sun Mar 17 16:28:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594625 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F25E1CD11; Sun, 17 Mar 2024 16:28:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692933; cv=none; b=L6S4MwhQGiYCB1yVpagaggfHkgLYMSYbfZudaB4wAkxtVV9lV7a6VqknhE0RTUmrp1CAUeB7IhILeHdoTIducUkFSX4r70oTgVWww/qfWqysWkGyDbR/jQVtci48zUKtGn6Kr+TnIkd/vp7ix+dK/RhS5cQ/KmMVKKDnkpKf5EA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692933; c=relaxed/simple; bh=tXbnyqEYd6P7nbzJPZXz7zhP2hgKT0AzmTorGbDebQg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cS04/ByxbCUc9g9B7iR9VEdAhLPMUvFJE44DX1cFdcll+/ENkbOai9HPCCuQ11FacJWpy6PVDoKO5NZbTWUFvW7APneG1MLMZkhOQQgpZhvkbOUC5lPW8rLMdBs6Pp1q9ynd8vTwG4tU0dUHBnmgLq2rZpv2f43a0yo/WRTylAs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L8mqJk3t; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L8mqJk3t" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DF9B4C433F1; Sun, 17 Mar 2024 16:28:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692932; bh=tXbnyqEYd6P7nbzJPZXz7zhP2hgKT0AzmTorGbDebQg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=L8mqJk3tAYm62j45Hwcl+ZJ+N8Lf+P1P91DZkyTEBwEUmaPjhiQfG73yR2UVjWb6u 6SsmmErE1WXs1NPyoCXBOAXD5gWRYFNICj4JdvjfMH79vEeeA20/Ma1Hbpl9HTE5w4 2MXj8KFSmXpvHFN8Ne80sWnoUAag3r6IIODiY0kHzuycGkiA4Y92Th93cu8hIMu72d mpBbqTtr++kQWdl8pyDZaPBK7AMXk6FBcfuZsL0WlsIsEt/HGSmLZp1bUV/FIPu9Ex YFdTF+ggVFu7/2KD4DBmpsyNOBTiGcm2JNL3QX2LqQ1Gqv3aicSjf2DbPVBZplL91o wXIvijkpqJoAA== Date: Sun, 17 Mar 2024 09:28:52 -0700 Subject: [PATCH 21/40] xfs: add inode on-disk VERITY flag From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246249.2684506.7049507863251169390.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn Add flag to mark inodes which have fs-verity enabled on them (i.e. descriptor exist and tree is built). Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_format.h | 4 +++- fs/xfs/xfs_inode.c | 2 ++ fs/xfs/xfs_iops.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 93d280eb8451..3ce2902101bc 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -1085,16 +1085,18 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */ #define XFS_DIFLAG2_BIGTIME_BIT 3 /* big timestamps */ #define XFS_DIFLAG2_NREXT64_BIT 4 /* large extent counters */ +#define XFS_DIFLAG2_VERITY_BIT 5 /* inode sealed by fsverity */ #define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) #define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) #define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) #define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT) +#define XFS_DIFLAG2_VERITY (1 << XFS_DIFLAG2_VERITY_BIT) #define XFS_DIFLAG2_ANY \ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ - XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64) + XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_VERITY) static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip) { diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ea48774f6b76..59446e9e1719 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -607,6 +607,8 @@ xfs_ip2xflags( flags |= FS_XFLAG_DAX; if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) flags |= FS_XFLAG_COWEXTSIZE; + if (ip->i_diflags2 & XFS_DIFLAG2_VERITY) + flags |= FS_XFLAG_VERITY; } if (xfs_inode_has_attr_fork(ip)) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 66f8c47642e8..0e5cdb82b231 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -1241,6 +1241,8 @@ xfs_diflags_to_iflags( flags |= S_NOATIME; if (init && xfs_inode_should_enable_dax(ip)) flags |= S_DAX; + if (xflags & FS_XFLAG_VERITY) + flags |= S_VERITY; /* * S_DAX can only be set during inode initialization and is never set by From patchwork Sun Mar 17 16:29:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594626 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A91B01CD15; Sun, 17 Mar 2024 16:29:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692948; cv=none; b=IKd9tAs370Q3A6yM9/SDJa3fK3zjZOb5uSQD1dge7D61ZV3d/7I5/S2cmq+kIa6E6c1/Rv/Ulf0d12b5AdhqnPxJ+eP+O7xX8ti6QZxUW+iI5mt/KqbB4oTK4YAx9iGumOcv1XSl9HYsUycqP9QFO6aaFaDWz8Vn4nX0HQiVQdA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692948; c=relaxed/simple; bh=IbdxCYJ2BOtFhytk6YBJUGUCJBZ0PkrYYAYsg50vfqg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Pv4QvfP9axszSZvOxl/vE9FePhk2Q8Iz+EYTPNwD7xySyw78Vm+Ry4uhTC+aBG97v/TFWEuSBlX2X3xySMXJQ7+jQ4iPvzYjogy6itdeWB6XosVvLXXJZi+Prp4qJz6Tdughu2sYVsL/97E/2FIJ08//EufHHgH6zqw5XEIO/6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XwIBJPet; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XwIBJPet" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 804F4C433C7; Sun, 17 Mar 2024 16:29:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692948; bh=IbdxCYJ2BOtFhytk6YBJUGUCJBZ0PkrYYAYsg50vfqg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=XwIBJPetXg1Q+TfFgD8Ss/E8dAC+X5aXqFmhBzRppxd0MwOOFMdISwUv/1WJFqjH0 9IT74pBuItW93agyDlBmy3atbgouadP67VwPH+uYi2/juc8zeVUYf4ht9qm9KEziDv cnJk0t+cSxmF+J0Vu9xmIydbbyK9qLnXwngRXNJ/tLkkx+ztI36G3B90ZodtnWVZ1l eSiGZKZ3CbedV0vIFF1SHMO2tGor1zmyMQ6DyfZAx5KuQ4l/w2p39WzjuufIKJYmRT 53xWRV61Uvgtj0hh5+jIH3wZqJBdj53htVZziTeiC9bsuW/fZ7AcXXyOFkuJ1ya/9A 21HRswJvh/ddQ== Date: Sun, 17 Mar 2024 09:29:08 -0700 Subject: [PATCH 22/40] xfs: initialize fs-verity on file open and cleanup on inode destruction From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246265.2684506.1419479199273543604.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn fs-verity will read and attach metadata (not the tree itself) from a disk for those inodes which already have fs-verity enabled. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_file.c | 8 ++++++++ fs/xfs/xfs_super.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 632653e00906..74dba917be93 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -31,6 +31,7 @@ #include #include #include +#include static const struct vm_operations_struct xfs_file_vm_ops; @@ -1228,10 +1229,17 @@ xfs_file_open( struct inode *inode, struct file *file) { + int error; + if (xfs_is_shutdown(XFS_M(inode->i_sb))) return -EIO; file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC | FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT; + + error = fsverity_file_open(inode, file); + if (error) + return error; + return generic_file_open(inode, file); } diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 6828c48b15e9..a09739beb8f3 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -49,6 +49,7 @@ #include #include #include +#include static const struct super_operations xfs_super_operations; @@ -664,6 +665,7 @@ xfs_fs_destroy_inode( ASSERT(!rwsem_is_locked(&inode->i_rwsem)); XFS_STATS_INC(ip->i_mount, vn_rele); XFS_STATS_INC(ip->i_mount, vn_remove); + fsverity_cleanup_inode(inode); xfs_inode_mark_reclaimable(ip); } From patchwork Sun Mar 17 16:29:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594627 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DDE4E1CFB2; Sun, 17 Mar 2024 16:29:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692965; cv=none; b=IpFrRRYkVUcHssP8s9zfsZbtSpQL3ReFESQR0yCok6EK9WuR2SNtcq1AdOlUjGxE874nMpjCPOqSD+IYCkpc3JO2uNhEJLIK7yB6/fXnxUCi8MBe9Tgo7g5i9gL2t85Q82IhBq98UTuRA7GQ/2+uVd4nCNHA8kY5eydM/vlwooM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692965; c=relaxed/simple; bh=mB3EmY4L8UVv1yUNzGfufjLv8z0elMsZvlto+EA/uYI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gApfakrtUAMt/CUl3LpBE4SXeZUAp1tGhx8+NQvr3hABbg61u+wrAGehVRnStgQd7ZI0megXbs/sYz3kDVUjrDydQXX+89FRh4Dd5GK/9/s+X9sHPNL22+V+o+XBNVTginx8WQkcDtsz7g+KNaSnC3BVs0/IE7VM++Dj9w8pfG8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tKg+Z+BA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tKg+Z+BA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 25849C433C7; Sun, 17 Mar 2024 16:29:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692964; bh=mB3EmY4L8UVv1yUNzGfufjLv8z0elMsZvlto+EA/uYI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=tKg+Z+BAyfPF19piV2ReYcZmFcRZHbNdLfDEutk5aWKqZaAdfNCZxV3+EYLw5P7Va WVUZ7B8AHdo1U+dzZGDaOetTEdhCPfis/B5BGiFJ58TKU05k0rgQpwh4ra1MBbJ4yX 1MXH94takYTYt6FJ/KjI7F82JxXSx9Czj+bYJB2PL2gzySFGyvu4OoqpMIxGNiXTaJ oQQPY+IKGxoRRixKV25MF/62VDuwgAgowPu4Q2k+vxJ5I8bH3bAfWkJDb/pY7Euea1 YCRU7OWpdY2CmHNBP/B5kLbry0T/Qb6Xev9qezkaBUiYK1ZTp7BV26pbedjttwemz0 eSsWV+/c3Qn6A== Date: Sun, 17 Mar 2024 09:29:23 -0700 Subject: [PATCH 23/40] xfs: don't allow to enable DAX on fs-verity sealed inode From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246281.2684506.9599077093147119528.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn fs-verity doesn't support DAX. Forbid filesystem to enable DAX on inodes which already have fs-verity enabled. The opposite is checked when fs-verity is enabled, it won't be enabled if DAX is. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: fix typo in subject] Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_iops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 0e5cdb82b231..6f97d777f702 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -1213,6 +1213,8 @@ xfs_inode_should_enable_dax( return false; if (!xfs_inode_supports_dax(ip)) return false; + if (ip->i_diflags2 & XFS_DIFLAG2_VERITY) + return false; if (xfs_has_dax_always(ip->i_mount)) return true; if (ip->i_diflags2 & XFS_DIFLAG2_DAX) From patchwork Sun Mar 17 16:29:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594628 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 34CBA1CD06; Sun, 17 Mar 2024 16:29:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692980; cv=none; b=rqdArwhPITaQ4n39AxR3yX2PB0wsFncaXyhrXuVuUfkLfuB0VcXt0nrUEsHEyHYvm7OYtAPuF7tJcLvtV1ZYrZsWzAch97AllnE1rqAmrla/Fc1FOcwWhRL0x1NQj8lgU9uARy37DM+qCNLxiFOPB9MzUrtWgosFr42A4bKUlkQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692980; c=relaxed/simple; bh=SlQI136CHhejSV55+uq80fnqYG4X2Ac5Dqu6QQDTOlo=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RRECqywam82nmVm/uP0JNfWtUo67zKiUJDc/mc4lg34RzuRN8XKtayFJhI8Y35Dy5h4G+jbfXivggpu3qhRFN4dybKdBRtqgKqzb+hrF3kjMifPpGFHzZSHSWA0JiHi6Y6uMKzjv3L8AEYkEBQxzF/ariWmlYofHyMNM3y9CpHs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=F2ew47uu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="F2ew47uu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C30FFC433F1; Sun, 17 Mar 2024 16:29:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692979; bh=SlQI136CHhejSV55+uq80fnqYG4X2Ac5Dqu6QQDTOlo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=F2ew47uu+/idrf22JJEXeXC4NyPXh+N0wv48dRdFC1ercnuX5yfFcGxm8G5kEvmIf c+Hh4YfvRu0DA8l8NZGJyfVFMavdnq0mboSRcn3us7I5YNTZPBv+2K6SHWgpF5KBq+ fI9CDU9wOa6cVJue45ZlPy8p+H61xMvPYO+nf54JnqP/4J/26kNpQ/PIo3xwSqwu6R qG8tUcQrHR0BqM+1EG3gnjP04A8r46kEvm8KdH3cncC+ZMFEgya++Jwjw8FjECESLv RHy3MiAJnsyGmjpxeSHfHDygV/y5kFhxtOalSBgewp/n1GeKnBsS2qjvYuE5Tu/EXY tyqNlIn6N8Sgw== Date: Sun, 17 Mar 2024 09:29:39 -0700 Subject: [PATCH 24/40] xfs: disable direct read path for fs-verity files From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246296.2684506.17423583037447505680.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn The direct path is not supported on verity files. Attempts to use direct I/O path on such files should fall back to buffered I/O path. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: fix braces] Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_file.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 74dba917be93..0ce51a020115 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -281,7 +281,8 @@ xfs_file_dax_read( struct kiocb *iocb, struct iov_iter *to) { - struct xfs_inode *ip = XFS_I(iocb->ki_filp->f_mapping->host); + struct inode *inode = iocb->ki_filp->f_mapping->host; + struct xfs_inode *ip = XFS_I(inode); ssize_t ret = 0; trace_xfs_file_dax_read(iocb, to); @@ -334,10 +335,18 @@ xfs_file_read_iter( if (IS_DAX(inode)) ret = xfs_file_dax_read(iocb, to); - else if (iocb->ki_flags & IOCB_DIRECT) + else if (iocb->ki_flags & IOCB_DIRECT && !fsverity_active(inode)) ret = xfs_file_dio_read(iocb, to); - else + else { + /* + * In case fs-verity is enabled, we also fallback to the + * buffered read from the direct read path. Therefore, + * IOCB_DIRECT is set and need to be cleared (see + * generic_file_read_iter()) + */ + iocb->ki_flags &= ~IOCB_DIRECT; ret = xfs_file_buffered_read(iocb, to); + } if (ret > 0) XFS_STATS_ADD(mp, xs_read_bytes, ret); From patchwork Sun Mar 17 16:29:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594629 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 022561CD06; Sun, 17 Mar 2024 16:29:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692996; cv=none; b=ahPy93p203YF1tK20a/WATLvdKUI8gKMUccnOU8bXjuq8mE0cr2fhlVhVpN1Ztkcrgs1bxpppYk2vwrwaMKRRjmIr7uqoMYTktHwxX9CO3LgafgqZqvT8rLN4DjjLlvul3Q7uNgtc0MZEx46X+2tSfme5DZXluuVT4lsTGxVwqM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710692996; c=relaxed/simple; bh=el7fu9wQ+wCYZSmj8Df/MzRCK0qEMwnhbP3oOjYhriU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TF7GyDIFTZW+YmMJdZbWuUy5gLMz3zBDnVDqU0dZPREoyh0CVpviPh62Xs3adNS3Zudalor8MEbbpTdwLn929qnwJn69FsfyDUpIBgFl4VI31HvyDKuemjHloM4uzUgaSAik9wa4J7apnaiQIUXrzD6bXgICKh2tRtDfG/Kj2PA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=G31A+1Gq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="G31A+1Gq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F233C433C7; Sun, 17 Mar 2024 16:29:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710692995; bh=el7fu9wQ+wCYZSmj8Df/MzRCK0qEMwnhbP3oOjYhriU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=G31A+1GqRB5TrXVvZxZA0GCO1dwFGkhgyVYmEOHDaWb7EqkeTGTdHGXKXKVS4Q7fJ iJDNQstJFimSSy6DZN2E5nT75uPv7LUhcAKNN6Rzo0ivtFvTl5m4zxnT1x0EOw6YAE Vh7r7mpybIh3Bu9IQKOop4o0+PhQvYSi8cBr/85VdvEVu6ObN7+b6EQXi2WugXPqX+ YpvpPECo1BpNf5aS5qyB0yzsdiCSmOaH58UFFrVhJDFMYTZJvjXvnAwCjFKeW3+4J5 4R5fcnLMzy+Vm+AbZJySLGb1oPapekfJwaCiExq3e6RCuUz2ZsGP6+4t9XYLMyacAc EDIXHo9+e95Ng== Date: Sun, 17 Mar 2024 09:29:54 -0700 Subject: [PATCH 25/40] xfs: widen flags argument to the xfs_iflags_* helpers From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246312.2684506.1372758293673496541.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong xfs_inode.i_flags is an unsigned long, so make these helpers take that as the flags argument instead of unsigned short. This is needed for the next patch. Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_inode.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index ab46ffb3ac19..3ea3a6f26ceb 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -207,13 +207,13 @@ xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size) * i_flags helper functions */ static inline void -__xfs_iflags_set(xfs_inode_t *ip, unsigned short flags) +__xfs_iflags_set(xfs_inode_t *ip, unsigned long flags) { ip->i_flags |= flags; } static inline void -xfs_iflags_set(xfs_inode_t *ip, unsigned short flags) +xfs_iflags_set(xfs_inode_t *ip, unsigned long flags) { spin_lock(&ip->i_flags_lock); __xfs_iflags_set(ip, flags); @@ -221,7 +221,7 @@ xfs_iflags_set(xfs_inode_t *ip, unsigned short flags) } static inline void -xfs_iflags_clear(xfs_inode_t *ip, unsigned short flags) +xfs_iflags_clear(xfs_inode_t *ip, unsigned long flags) { spin_lock(&ip->i_flags_lock); ip->i_flags &= ~flags; @@ -229,13 +229,13 @@ xfs_iflags_clear(xfs_inode_t *ip, unsigned short flags) } static inline int -__xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) +__xfs_iflags_test(xfs_inode_t *ip, unsigned long flags) { return (ip->i_flags & flags); } static inline int -xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) +xfs_iflags_test(xfs_inode_t *ip, unsigned long flags) { int ret; spin_lock(&ip->i_flags_lock); @@ -245,7 +245,7 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) } static inline int -xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) +xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned long flags) { int ret; @@ -258,7 +258,7 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) } static inline int -xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags) +xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned long flags) { int ret; From patchwork Sun Mar 17 16:30:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594630 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BEA16EBB; Sun, 17 Mar 2024 16:30:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693011; cv=none; b=cFr/IdgdAUibLrUrGIFzIUiyxAprkrF4mk1+U/nPfFPRoWrfMfyMdtZfhW6LkC2qNXPQ8cb+D8kP/0rf0edUcsu/l317IlFYYXdWMJ6274LUG2Ng+ODoUUaDz5eASkggWMMQSb7LQt5xBUNpj3NOpmAitwxAa/o3yndlN3eekpA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693011; c=relaxed/simple; bh=V1/V6h45DUMX2FL87CZxri0fBT3wZT1G8pf6BXyZud8=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QMEObu48CWsUjgs9fubIKWkJsgBAIzdL6mby3powCVVydkw0uIrYYvGM5amH/RxNBInapQKymqx/ahzNixbRa+8vDFeKN2LUZCOpw3vt1ptsPTci4Yp7MkpwR+TC4MRSbP+UyVwnvJjQmJqf+l2vh19WLjERSigPexRQmSG+Nik= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pKgm7oZX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pKgm7oZX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 24D87C433F1; Sun, 17 Mar 2024 16:30:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693011; bh=V1/V6h45DUMX2FL87CZxri0fBT3wZT1G8pf6BXyZud8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=pKgm7oZXq/8om/pG0q7NRM/juN9OstLAJeMGrXWlLPcesxCVWlEeEGlBv1qjX5sMr a+yjZ5G154fO84xdr54wdjUtcjDY6y/Jnx4juG2HL8wTrNXzU49RrCYmYFzJxUHAhJ 6EwceAoboKkyhdNxG7jw8s32lwEblIomA98SOhEla2r+W0HPrnCugrsrrTaQd1Pu2s AqOtgfZIe6ssLOZ7YUNyVx6C4xpc+Sr6eVLljxLFi1Wgq3AvyL3yNYYTWHAXMPltMZ y+/2A5RuMyrgTjeXj53JHaQqL9aBE94gi/fSeCUTQLkZOijnj7zEO4u7a1LWGY2sPP hXQVPoZuYFMWw== Date: Sun, 17 Mar 2024 09:30:10 -0700 Subject: [PATCH 26/40] xfs: add fs-verity support From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246327.2684506.14573441099126414062.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn Add integration with fs-verity. The XFS store fs-verity metadata in the extended file attributes. The metadata consist of verity descriptor and Merkle tree blocks. The descriptor is stored under "vdesc" extended attribute. The Merkle tree blocks are stored under binary indexes which are offsets into the Merkle tree. When fs-verity is enabled on an inode, the XFS_IVERITY_CONSTRUCTION flag is set meaning that the Merkle tree is being build. The initialization ends with storing of verity descriptor and setting inode on-disk flag (XFS_DIFLAG2_VERITY). The verification on read is done in read path of iomap. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: replace caching implementation with an xarray, other cleanups] Signed-off-by: Darrick J. Wong --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_attr.c | 13 + fs/xfs/libxfs/xfs_da_format.h | 32 +++ fs/xfs/libxfs/xfs_ondisk.h | 4 fs/xfs/xfs_icache.c | 4 fs/xfs/xfs_inode.h | 5 fs/xfs/xfs_super.c | 12 + fs/xfs/xfs_trace.h | 32 +++ fs/xfs/xfs_verity.c | 468 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_verity.h | 20 ++ 10 files changed, 591 insertions(+) create mode 100644 fs/xfs/xfs_verity.c create mode 100644 fs/xfs/xfs_verity.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index f8845e65cac7..8396a633b541 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -130,6 +130,7 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o +xfs-$(CONFIG_FS_VERITY) += xfs_verity.o # notify failure ifeq ($(CONFIG_MEMORY_FAILURE),y) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index f0b625d45aa4..b7aa1bc12fd1 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -27,6 +27,7 @@ #include "xfs_attr_item.h" #include "xfs_xattr.h" #include "xfs_parent.h" +#include "xfs_verity.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1524,6 +1525,18 @@ xfs_attr_namecheck( if (flags & XFS_ATTR_PARENT) return xfs_parent_namecheck(mp, name, length, flags); + if (flags & XFS_ATTR_VERITY) { + /* Merkle tree pages are stored under u64 indexes */ + if (length == sizeof(struct xfs_verity_merkle_key)) + return true; + + /* Verity descriptor blocks are held in a named attribute. */ + if (length == XFS_VERITY_DESCRIPTOR_NAME_LEN) + return true; + + return false; + } + /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 28d4ac6fa156..e4aa7c9a0ccb 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -914,4 +914,36 @@ struct xfs_parent_name_rec { */ #define XFS_PARENT_DIRENT_NAME_MAX_SIZE (MAXNAMELEN - 1) +/* + * fs-verity attribute name format + * + * Merkle tree blocks are stored under extended attributes of the inode. The + * name of the attributes are byte offsets into merkle tree. + */ +struct xfs_verity_merkle_key { + __be64 vi_merkleoff; +}; + +static inline void +xfs_verity_merkle_key_to_disk( + struct xfs_verity_merkle_key *key, + uint64_t offset) +{ + key->vi_merkleoff = cpu_to_be64(offset); +} + +static inline uint64_t +xfs_verity_merkle_key_from_disk( + const void *attr_name) +{ + const struct xfs_verity_merkle_key *key = attr_name; + + return be64_to_cpu(key->vi_merkleoff); +} + + +/* ondisk xattr name used for the fsverity descriptor */ +#define XFS_VERITY_DESCRIPTOR_NAME "vdesc" +#define XFS_VERITY_DESCRIPTOR_NAME_LEN (sizeof(XFS_VERITY_DESCRIPTOR_NAME) - 1) + #endif /* __XFS_DA_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h index 81885a6a028e..16f4ef2fbeaf 100644 --- a/fs/xfs/libxfs/xfs_ondisk.h +++ b/fs/xfs/libxfs/xfs_ondisk.h @@ -194,6 +194,10 @@ xfs_check_ondisk_structs(void) XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MIN << XFS_DQ_BIGTIME_SHIFT, 4); XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MAX << XFS_DQ_BIGTIME_SHIFT, 16299260424LL); + + /* fs-verity xattrs */ + XFS_CHECK_STRUCT_SIZE(struct xfs_verity_merkle_key, 8); + XFS_CHECK_VALUE(sizeof(XFS_VERITY_DESCRIPTOR_NAME), 6); } #endif /* __XFS_ONDISK_H */ diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index e64265bc0b33..fef77938c718 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -25,6 +25,7 @@ #include "xfs_ag.h" #include "xfs_log_priv.h" #include "xfs_health.h" +#include "xfs_verity.h" #include @@ -115,6 +116,7 @@ xfs_inode_alloc( spin_lock_init(&ip->i_ioend_lock); ip->i_next_unlinked = NULLAGINO; ip->i_prev_unlinked = 0; + xfs_verity_cache_init(ip); return ip; } @@ -126,6 +128,8 @@ xfs_inode_free_callback( struct inode *inode = container_of(head, struct inode, i_rcu); struct xfs_inode *ip = XFS_I(inode); + xfs_verity_cache_destroy(ip); + switch (VFS_I(ip)->i_mode & S_IFMT) { case S_IFREG: case S_IFDIR: diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 3ea3a6f26ceb..cb2e43e5cd43 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -92,6 +92,9 @@ typedef struct xfs_inode { spinlock_t i_ioend_lock; struct work_struct i_ioend_work; struct list_head i_ioend_list; +#ifdef CONFIG_FS_VERITY + struct xarray i_merkle_blocks; +#endif } xfs_inode_t; static inline bool xfs_inode_on_unlinked_list(const struct xfs_inode *ip) @@ -361,6 +364,8 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip) */ #define XFS_IREMAPPING (1U << 15) +#define XFS_VERITY_CONSTRUCTION (1U << 16) /* merkle tree construction */ + /* All inode state flags related to inode reclaim. */ #define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \ XFS_IRECLAIM | \ diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index a09739beb8f3..1f96dff5731e 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -30,6 +30,7 @@ #include "xfs_filestream.h" #include "xfs_quota.h" #include "xfs_sysfs.h" +#include "xfs_verity.h" #include "xfs_ondisk.h" #include "xfs_rmap_item.h" #include "xfs_refcount_item.h" @@ -666,6 +667,8 @@ xfs_fs_destroy_inode( XFS_STATS_INC(ip->i_mount, vn_rele); XFS_STATS_INC(ip->i_mount, vn_remove); fsverity_cleanup_inode(inode); + if (IS_VERITY(inode)) + xfs_verity_cache_drop(ip); xfs_inode_mark_reclaimable(ip); } @@ -1521,6 +1524,11 @@ xfs_fs_fill_super( sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; #endif sb->s_op = &xfs_super_operations; +#ifdef CONFIG_FS_VERITY + error = fsverity_set_ops(sb, &xfs_verity_ops); + if (error) + return error; +#endif /* * Delay mount work if the debug hook is set. This is debug @@ -1730,6 +1738,10 @@ xfs_fs_fill_super( goto out_filestream_unmount; } + if (xfs_has_verity(mp)) + xfs_alert(mp, + "EXPERIMENTAL fs-verity feature in use. Use at your own risk!"); + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount; diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 9d4ae05abfc8..23abec742c3b 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -4767,6 +4767,38 @@ DEFINE_XFBTREE_FREESP_EVENT(xfbtree_alloc_block); DEFINE_XFBTREE_FREESP_EVENT(xfbtree_free_block); #endif /* CONFIG_XFS_BTREE_IN_MEM */ +#ifdef CONFIG_FS_VERITY +DECLARE_EVENT_CLASS(xfs_verity_cache_class, + TP_PROTO(struct xfs_inode *ip, unsigned long key, unsigned long caller_ip), + TP_ARGS(ip, key, caller_ip), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned long, key) + __field(void *, caller_ip) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->key = key; + __entry->caller_ip = (void *)caller_ip; + ), + TP_printk("dev %d:%d ino 0x%llx key 0x%lx caller %pS", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->key, + __entry->caller_ip) +) + +#define DEFINE_XFS_VERITY_CACHE_EVENT(name) \ +DEFINE_EVENT(xfs_verity_cache_class, name, \ + TP_PROTO(struct xfs_inode *ip, unsigned long key, unsigned long caller_ip), \ + TP_ARGS(ip, key, caller_ip)) +DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_load); +DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_store); +DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_drop); +#endif /* CONFIG_XFS_VERITY */ + #endif /* _TRACE_XFS_H */ #undef TRACE_INCLUDE_PATH diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c new file mode 100644 index 000000000000..69b54e70e312 --- /dev/null +++ b/fs/xfs/xfs_verity.c @@ -0,0 +1,468 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ +#include "xfs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_inode.h" +#include "xfs_log_format.h" +#include "xfs_attr.h" +#include "xfs_verity.h" +#include "xfs_bmap_util.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_attr_leaf.h" +#include "xfs_trace.h" +#include + +/* + * Merkle Tree Block Cache + * ======================= + * + * fsverity requires that the filesystem implement caching of ondisk merkle + * tree blocks. XFS stores merkle tree blocks in the extended attribute data, + * which makes it important to keep copies in memory for as long as possible. + * This is performed by allocating the data blob structure defined below, + * passing the data portion of the blob to xfs_attr_get, and later adding the + * data blob to an xarray embedded in the xfs_inode structure. + * + * The xarray structure indexes merkle tree blocks by the offset given to us by + * fsverity, which drastically reduces lookups. First, it eliminating the need + * to walk the xattr structure to find the remote block containing the merkle + * tree block. Second, access to each block in the xattr structure requires a + * lookup in the incore extent btree. + */ +struct xfs_merkle_blob { + /* refcount of this item; the cache holds its own ref */ + refcount_t refcount; + + unsigned long flags; + + /* Pointer to the merkle tree block, which is power-of-2 sized */ + void *data; +}; + +#define XFS_MERKLE_BLOB_VERIFIED_BIT (0) /* fsverity validated this */ + +/* + * Allocate a merkle tree blob object to prepare for reading a merkle tree + * object from disk. + */ +static inline struct xfs_merkle_blob * +xfs_merkle_blob_alloc( + unsigned int blocksize) +{ + struct xfs_merkle_blob *mk; + + mk = kmalloc(sizeof(struct xfs_merkle_blob), GFP_KERNEL); + if (!mk) + return NULL; + + mk->data = kvzalloc(blocksize, GFP_KERNEL); + if (!mk->data) { + kfree(mk); + return NULL; + } + + /* Caller owns this refcount. */ + refcount_set(&mk->refcount, 1); + mk->flags = 0; + return mk; +} + +/* Free a merkle tree blob. */ +static inline void +xfs_merkle_blob_rele( + struct xfs_merkle_blob *mk) +{ + if (refcount_dec_and_test(&mk->refcount)) { + kvfree(mk->data); + kfree(mk); + } +} + +/* Initialize the merkle tree block cache */ +void +xfs_verity_cache_init( + struct xfs_inode *ip) +{ + xa_init(&ip->i_merkle_blocks); +} + +/* + * Drop all the merkle tree blocks out of the cache. Caller must ensure that + * there are no active references to cache items. + */ +void +xfs_verity_cache_drop( + struct xfs_inode *ip) +{ + XA_STATE(xas, &ip->i_merkle_blocks, 0); + struct xfs_merkle_blob *mk; + unsigned long flags; + + xas_lock_irqsave(&xas, flags); + xas_for_each(&xas, mk, ULONG_MAX) { + ASSERT(refcount_read(&mk->refcount) == 1); + + trace_xfs_verity_cache_drop(ip, xas.xa_index, _RET_IP_); + + xas_store(&xas, NULL); + xfs_merkle_blob_rele(mk); + } + xas_unlock_irqrestore(&xas, flags); +} + +/* Destroy the merkle tree block cache */ +void +xfs_verity_cache_destroy( + struct xfs_inode *ip) +{ + ASSERT(xa_empty(&ip->i_merkle_blocks)); + + /* + * xa_destroy calls xas_lock from rcu freeing softirq context, so + * we must use xa*_lock_irqsave. + */ + xa_destroy(&ip->i_merkle_blocks); +} + +/* Return a cached merkle tree block, or NULL. */ +static struct xfs_merkle_blob * +xfs_verity_cache_load( + struct xfs_inode *ip, + unsigned long key) +{ + XA_STATE(xas, &ip->i_merkle_blocks, key); + struct xfs_merkle_blob *mk; + + /* Look up the cached item and try to get an active ref. */ + rcu_read_lock(); + do { + mk = xas_load(&xas); + if (xa_is_zero(mk)) + mk = NULL; + } while (xas_retry(&xas, mk) || + (mk && !refcount_inc_not_zero(&mk->refcount))); + rcu_read_unlock(); + + if (!mk) + return NULL; + + trace_xfs_verity_cache_load(ip, key, _RET_IP_); + return mk; +} + +/* + * Try to store a merkle tree block in the cache with the given key. + * + * If the merkle tree block is not already in the cache, the given block @mk + * will be added to the cache and returned. The caller retains its active + * reference to @mk. + * + * If there was already a merkle block in the cache, it will be returned to + * the caller with an active reference. @mk will be untouched. + */ +static struct xfs_merkle_blob * +xfs_verity_cache_store( + struct xfs_inode *ip, + unsigned long key, + struct xfs_merkle_blob *mk) +{ + struct xfs_merkle_blob *old; + unsigned long flags; + + trace_xfs_verity_cache_store(ip, key, _RET_IP_); + + /* + * Either replace a NULL entry with mk, or take an active ref to + * whatever's currently there. + */ + xa_lock_irqsave(&ip->i_merkle_blocks, flags); + do { + old = __xa_cmpxchg(&ip->i_merkle_blocks, key, NULL, mk, + GFP_KERNEL); + } while (old && !refcount_inc_not_zero(&old->refcount)); + xa_unlock_irqrestore(&ip->i_merkle_blocks, flags); + + if (old == NULL) { + /* + * There was no previous value. @mk is now live in the cache. + * Bump the active refcount to transfer ownership to the cache + * and return @mk to the caller. + */ + refcount_inc(&mk->refcount); + return mk; + } + + /* + * We obtained an active reference to a previous value in the cache. + * Return it to the caller. + */ + return old; +} + +static int +xfs_verity_get_descriptor( + struct inode *inode, + void *buf, + size_t buf_size) +{ + struct xfs_inode *ip = XFS_I(inode); + int error = 0; + struct xfs_da_args args = { + .dp = ip, + .attr_filter = XFS_ATTR_VERITY, + .name = (const uint8_t *)XFS_VERITY_DESCRIPTOR_NAME, + .namelen = XFS_VERITY_DESCRIPTOR_NAME_LEN, + .value = buf, + .valuelen = buf_size, + }; + + /* + * The fact that (returned attribute size) == (provided buf_size) is + * checked by xfs_attr_copy_value() (returns -ERANGE) + */ + error = xfs_attr_get(&args); + if (error) + return error; + + return args.valuelen; +} + +static int +xfs_verity_begin_enable( + struct file *filp, + u64 merkle_tree_size, + unsigned int tree_blocksize) +{ + struct inode *inode = file_inode(filp); + struct xfs_inode *ip = XFS_I(inode); + int error = 0; + + xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL); + + if (IS_DAX(inode)) + return -EINVAL; + + if (xfs_iflags_test_and_set(ip, XFS_VERITY_CONSTRUCTION)) + return -EBUSY; + + return error; +} + +static int +xfs_drop_merkle_tree( + struct xfs_inode *ip, + u64 merkle_tree_size, + unsigned int tree_blocksize) +{ + struct xfs_verity_merkle_key name; + int error = 0; + u64 offset = 0; + struct xfs_da_args args = { + .dp = ip, + .whichfork = XFS_ATTR_FORK, + .attr_filter = XFS_ATTR_VERITY, + .op_flags = XFS_DA_OP_REMOVE, + .name = (const uint8_t *)&name, + .namelen = sizeof(struct xfs_verity_merkle_key), + /* NULL value make xfs_attr_set remove the attr */ + .value = NULL, + }; + + if (!merkle_tree_size) + return 0; + + for (offset = 0; offset < merkle_tree_size; offset += tree_blocksize) { + xfs_verity_merkle_key_to_disk(&name, offset); + error = xfs_attr_set(&args); + if (error) + return error; + } + + args.name = (const uint8_t *)XFS_VERITY_DESCRIPTOR_NAME; + args.namelen = XFS_VERITY_DESCRIPTOR_NAME_LEN; + error = xfs_attr_set(&args); + + return error; +} + +static int +xfs_verity_end_enable( + struct file *filp, + const void *desc, + size_t desc_size, + u64 merkle_tree_size, + unsigned int tree_blocksize) +{ + struct inode *inode = file_inode(filp); + struct xfs_inode *ip = XFS_I(inode); + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + struct xfs_da_args args = { + .dp = ip, + .whichfork = XFS_ATTR_FORK, + .attr_filter = XFS_ATTR_VERITY, + .name = (const uint8_t *)XFS_VERITY_DESCRIPTOR_NAME, + .namelen = XFS_VERITY_DESCRIPTOR_NAME_LEN, + .value = (void *)desc, + .valuelen = desc_size, + }; + int error = 0; + + xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL); + + /* fs-verity failed, just cleanup */ + if (desc == NULL) + goto out; + + error = xfs_attr_set(&args); + if (error) + goto out; + + /* Set fsverity inode flag */ + error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange, + 0, 0, false, &tp); + if (error) + goto out; + + /* + * Ensure that we've persisted the verity information before we enable + * it on the inode and tell the caller we have sealed the inode. + */ + ip->i_diflags2 |= XFS_DIFLAG2_VERITY; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + + error = xfs_trans_commit(tp); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + if (!error) + inode->i_flags |= S_VERITY; + +out: + if (error) + WARN_ON_ONCE(xfs_drop_merkle_tree(ip, merkle_tree_size, + tree_blocksize)); + + xfs_iflags_clear(ip, XFS_VERITY_CONSTRUCTION); + return error; +} + +static int +xfs_verity_read_merkle( + const struct fsverity_readmerkle *req, + struct fsverity_blockbuf *block) +{ + struct xfs_inode *ip = XFS_I(req->inode); + struct xfs_verity_merkle_key name; + struct xfs_da_args args = { + .dp = ip, + .attr_filter = XFS_ATTR_VERITY, + .name = (const uint8_t *)&name, + .namelen = sizeof(struct xfs_verity_merkle_key), + .valuelen = block->size, + }; + struct xfs_merkle_blob *mk, *new_mk; + unsigned long key = block->offset >> req->log_blocksize; + int error; + + ASSERT(block->offset >> req->log_blocksize <= ULONG_MAX); + + xfs_verity_merkle_key_to_disk(&name, block->offset); + + /* Is the block already cached? */ + mk = xfs_verity_cache_load(ip, key); + if (mk) + goto out_hit; + + new_mk = xfs_merkle_blob_alloc(block->size); + if (!new_mk) + return -ENOMEM; + args.value = new_mk->data; + + /* Read the block in from disk and try to store it in the cache. */ + xfs_verity_merkle_key_to_disk(&name, block->offset); + + error = xfs_attr_get(&args); + if (error) + goto out_new_mk; + + if (!args.valuelen) { + error = -ENODATA; + goto out_new_mk; + } + + mk = xfs_verity_cache_store(ip, key, new_mk); + if (mk != new_mk) { + /* + * We raced with another thread to populate the cache and lost. + * Free the new cache blob and continue with the existing one. + */ + xfs_merkle_blob_rele(new_mk); + } + +out_hit: + block->kaddr = (void *)mk->data; + block->context = mk; + block->verified = test_bit(XFS_MERKLE_BLOB_VERIFIED_BIT, &mk->flags); + + return 0; + +out_new_mk: + xfs_merkle_blob_rele(new_mk); + return error; +} + +static int +xfs_verity_write_merkle( + const struct fsverity_writemerkle *req, + const void *buf, + u64 pos, + unsigned int size) +{ + struct inode *inode = req->inode; + struct xfs_inode *ip = XFS_I(inode); + struct xfs_verity_merkle_key name; + struct xfs_da_args args = { + .dp = ip, + .whichfork = XFS_ATTR_FORK, + .attr_filter = XFS_ATTR_VERITY, + .name = (const uint8_t *)&name, + .namelen = sizeof(struct xfs_verity_merkle_key), + .value = (void *)buf, + .valuelen = size, + }; + + xfs_verity_merkle_key_to_disk(&name, pos); + return xfs_attr_set(&args); +} + +static void +xfs_verity_drop_merkle( + struct fsverity_blockbuf *block) +{ + struct xfs_merkle_blob *mk = block->context; + + if (block->verified) + set_bit(XFS_MERKLE_BLOB_VERIFIED_BIT, &mk->flags); + xfs_merkle_blob_rele(mk); + block->kaddr = NULL; + block->context = NULL; +} + +const struct fsverity_operations xfs_verity_ops = { + .begin_enable_verity = xfs_verity_begin_enable, + .end_enable_verity = xfs_verity_end_enable, + .get_verity_descriptor = xfs_verity_get_descriptor, + .read_merkle_tree_block = xfs_verity_read_merkle, + .write_merkle_tree_block = xfs_verity_write_merkle, + .drop_merkle_tree_block = xfs_verity_drop_merkle, +}; diff --git a/fs/xfs/xfs_verity.h b/fs/xfs/xfs_verity.h new file mode 100644 index 000000000000..31d51482f7f7 --- /dev/null +++ b/fs/xfs/xfs_verity.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ +#ifndef __XFS_VERITY_H__ +#define __XFS_VERITY_H__ + +#ifdef CONFIG_FS_VERITY +void xfs_verity_cache_init(struct xfs_inode *ip); +void xfs_verity_cache_drop(struct xfs_inode *ip); +void xfs_verity_cache_destroy(struct xfs_inode *ip); + +extern const struct fsverity_operations xfs_verity_ops; +#else +# define xfs_verity_cache_init(ip) ((void)0) +# define xfs_verity_cache_drop(ip) ((void)0) +# define xfs_verity_cache_destroy(ip) ((void)0) +#endif /* CONFIG_FS_VERITY */ + +#endif /* __XFS_VERITY_H__ */ From patchwork Sun Mar 17 16:30:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594631 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FDDF36D; Sun, 17 Mar 2024 16:30:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693027; cv=none; b=rrfGnnj3fc31IjQOsDZ42xbuSIPjqAyUlUIhmfJvaIy1FwGbIEHMq6VbZvDXr8AiM0gRz0NZBUhFyCneQZ2oTfgC7moItoRj8VpX96cORBGmnb9eibl0eiZTi7it20uFmYiNAU5SsQ8uxuA2pBwLYvF1KpYCNiLN9XBljZ61c68= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693027; c=relaxed/simple; bh=IMUik4hsII1rW6DSqSBj29hYhWJPIrfzGu1jqCLlK6w=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=AqLJ+IGb8M0OpoplrZJ/VcTANK6h9HJ0QJ1uStvpNul8FCXhxzTEI2SkOtcB1CQCLvA9AudMPNY7P2UQpGSI2NyA2gL1vIMTy+qVloWONJbnnGwdBi6+E4De5JhLeyNAhV5qwQgqyfFeQpTZNe+wjQI4C7vliOUmbe9BgsF1+EM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pt6rJlMH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pt6rJlMH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CC077C433C7; Sun, 17 Mar 2024 16:30:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693026; bh=IMUik4hsII1rW6DSqSBj29hYhWJPIrfzGu1jqCLlK6w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=pt6rJlMHaDPvHqu97qGb/aAcuurZmVqmRhTlRT8CgmwOkOFXdpSbE/Z5D1+kkXot/ AFXnxitELvf0oIHHXV9v0/TsKKZP1PzAEQtGmKCCxsmjswXDHYA/sPMM6P363d8F7k sxjrf47gSsriy0qYHIqIDOVqTGiFy3hLVkpM9JXaf0x8y/KeKKb98DnJFsg6HmqILh SMb2PKySe/vq7LKl5zZvKf1xCtHAPoR0gD4Yra71mZmgKXaUwgEmxYrFHWbOqm4cPC XjCbt1vsc/QnxlUoBOlv5mFtVP6JdAaJU9jGuOKcpp4ROkEijJYkUCNmwuJL9SiTPs jWHb+loRnMXNQ== Date: Sun, 17 Mar 2024 09:30:26 -0700 Subject: [PATCH 27/40] xfs: create a per-mount shrinker for verity inodes merkle tree blocks From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246344.2684506.2186413865852816494.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a shrinker for an entire filesystem that will walk the inodes looking for inodes that are caching merkle tree blocks, and invoke shrink functions on that cache. The actual details of shrinking merkle tree caches are left for subsequent patches. Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_mount.c | 10 ++++++- fs/xfs/xfs_mount.h | 6 ++++ fs/xfs/xfs_trace.h | 20 +++++++++++++ fs/xfs/xfs_verity.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_verity.h | 5 +++ 5 files changed, 117 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 7328034d42ed..4b5b74809cff 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -34,6 +34,7 @@ #include "xfs_health.h" #include "xfs_trace.h" #include "xfs_ag.h" +#include "xfs_verity.h" #include "scrub/stats.h" static DEFINE_MUTEX(xfs_uuid_table_mutex); @@ -813,6 +814,10 @@ xfs_mountfs( if (error) goto out_fail_wait; + error = xfs_verity_register_shrinker(mp); + if (error) + goto out_inodegc_shrinker; + /* * Log's mount-time initialization. The first part of recovery can place * some items on the AIL, to be handled when recovery is finished or @@ -823,7 +828,7 @@ xfs_mountfs( XFS_FSB_TO_BB(mp, sbp->sb_logblocks)); if (error) { xfs_warn(mp, "log mount failed"); - goto out_inodegc_shrinker; + goto out_verity_shrinker; } /* Enable background inode inactivation workers. */ @@ -1018,6 +1023,8 @@ xfs_mountfs( xfs_unmount_flush_inodes(mp); out_log_dealloc: xfs_log_mount_cancel(mp); + out_verity_shrinker: + xfs_verity_unregister_shrinker(mp); out_inodegc_shrinker: shrinker_free(mp->m_inodegc_shrinker); out_fail_wait: @@ -1100,6 +1107,7 @@ xfs_unmountfs( #if defined(DEBUG) xfs_errortag_clearall(mp); #endif + xfs_verity_unregister_shrinker(mp); shrinker_free(mp->m_inodegc_shrinker); xfs_free_perag(mp); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f198d7c82552..855517583ce6 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -255,6 +255,12 @@ typedef struct xfs_mount { /* Hook to feed dirent updates to an active online repair. */ struct xfs_hooks m_dir_update_hooks; + +#ifdef CONFIG_FS_VERITY + /* shrinker and cached blocks count for merkle trees */ + struct shrinker *m_verity_shrinker; + struct percpu_counter m_verity_blocks; +#endif } xfs_mount_t; #define M_IGEO(mp) (&(mp)->m_ino_geo) diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 23abec742c3b..fa05122a7c4d 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -4797,6 +4797,26 @@ DEFINE_EVENT(xfs_verity_cache_class, name, \ DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_load); DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_store); DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_drop); + +TRACE_EVENT(xfs_verity_shrinker_count, + TP_PROTO(struct xfs_mount *mp, unsigned long long count, + unsigned long caller_ip), + TP_ARGS(mp, count, caller_ip), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned long long, count) + __field(void *, caller_ip) + ), + TP_fast_assign( + __entry->dev = mp->m_super->s_dev; + __entry->count = count; + __entry->caller_ip = (void *)caller_ip; + ), + TP_printk("dev %d:%d count %llu caller %pS", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->count, + __entry->caller_ip) +) #endif /* CONFIG_XFS_VERITY */ #endif /* _TRACE_XFS_H */ diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index 69b54e70e312..46aa5002e4e1 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -18,6 +18,7 @@ #include "xfs_trans.h" #include "xfs_attr_leaf.h" #include "xfs_trace.h" +#include "xfs_icache.h" #include /* @@ -207,6 +208,82 @@ xfs_verity_cache_store( return old; } +/* Count the merkle tree blocks that we might be able to reclaim. */ +static unsigned long +xfs_verity_shrinker_count( + struct shrinker *shrink, + struct shrink_control *sc) +{ + struct xfs_mount *mp = shrink->private_data; + s64 count; + + if (!xfs_has_verity(mp)) + return SHRINK_EMPTY; + + count = percpu_counter_sum_positive(&mp->m_verity_blocks); + + trace_xfs_verity_shrinker_count(mp, count, _RET_IP_); + return min_t(s64, ULONG_MAX, count); +} + +/* Actually try to reclaim merkle tree blocks. */ +static unsigned long +xfs_verity_shrinker_scan( + struct shrinker *shrink, + struct shrink_control *sc) +{ + struct xfs_mount *mp = shrink->private_data; + + if (!xfs_has_verity(mp)) + return SHRINK_STOP; + + return 0; +} + +/* Register a shrinker so we can release cached merkle tree blocks. */ +int +xfs_verity_register_shrinker( + struct xfs_mount *mp) +{ + int error; + + if (!xfs_has_verity(mp)) + return 0; + + error = percpu_counter_init(&mp->m_verity_blocks, 0, GFP_KERNEL); + if (error) + return error; + + mp->m_verity_shrinker = shrinker_alloc(0, "xfs-verity:%s", + mp->m_super->s_id); + if (!mp->m_verity_shrinker) { + percpu_counter_destroy(&mp->m_verity_blocks); + return -ENOMEM; + } + + mp->m_verity_shrinker->count_objects = xfs_verity_shrinker_count; + mp->m_verity_shrinker->scan_objects = xfs_verity_shrinker_scan; + mp->m_verity_shrinker->seeks = 0; + mp->m_verity_shrinker->private_data = mp; + + shrinker_register(mp->m_verity_shrinker); + + return 0; +} + +/* Unregister the merkle tree block shrinker. */ +void +xfs_verity_unregister_shrinker(struct xfs_mount *mp) +{ + if (!xfs_has_verity(mp)) + return; + + ASSERT(percpu_counter_sum(&mp->m_verity_blocks) == 0); + + shrinker_free(mp->m_verity_shrinker); + percpu_counter_destroy(&mp->m_verity_blocks); +} + static int xfs_verity_get_descriptor( struct inode *inode, diff --git a/fs/xfs/xfs_verity.h b/fs/xfs/xfs_verity.h index 31d51482f7f7..0ec0a61bee65 100644 --- a/fs/xfs/xfs_verity.h +++ b/fs/xfs/xfs_verity.h @@ -10,11 +10,16 @@ void xfs_verity_cache_init(struct xfs_inode *ip); void xfs_verity_cache_drop(struct xfs_inode *ip); void xfs_verity_cache_destroy(struct xfs_inode *ip); +int xfs_verity_register_shrinker(struct xfs_mount *mp); +void xfs_verity_unregister_shrinker(struct xfs_mount *mp); + extern const struct fsverity_operations xfs_verity_ops; #else # define xfs_verity_cache_init(ip) ((void)0) # define xfs_verity_cache_drop(ip) ((void)0) # define xfs_verity_cache_destroy(ip) ((void)0) +# define xfs_verity_register_shrinker(mp) (0) +# define xfs_verity_unregister_shrinker(mp) ((void)0) #endif /* CONFIG_FS_VERITY */ #endif /* __XFS_VERITY_H__ */ From patchwork Sun Mar 17 16:30:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594632 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E99936D; Sun, 17 Mar 2024 16:30:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693043; cv=none; b=q+Am6D9OlvlEtSucH9nizV+2vrcX0VsNN9lk1TVqYxt18TAFSPkzkSXvxt6HFzGcqPpB9bjUZBDbc3dnTm/9X6C/gJrc0tr8I5yQ6Vcs8ogX2xsz+HfKXgPrzxaCv1PFZWwF3wDlXNOogmfyQwkW621dyIZWFZD+IUTbUtZocuU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693043; c=relaxed/simple; bh=HPg0uHo7j99EGWluJBAWme7C4oDdlQfOoK1M8qa1lUg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rz66KAMz+/gVs5XMQL1cpaA0pmh842HK76amfuOTssdzcPtk3RkLM/Lr1fMIhhOnd/rloY7vP923oi57c73oHwlDhqu/18Ip1Z/+drHLgIbgs87aP03eNMglHYVHezHB2oTRu8HaZNezyFREZKR7j+gbeAvYp8jTr3mo2gnuZ9k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aQuZiE64; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aQuZiE64" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 74C4AC433C7; Sun, 17 Mar 2024 16:30:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693042; bh=HPg0uHo7j99EGWluJBAWme7C4oDdlQfOoK1M8qa1lUg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=aQuZiE64hpUJaeYbSvPSSYL2P86HDa21Y32xKq2vM4TdZE7zcyZSJzKyV+7xw6ODK AEHllHl3A9ACeCxaLZ+cPd8pfJEZShmh3WDLTB++1mcI5o1Idk+cDISSl1r1C5AeC9 iPxDwskHgZ99tyGycLipCYd72oQhzJveiq/b/yKe9x11Au7CohiVw8a7TZ5BILlY3l MZdQNRyBDKsRks/OLU8GRBDdR4Dvuuk06g+lMWEoLPjplG2dpDBgialTf5BV3qPBF/ Cs1D01AbYaxYtfKidLnTExRMQ2pFQdFY3wUq5qXCGnfCsb+xoDPJgS37eRlaJrLqwJ QLInjLex8jlfQ== Date: Sun, 17 Mar 2024 09:30:42 -0700 Subject: [PATCH 28/40] xfs: create an icache tag for files with cached merkle tree blocks From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246360.2684506.17126297394323595908.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a radix tree tag for the inode cache so that merkle tree block shrinkers can find verity inodes quickly. Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_icache.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_icache.h | 8 +++++ fs/xfs/xfs_trace.h | 23 ++++++++++++++ fs/xfs/xfs_verity.c | 30 ++++++++++++++++++- fs/xfs/xfs_verity.h | 4 +++ 5 files changed, 145 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index fef77938c718..ad02af0da843 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -35,6 +35,8 @@ #define XFS_ICI_RECLAIM_TAG 0 /* Inode has speculative preallocations (posteof or cow) to clean. */ #define XFS_ICI_BLOCKGC_TAG 1 +/* Inode has incore merkle tree blocks */ +#define XFS_ICI_VERITY_TAG 2 /* * The goal for walking incore inodes. These can correspond with incore inode @@ -44,6 +46,7 @@ enum xfs_icwalk_goal { /* Goals directly associated with tagged inodes. */ XFS_ICWALK_BLOCKGC = XFS_ICI_BLOCKGC_TAG, XFS_ICWALK_RECLAIM = XFS_ICI_RECLAIM_TAG, + XFS_ICWALK_VERITY = XFS_ICI_VERITY_TAG, }; static int xfs_icwalk(struct xfs_mount *mp, @@ -1606,6 +1609,7 @@ xfs_icwalk_igrab( { switch (goal) { case XFS_ICWALK_BLOCKGC: + case XFS_ICWALK_VERITY: return xfs_blockgc_igrab(ip); case XFS_ICWALK_RECLAIM: return xfs_reclaim_igrab(ip, icw); @@ -1634,6 +1638,9 @@ xfs_icwalk_process_inode( case XFS_ICWALK_RECLAIM: xfs_reclaim_inode(ip, pag); break; + case XFS_ICWALK_VERITY: + error = xfs_verity_scan_inode(ip, icw); + break; } return error; } @@ -1750,6 +1757,80 @@ xfs_icwalk_ag( return last_error; } +#ifdef CONFIG_FS_VERITY +/* Mark this inode as having cached merkle tree blocks */ +void +xfs_inode_set_verity_tag( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_perag *pag; + + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); + if (!pag) + return; + + spin_lock(&pag->pag_ici_lock); + xfs_perag_set_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino), + XFS_ICI_VERITY_TAG); + spin_unlock(&pag->pag_ici_lock); + xfs_perag_put(pag); +} + +/* Mark this inode as not having cached merkle tree blocks */ +void +xfs_inode_clear_verity_tag( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_perag *pag; + + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); + if (!pag) + return; + + spin_lock(&pag->pag_ici_lock); + xfs_perag_clear_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino), + XFS_ICI_VERITY_TAG); + spin_unlock(&pag->pag_ici_lock); + xfs_perag_put(pag); +} + +/* Walk all the verity inodes in the filesystem. */ +int +xfs_icwalk_verity( + struct xfs_mount *mp, + struct xfs_icwalk *icw) +{ + struct xfs_perag *pag; + xfs_agnumber_t agno = 0; + int error = 0; + + for_each_perag_tag(mp, agno, pag, XFS_ICWALK_VERITY) { + error = xfs_icwalk_ag(pag, XFS_ICWALK_VERITY, icw); + if (error) + break; + + if ((icw->icw_flags & XFS_ICWALK_FLAG_SCAN_LIMIT) && + icw->icw_scan_limit <= 0) { + xfs_perag_rele(pag); + break; + } + } + + return error; +} + +/* Stop a verity incore walk scan. */ +void +xfs_icwalk_verity_stop( + struct xfs_icwalk *icw) +{ + icw->icw_flags |= XFS_ICWALK_FLAG_SCAN_LIMIT; + icw->icw_scan_limit = -1; +} +#endif /* CONFIG_FS_VERITY */ + /* Walk all incore inodes to achieve a given goal. */ static int xfs_icwalk( diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index 905944dafbe5..621ce0078e08 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h @@ -81,4 +81,12 @@ void xfs_inodegc_stop(struct xfs_mount *mp); void xfs_inodegc_start(struct xfs_mount *mp); int xfs_inodegc_register_shrinker(struct xfs_mount *mp); +#ifdef CONFIG_FS_VERITY +int xfs_icwalk_verity(struct xfs_mount *mp, struct xfs_icwalk *icw); +void xfs_icwalk_verity_stop(struct xfs_icwalk *icw); + +void xfs_inode_set_verity_tag(struct xfs_inode *ip); +void xfs_inode_clear_verity_tag(struct xfs_inode *ip); +#endif /* CONFIG_FS_VERITY */ + #endif diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index fa05122a7c4d..91a73399114e 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -4817,6 +4817,29 @@ TRACE_EVENT(xfs_verity_shrinker_count, __entry->count, __entry->caller_ip) ) + +TRACE_EVENT(xfs_verity_shrinker_scan, + TP_PROTO(struct xfs_mount *mp, unsigned long scanned, + unsigned long freed, unsigned long caller_ip), + TP_ARGS(mp, scanned, freed, caller_ip), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned long, scanned) + __field(unsigned long, freed) + __field(void *, caller_ip) + ), + TP_fast_assign( + __entry->dev = mp->m_super->s_dev; + __entry->scanned = scanned; + __entry->freed = freed; + __entry->caller_ip = (void *)caller_ip; + ), + TP_printk("dev %d:%d scanned %lu freed %lu caller %pS", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->scanned, + __entry->freed, + __entry->caller_ip) +) #endif /* CONFIG_XFS_VERITY */ #endif /* _TRACE_XFS_H */ diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index 46aa5002e4e1..8d1888353515 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -226,18 +226,46 @@ xfs_verity_shrinker_count( return min_t(s64, ULONG_MAX, count); } +struct xfs_verity_scan { + struct xfs_icwalk icw; + struct shrink_control *sc; + + unsigned long scanned; + unsigned long freed; +}; + +/* Scan an inode as part of a verity scan. */ +int +xfs_verity_scan_inode( + struct xfs_inode *ip, + struct xfs_icwalk *icw) +{ + xfs_irele(ip); + return 0; +} + /* Actually try to reclaim merkle tree blocks. */ static unsigned long xfs_verity_shrinker_scan( struct shrinker *shrink, struct shrink_control *sc) { + struct xfs_verity_scan vs = { + .sc = sc, + }; struct xfs_mount *mp = shrink->private_data; + int error; if (!xfs_has_verity(mp)) return SHRINK_STOP; - return 0; + error = xfs_icwalk_verity(mp, &vs.icw); + if (error) + xfs_alert(mp, "%s: verity scan failed, error %d", __func__, + error); + + trace_xfs_verity_shrinker_scan(mp, vs.scanned, vs.freed, _RET_IP_); + return vs.freed; } /* Register a shrinker so we can release cached merkle tree blocks. */ diff --git a/fs/xfs/xfs_verity.h b/fs/xfs/xfs_verity.h index 0ec0a61bee65..e1980fc1f149 100644 --- a/fs/xfs/xfs_verity.h +++ b/fs/xfs/xfs_verity.h @@ -13,6 +13,9 @@ void xfs_verity_cache_destroy(struct xfs_inode *ip); int xfs_verity_register_shrinker(struct xfs_mount *mp); void xfs_verity_unregister_shrinker(struct xfs_mount *mp); +struct xfs_icwalk; +int xfs_verity_scan_inode(struct xfs_inode *ip, struct xfs_icwalk *icw); + extern const struct fsverity_operations xfs_verity_ops; #else # define xfs_verity_cache_init(ip) ((void)0) @@ -20,6 +23,7 @@ extern const struct fsverity_operations xfs_verity_ops; # define xfs_verity_cache_destroy(ip) ((void)0) # define xfs_verity_register_shrinker(mp) (0) # define xfs_verity_unregister_shrinker(mp) ((void)0) +# define xfs_verity_scan_inode(ip, icw) (0) #endif /* CONFIG_FS_VERITY */ #endif /* __XFS_VERITY_H__ */ From patchwork Sun Mar 17 16:30:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594633 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51C931B949; Sun, 17 Mar 2024 16:30:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693058; cv=none; b=Bl0RuwfLrK/YSf9laVbjIpeQ+6f7LJNrbsbJS9N+bszKCfvnQ45klq0I30vdAly9vs7gC2eX+A+B06IEM8ZLnmIetPwA2XhzSHbdhqM5k+8bCIcnTN61pV2HS9JLBlL5C/aVKWaj0NbRPH7/n+3wxjM+5rqOkvFLaIzD1MOfZ7I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693058; c=relaxed/simple; bh=JWJ6asaa3IgK2Lg0qfpCMVmw2WfKIpy4CzWRor5gTcw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GxxdVIRdTH4x7uCMKqn/RX5f7R3lNczZzrwu4NscfpoisRnes9xfpH00CSPYO5Xtxnc95kL+pIRhxDCmLM2poOlU2afPomY2MPOpHro1+01PkTi8SXW9frXI/tOBGShG75rWF2FXlecvgruSet6nFCNnxvFvj+qTVpLvqti5pws= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Xc66V4Gp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Xc66V4Gp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2A6FBC433C7; Sun, 17 Mar 2024 16:30:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693058; bh=JWJ6asaa3IgK2Lg0qfpCMVmw2WfKIpy4CzWRor5gTcw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Xc66V4Gp9ro7OPX71mlUyGezytQejc0bHpiUQRCcOh7f0ZrGxpa582hNfFdh1sxn1 d4hyts6xsG4NNLr1fVKQnICAsnveYKDR3MxJRMGdmdXmY1wQGRMmnMh5Iq325b8eNj Fz/Mfw/674EEZA1mb3Ly+0JeF3skPeRChYGaQlIDDD4ai+2DHAWn7iXWbIIIdlcL3J PjwvxIPKxRFBolAHN0pbrypzXHOjrtsZ5dpS3Csj2NoUaE5eVv16rWL3+aiFNPGVSY zGBeFg1+103cyPTCDH6z4mYIEGUOgBAk6b05FG9qmMvckCXEHrDhQE1S15MX0Sd34U nylOMiQbSSshA== Date: Sun, 17 Mar 2024 09:30:57 -0700 Subject: [PATCH 29/40] xfs: shrink verity blob cache From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246376.2684506.9738125055810923344.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add some shrinkers so that reclaim can free cached merkle tree blocks when memory is tight. We add a shrinkref variable to bias reclaim against freeing the upper levels of the merkle tree in the hope of maintaining read performance. Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_trace.h | 1 + fs/xfs/xfs_verity.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 91a73399114e..37ea6822cca3 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -4797,6 +4797,7 @@ DEFINE_EVENT(xfs_verity_cache_class, name, \ DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_load); DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_store); DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_drop); +DEFINE_XFS_VERITY_CACHE_EVENT(xfs_verity_cache_reclaim); TRACE_EVENT(xfs_verity_shrinker_count, TP_PROTO(struct xfs_mount *mp, unsigned long long count, diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index 8d1888353515..c19fa47d1f76 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -42,6 +42,9 @@ struct xfs_merkle_blob { /* refcount of this item; the cache holds its own ref */ refcount_t refcount; + /* number of times the shrinker should ignore this item */ + atomic_t shrinkref; + unsigned long flags; /* Pointer to the merkle tree block, which is power-of-2 sized */ @@ -72,6 +75,7 @@ xfs_merkle_blob_alloc( /* Caller owns this refcount. */ refcount_set(&mk->refcount, 1); + atomic_set(&mk->shrinkref, 0); mk->flags = 0; return mk; } @@ -104,8 +108,10 @@ xfs_verity_cache_drop( struct xfs_inode *ip) { XA_STATE(xas, &ip->i_merkle_blocks, 0); + struct xfs_mount *mp = ip->i_mount; struct xfs_merkle_blob *mk; unsigned long flags; + s64 freed = 0; xas_lock_irqsave(&xas, flags); xas_for_each(&xas, mk, ULONG_MAX) { @@ -113,10 +119,13 @@ xfs_verity_cache_drop( trace_xfs_verity_cache_drop(ip, xas.xa_index, _RET_IP_); + freed++; xas_store(&xas, NULL); xfs_merkle_blob_rele(mk); } + percpu_counter_sub(&mp->m_verity_blocks, freed); xas_unlock_irqrestore(&xas, flags); + xfs_inode_clear_verity_tag(ip); } /* Destroy the merkle tree block cache */ @@ -175,6 +184,7 @@ xfs_verity_cache_store( unsigned long key, struct xfs_merkle_blob *mk) { + struct xfs_mount *mp = ip->i_mount; struct xfs_merkle_blob *old; unsigned long flags; @@ -189,6 +199,8 @@ xfs_verity_cache_store( old = __xa_cmpxchg(&ip->i_merkle_blocks, key, NULL, mk, GFP_KERNEL); } while (old && !refcount_inc_not_zero(&old->refcount)); + if (!old) + percpu_counter_add(&mp->m_verity_blocks, 1); xa_unlock_irqrestore(&ip->i_merkle_blocks, flags); if (old == NULL) { @@ -234,12 +246,73 @@ struct xfs_verity_scan { unsigned long freed; }; +/* Reclaim inactive merkle tree blocks that have run out of second chances. */ +static void +xfs_verity_cache_reclaim( + struct xfs_inode *ip, + struct xfs_verity_scan *vs) +{ + XA_STATE(xas, &ip->i_merkle_blocks, 0); + struct xfs_mount *mp = ip->i_mount; + struct xfs_merkle_blob *mk; + unsigned long flags; + s64 freed = 0; + + xas_lock_irqsave(&xas, flags); + xas_for_each(&xas, mk, ULONG_MAX) { + /* + * Tell the shrinker that we scanned this merkle tree block, + * even if we don't remove it. + */ + vs->scanned++; + if (vs->sc->nr_to_scan-- == 0) + break; + + /* Retain if there are active references */ + if (refcount_read(&mk->refcount) > 1) + continue; + + /* Ignore if the item still has lru refcount */ + if (atomic_add_unless(&mk->shrinkref, -1, 0)) + continue; + + trace_xfs_verity_cache_reclaim(ip, xas.xa_index, _RET_IP_); + + freed++; + xas_store(&xas, NULL); + xfs_merkle_blob_rele(mk); + } + percpu_counter_sub(&mp->m_verity_blocks, freed); + xas_unlock_irqrestore(&xas, flags); + + /* + * Try to clear the verity tree tag if we reclaimed all the cached + * blocks. On the flag setting side, we should have IOLOCK_SHARED. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + if (xa_empty(&ip->i_merkle_blocks)) + xfs_inode_clear_verity_tag(ip); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + + vs->freed += freed; +} + /* Scan an inode as part of a verity scan. */ int xfs_verity_scan_inode( struct xfs_inode *ip, struct xfs_icwalk *icw) { + struct xfs_verity_scan *vs; + + vs = container_of(icw, struct xfs_verity_scan, icw); + + if (vs->sc->nr_to_scan > 0) + xfs_verity_cache_reclaim(ip, vs); + + if (vs->sc->nr_to_scan == 0) + xfs_icwalk_verity_stop(icw); + xfs_irele(ip); return 0; } @@ -512,6 +585,13 @@ xfs_verity_read_merkle( * Free the new cache blob and continue with the existing one. */ xfs_merkle_blob_rele(new_mk); + } else { + /* + * We added this merkle tree block to the cache; tag the inode + * so that reclaim will scan this inode. The caller holds + * IOLOCK_SHARED this will not race with the shrinker. + */ + xfs_inode_set_verity_tag(ip); } out_hit: @@ -519,6 +599,13 @@ xfs_verity_read_merkle( block->context = mk; block->verified = test_bit(XFS_MERKLE_BLOB_VERIFIED_BIT, &mk->flags); + /* + * Prioritize keeping the root-adjacent levels cached if this isn't a + * streaming read. + */ + if (req->level >= 0) + atomic_set(&mk->shrinkref, req->level + 1); + return 0; out_new_mk: From patchwork Sun Mar 17 16:31:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594634 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED8471CD11; Sun, 17 Mar 2024 16:31:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693074; cv=none; b=nzUeEqyaHa8oPZbfI2HkUO2NPUnynBFOUKqZieyg71jk4yQ+/RgzyBpIocIzlpYjz5x+7DfglA/nacvuQnWRHWL9HFCMWmOH84H5fgQMzIDcGOo1Gfo3EpGOx59+HVjjZ86phzXTN20iOM6OHTqx6RTRFVoCL/TG+tGVH2GPGvw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693074; c=relaxed/simple; bh=xXMKW41WqkCzoTjVEyZi8pdjn3znKDc09/ezHh58SNI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=objUQ1PQLOLXK8C4Bq3eWQwKw1dXdBeAMIyWuCA45Q4YH2ffa9QQ2A5buDlrcDC4DGvMNhtu4t6sUwCIQJ+zisaCBlZR0RDnTUEfA8IeFhY4Hp+1MAFe7q9NHufhkrCoJylleZpxr0LGP2DydRiFvR9u9TllVSaCNheCoZAjIf8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FbaHRvSl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FbaHRvSl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C490CC433C7; Sun, 17 Mar 2024 16:31:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693073; bh=xXMKW41WqkCzoTjVEyZi8pdjn3znKDc09/ezHh58SNI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=FbaHRvSl34yOjqsf8iWA5aEvhNbaHUKL89zSiCK69A5t7+wBKVQmjtjxAXLFrRcZq owiGEr+/OqNaieM75fHn79E/zmGkGEl1DdsGyeoyp+0Sv3o2C5lYGuhdCZd9PHRz4X n4GjiQyn/kqdmc+V4UiLWRfHW+xhD9NZNhBKQ1DicLUxETjMhUilStlfl4f+u5z2Ow ST5iJEPaEyK5bvWRhOrREzWj+5KLBsl5JJtOdXIPmJRM5kz9ipXr8hxgLQ+IkFeLwS slGvaCMpso7IdexDnL/Nc7i9AXGppxLW/koAGcEcWtZZdXpKYE38wUKHlWecuuYZXa jjCmHvHH7KgCw== Date: Sun, 17 Mar 2024 09:31:13 -0700 Subject: [PATCH 30/40] xfs: clean up stale fsverity metadata before starting From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246392.2684506.14484170564314714404.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Before we let fsverity begin writing merkle tree blocks to the file, let's perform a minor effort to clean up any stale metadata from a previous attempt to enable fsverity. This can only happen if the system crashes /and/ the file shrinks, which is unlikely. But we could do a better job of cleaning up anyway. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/xfs_verity.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index c19fa47d1f76..db43e017f10e 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -413,6 +413,44 @@ xfs_verity_get_descriptor( return args.valuelen; } +/* + * Clear out old fsverity metadata before we start building a new one. This + * could happen if, say, we crashed while building fsverity data. + */ +static int +xfs_verity_drop_old_metadata( + struct xfs_inode *ip, + u64 new_tree_size, + unsigned int tree_blocksize) +{ + struct xfs_verity_merkle_key name; + struct xfs_da_args args = { + .dp = ip, + .whichfork = XFS_ATTR_FORK, + .attr_filter = XFS_ATTR_VERITY, + .op_flags = XFS_DA_OP_REMOVE, + .name = (const uint8_t *)&name, + .namelen = sizeof(struct xfs_verity_merkle_key), + /* NULL value make xfs_attr_set remove the attr */ + .value = NULL, + }; + u64 offset; + int error = 0; + + /* + * Delete as many merkle tree blocks in increasing blkno order until we + * don't find any more. That ought to be good enough for avoiding + * dead bloat without excessive runtime. + */ + for (offset = new_tree_size; !error; offset += tree_blocksize) { + xfs_verity_merkle_key_to_disk(&name, offset); + error = xfs_attr_set(&args); + } + if (error == -ENOATTR) + return 0; + return error; +} + static int xfs_verity_begin_enable( struct file *filp, @@ -421,7 +459,6 @@ xfs_verity_begin_enable( { struct inode *inode = file_inode(filp); struct xfs_inode *ip = XFS_I(inode); - int error = 0; xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL); @@ -431,7 +468,8 @@ xfs_verity_begin_enable( if (xfs_iflags_test_and_set(ip, XFS_VERITY_CONSTRUCTION)) return -EBUSY; - return error; + return xfs_verity_drop_old_metadata(ip, merkle_tree_size, + tree_blocksize); } static int From patchwork Sun Mar 17 16:31:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594635 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D712F17EF; Sun, 17 Mar 2024 16:31:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693089; cv=none; b=YBDBHG7A2SpHBOuRyG+8POrn7B6PjeyH+1/tQd0CjH67FVkBCJbSaQ+lBonxLuXKFGVmGqqoB0rIDsjEU2MH7XxWZnH4cdhgSDYlpqNY4V7U1Tp12P4IQayBDxzpNyr3zp5TFpQ7yt1zeDju6HXd7Gf29U7w5BC5qrxIh9rSybM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693089; c=relaxed/simple; bh=ZY0U/nov57RCmogmbrq6wE5MUGAayV8eQiH4hfO1k2M=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JnaCdL/lsZpKM24vHbKSbE9aS0XrcYOimjtb1msKHPTixPLzDqM64lD9dAJDdLZyXV90q9E9UozhJ9UuuYC2HtI9YAbpp62ACVyVr9YP1W3i6dtvJFcJ/qj0UeefBkNefe8yJqPA3DTICKZWrz2ZCQqqloKW95kwpHCn4aZRR2k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=W3+Yr3ln; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="W3+Yr3ln" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 60E29C433C7; Sun, 17 Mar 2024 16:31:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693089; bh=ZY0U/nov57RCmogmbrq6wE5MUGAayV8eQiH4hfO1k2M=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=W3+Yr3lnVFTF/x8KNv0I6179PqbVyAKLZvof15TU6PJw3JRtPtL63+VZyqUkyyL6C OwVkzide+6G1ZM7He5RNMGx8XlY5L2wkpyAcp0Ewv94D1y5hWd+hoyZju3fyjQNUDd Y52mXI4fmdVp8CLLKA8NQBI8nqob1jlyJ7a4UVj+j04VfN7YCxNLaU3cWjObQAiTUb YQO+TnFCa7F6g2NeRZTW/NTXHEpP9hB3e+tgwDKl/0mit/OOqhJKpmpWa+jzHKfgCT /TeTJddcpTiut08Key5ZNqKViCN9r8thdR2RS8/rUtErHcCmEwEQy6B0tSRYJciAnT +okcKzirSHZ0w== Date: Sun, 17 Mar 2024 09:31:28 -0700 Subject: [PATCH 31/40] xfs: better reporting and error handling in xfs_drop_merkle_tree From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246408.2684506.9245902616854244173.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong xfs_drop_merkle_tree is responsible for removing the fsverity metadata after a failed attempt to enable fsverity for a file. However, if the enablement process fails before the verity descriptor is written to the file, the cleanup function will trip the WARN_ON. The error code in that case is ENOATTR, which isn't worth logging about. Fix that return code handling, fix the tree block removal loop not to return early with ENOATTR, and improve the logging so that we actually capture what kind of error occurred. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/xfs_verity.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index db43e017f10e..32891ae42c47 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -472,15 +472,14 @@ xfs_verity_begin_enable( tree_blocksize); } +/* Try to remove all the fsverity metadata after a failed enablement. */ static int -xfs_drop_merkle_tree( +xfs_verity_drop_incomplete_tree( struct xfs_inode *ip, u64 merkle_tree_size, unsigned int tree_blocksize) { struct xfs_verity_merkle_key name; - int error = 0; - u64 offset = 0; struct xfs_da_args args = { .dp = ip, .whichfork = XFS_ATTR_FORK, @@ -491,6 +490,8 @@ xfs_drop_merkle_tree( /* NULL value make xfs_attr_set remove the attr */ .value = NULL, }; + u64 offset; + int error; if (!merkle_tree_size) return 0; @@ -498,6 +499,8 @@ xfs_drop_merkle_tree( for (offset = 0; offset < merkle_tree_size; offset += tree_blocksize) { xfs_verity_merkle_key_to_disk(&name, offset); error = xfs_attr_set(&args); + if (error == -ENOATTR) + error = 0; if (error) return error; } @@ -505,7 +508,8 @@ xfs_drop_merkle_tree( args.name = (const uint8_t *)XFS_VERITY_DESCRIPTOR_NAME; args.namelen = XFS_VERITY_DESCRIPTOR_NAME_LEN; error = xfs_attr_set(&args); - + if (error == -ENOATTR) + return 0; return error; } @@ -564,9 +568,16 @@ xfs_verity_end_enable( inode->i_flags |= S_VERITY; out: - if (error) - WARN_ON_ONCE(xfs_drop_merkle_tree(ip, merkle_tree_size, - tree_blocksize)); + if (error) { + int error2; + + error2 = xfs_verity_drop_incomplete_tree(ip, merkle_tree_size, + tree_blocksize); + if (error2) + xfs_alert(ip->i_mount, + "ino 0x%llx failed to clean up new fsverity metadata, err %d", + ip->i_ino, error2); + } xfs_iflags_clear(ip, XFS_VERITY_CONSTRUCTION); return error; From patchwork Sun Mar 17 16:31:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594636 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 379291B949; Sun, 17 Mar 2024 16:31:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693105; cv=none; b=qN7fG/3RPfuvZXx/7wGod8O4gF5+EOXGY76BJI7PdIstzybbov3D3O/7X7Y3vfJ0QpWm/6nq82A3lUhXglLXAHtWDdjB5Ngs5SROYMshF8wtvPTvSobuQmjlBD/eKOfxrGGcbgM99KTnphTyMTrw0NU/30dl4zfh+MgcvHJMvjI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693105; c=relaxed/simple; bh=PJf7MhulP7KKfLxtmjzccQbLC0uIEQngYqJwN54SY7Q=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EwIdc9/CANrpv7+iZNHuABxjL+7vd1dT5L/iFp5wjDtwQvTcqrlSXA3FGlil1MV+sh5I0jd67OiEiudclKnNvVmVQk4iUVOHp5vv7mvnt2cvyNY179KD/9wreXE3lUJH5puSN3yzoODW7ctD4G7msD5DPGecs8FzxxCIhsLKSnk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J4CuLmWx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="J4CuLmWx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C032C433F1; Sun, 17 Mar 2024 16:31:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693105; bh=PJf7MhulP7KKfLxtmjzccQbLC0uIEQngYqJwN54SY7Q=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=J4CuLmWx+vJKNWGZd4RlzyX1O1iMhDxXB+8gO90kJmejQy5Ccib1+HtTAuSzcLyzq mAsUow9cO0kLiJn7NeF2NuRoc/yK0VPs5QNT5qWAXWh+4osGIn4Au+KAEB0LV+ZKOi yom8KMDAf7wH9lABaefiYEQKFPhLRCCrFXiUSXS4dxr+oYD8M5mHeM8kBL+odWpL6j OKWk/owzkQTt3ne60zBWt/05hDs8cqvsYcpQBlrbzbX4Ap34DPjDkSarfbkrvvMAnS VYHQ82wSmohCso+LWOxzhxjQLWSxQZECosZH0zpoC81rEvrSc4IUBH4jV0kGyzClp9 O+LtKWfKO0hrg== Date: Sun, 17 Mar 2024 09:31:44 -0700 Subject: [PATCH 32/40] xfs: make scrub aware of verity dinode flag From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246423.2684506.11981674588788931642.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn fs-verity adds new inode flag which causes scrub to fail as it is not yet known. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/scrub/attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 9a1f59f7b5a4..ae4227cb55ec 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -494,7 +494,7 @@ xchk_xattr_rec( /* Retrieve the entry and check it. */ hash = be32_to_cpu(ent->hashval); badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE | - XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT); + XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT | XFS_ATTR_VERITY); if ((ent->flags & badflags) != 0) xchk_da_set_corrupt(ds, level); if (ent->flags & XFS_ATTR_LOCAL) { From patchwork Sun Mar 17 16:32:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594637 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF8A81CD13; Sun, 17 Mar 2024 16:32:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693121; cv=none; b=tk5+gn4ffb5BDgsMMZkVb50SeH044su0Hp/xlrfi9/aPO0S+q7J2UBzY6PNuMtqVRhXVL3xzgBdgOESY4qgwa8sKuQOzDM6DP3ihBdhPZkm1X1ehyYhmsLajfbO7khIGv5iHTsv36vdvdKhLfLd8vH8SYc8SejQaYsx573xs5hY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693121; c=relaxed/simple; bh=hfNdyLjE0iccOAS0uu/YAdIUW0G4z5hO8bo6TEkRMsk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NbOFhVrhRmIyMkGNRabuV5srcF/tr28wTNLtxdElgeBVHrebz4LzX9nGwLgfNxeWlb6QxUuujDgG6e32vfMIsaAeaCpqoL5JBq+W4P7wCluuX+r8Fihc2J2nOHuX8gkoodxfI+p/hpQzJ384ATGW1R0MnqOhqBpVUWbwbqr5yas= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UW9yt7iK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UW9yt7iK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AE206C433C7; Sun, 17 Mar 2024 16:32:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693120; bh=hfNdyLjE0iccOAS0uu/YAdIUW0G4z5hO8bo6TEkRMsk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UW9yt7iKAojHVHTga1fTtUjGhWvHzJ5pX4KJ/wIhHknWAPa7jm8762UIHTIS1iKBL QkbxqA3/T0/S87HU4t7BUs8LQCh/agTorGx8N+e45TaK2ii2NdGNbX3DMuIbqPWz19 gvQKbm77yX/JShbYbYSwv2rBEdlAN96NDre+WtMJgFpBr67+sFk0wR3Oib6MlrxIQC XfUMEgQTAyMtAKszvhe9CnEhlPNNCqMEJ8H7tYBeq9akWc9YYfTF17FNX3c+FaYDe2 URsp6meGwPuKA+NVuPRNn9xvv6MqhkPs0Fgnqc+cDizWcCXEs1fiYK93sXBD8ckkfb 8WOdz+YdPIPWQ== Date: Sun, 17 Mar 2024 09:32:00 -0700 Subject: [PATCH 33/40] xfs: add fs-verity ioctls From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246438.2684506.7350688709329720774.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn Add fs-verity ioctls to enable, dump metadata (descriptor and Merkle tree pages) and obtain file's digest. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: remove unnecessary casting] Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_ioctl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index ab61d7d552fb..4b11898728cc 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -43,6 +43,7 @@ #include #include #include +#include /* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to @@ -2174,6 +2175,21 @@ xfs_file_ioctl( return error; } + case FS_IOC_ENABLE_VERITY: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_enable(filp, arg); + + case FS_IOC_MEASURE_VERITY: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_measure(filp, arg); + + case FS_IOC_READ_VERITY_METADATA: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_read_metadata(filp, arg); + default: return -ENOTTY; } From patchwork Sun Mar 17 16:32:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594678 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EDAF536D; Sun, 17 Mar 2024 16:32:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693137; cv=none; b=fQPID3lHSyLp3WVyehlhECT9Jt5uxH6Neb06RCzLibMhovA3zBJa/X80NRvsU9c+wC00RSis1+LUScxmMTlN1wpSZUR8AauvK2SzZZk172/jodjZrDCfYbUNqxWCrSiJfXBsR1dX5mv7GB0Nn5gf3/E6n8lWfOEbyfqqhYwcfaM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693137; c=relaxed/simple; bh=yqHsxghv7Z64lboh1wQLuPmDG/JgBesCNaDkoWMgcDI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pJz/PDWEFIuoNWYoK6d25ZjrDGQTmxyWCRrsXTOt1G+aA70Bvs7+UuxKcD+2IribrdpjZjwume6QEHHhIqIxeBECXmx3b5iE2d3GvLtqeDhMutEYiClxupVQH3wf7oOLY23G7EpCIXJ3rT+PEafj9NGb8hhkCEpEue5c37ncoJU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fdoH3j+B; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fdoH3j+B" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5F1B0C433F1; Sun, 17 Mar 2024 16:32:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693136; bh=yqHsxghv7Z64lboh1wQLuPmDG/JgBesCNaDkoWMgcDI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=fdoH3j+BfNtnJQkvJBYn+e3mwqBH6ioXtFR91qJPFiFI/uKA8P45vaKy9IphMuAvm BUy0tT7eWTAtajY5myEf4ily+AQAVVYyLrGHNEFvwluw33C5ZaOMdSz6vBDe88jccU laQTC0vtLN5nikfLfAH1AYoGkrloKQ9h8K1fKOINQCd23EE0QGcecq0HJB5vu1zvuL WyO4lIv5Qa2nxST6IANIZUjAh+I773C+983mGYAxWxACyiG3Wo1kINXMbzav+akE9k vrJZsWFwhfcGluG2VETqlmqemOxaLysC6QwtwD2ar9v9age8Y5yyvSJK9QE3n8/F81 VhHpANd3hnC/g== Date: Sun, 17 Mar 2024 09:32:15 -0700 Subject: [PATCH 34/40] xfs: advertise fs-verity being available on filesystem From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246454.2684506.17930149061393435049.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Advertise that this filesystem supports fsverity. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_sb.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index ca1b17d01437..2f372088004f 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -239,6 +239,7 @@ typedef struct xfs_fsop_resblks { #define XFS_FSOP_GEOM_FLAGS_BIGTIME (1 << 21) /* 64-bit nsec timestamps */ #define XFS_FSOP_GEOM_FLAGS_INOBTCNT (1 << 22) /* inobt btree counter */ #define XFS_FSOP_GEOM_FLAGS_NREXT64 (1 << 23) /* large extent counters */ +#define XFS_FSOP_GEOM_FLAGS_VERITY (1 << 24) /* fs-verity */ /* * Minimum and maximum sizes need for growth checks. diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index a845cbe3f539..f5038d0d94fe 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -1260,6 +1260,8 @@ xfs_fs_geometry( } if (xfs_has_large_extent_counts(mp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_NREXT64; + if (xfs_has_verity(mp)) + geo->flags |= XFS_FSOP_GEOM_FLAGS_VERITY; geo->rtsectsize = sbp->sb_blocksize; geo->dirblocksize = xfs_dir2_dirblock_bytes(sbp); From patchwork Sun Mar 17 16:32:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594679 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F3001B949; Sun, 17 Mar 2024 16:32:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693152; cv=none; b=LdlyrDjLmWNvXOViQDc0Rt9gvPPd5wz04JGixeaa+F9XXemoeLHMZCPCq7bfK7E/PwoQ9Bm5kNTM5PMmuWSLHzixr73czXfhjZilRThLqVFfOE9GYDv0LHg21lqkMiSHzGATNC4YhRaA+sku3wDYWO1lGgTf4bpd1wDeT3UYH04= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693152; c=relaxed/simple; bh=4jMkHDMrDZOw2p/fhQDGP76wu2GFqy3BwQJT5LKQt9Y=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QSYVpjY1gvDIgv//nlXdHN5FGlHCCJgqbCDzn1WsWyE8apu22ZBuWGqGJ9S8dwiHh2g1F596su0971rhHwdsU4+z0k7r//OlCnLtnt106w+Z/u3VbzYBWWkLTUXAsJ2M5stK11Ixgx9ktUQBuTgQltvQO0Z1G08JBpmP38igNRU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZYo/dRBo; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZYo/dRBo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1CBF2C433F1; Sun, 17 Mar 2024 16:32:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693152; bh=4jMkHDMrDZOw2p/fhQDGP76wu2GFqy3BwQJT5LKQt9Y=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZYo/dRBotpN4KVSAz6ykCcSJyeWyt/VnBXP3k0dp6Hj8d6KawDtJJ3QR1WYtS3Pbg sARgjodd4QbxZvvpjiIyOagfPJDd6c7pCGKHllKA5yiz6KcXWk/j9kfEK+uKWhVV94 qza9qVpf12COmqsKVv696kzFLSsKJwIVGEC2La5k1ONCriid9yBrLVN+j2h4Tue1Yw sLU6wXAnC5D9/OyWIVVSZqJNQmajSaCr2YHzoGx2sdUKKeBYZ45PtH6xlYabfxGK7l e4og/CNZ8Qh0S0NXgZSBwVrBnHc0SN6hXZ2uoiREyksi4KvBip0NoKxYa+eq88DmUn +26pdbqDcRMEg== Date: Sun, 17 Mar 2024 09:32:31 -0700 Subject: [PATCH 35/40] xfs: teach online repair to evaluate fsverity xattrs From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246470.2684506.16777519924436608697.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Teach online repair to check for unused fsverity metadata and purge it on reconstruction. Signed-off-by: Darrick J. Wong --- fs/xfs/scrub/attr.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/attr.h | 4 ++ fs/xfs/scrub/common.c | 27 +++++++++++++ 3 files changed, 133 insertions(+) diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index ae4227cb55ec..c69dee281984 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -21,6 +21,8 @@ #include "scrub/dabtree.h" #include "scrub/attr.h" +#include + /* Free the buffers linked from the xattr buffer. */ static void xchk_xattr_buf_cleanup( @@ -135,6 +137,91 @@ xchk_setup_xattr( return xchk_setup_inode_contents(sc, 0); } +#ifdef CONFIG_FS_VERITY +/* Extract merkle tree geometry from incore information. */ +static int +xchk_xattr_extract_verity( + struct xfs_scrub *sc) +{ + struct xchk_xattr_buf *ab = sc->buf; + + /* setup should have allocated the buffer */ + if (!ab) { + ASSERT(0); + return -EFSCORRUPTED; + } + + return fsverity_merkle_tree_geometry(VFS_I(sc->ip), + &ab->merkle_blocksize, &ab->merkle_tree_size); +} + +/* Check the merkle tree xattrs. */ +STATIC void +xchk_xattr_verity( + struct xfs_scrub *sc, + xfs_dablk_t blkno, + const unsigned char *name, + unsigned int namelen, + unsigned int valuelen) +{ + struct xchk_xattr_buf *ab = sc->buf; + + /* Non-verity filesystems should never have verity xattrs. */ + if (!xfs_has_verity(sc->mp)) { + xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, blkno); + return; + } + + /* + * Any verity metadata on a non-verity file are leftovers from a + * previous attempt to enable verity. + */ + if (!IS_VERITY(VFS_I(sc->ip))) { + xchk_ino_set_preen(sc, sc->ip->i_ino); + return; + } + + switch (namelen) { + case sizeof(struct xfs_verity_merkle_key): + /* Oversized blocks are not allowed */ + if (valuelen > ab->merkle_blocksize) { + xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, blkno); + return; + } + break; + case XFS_VERITY_DESCRIPTOR_NAME_LEN: + /* Has to match the descriptor xattr name */ + if (memcmp(name, XFS_VERITY_DESCRIPTOR_NAME, namelen)) { + xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, blkno); + } + return; + default: + xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, blkno); + return; + } + + /* + * Merkle tree blocks beyond the end of the tree are leftovers from + * a previous failed attempt to enable verity. + */ + if (xfs_verity_merkle_key_from_disk(name) >= ab->merkle_tree_size) + xchk_ino_set_preen(sc, sc->ip->i_ino); +} +#else +# define xchk_xattr_extract_verity(sc) (0) + +static void +xchk_xattr_verity( + struct xfs_scrub *sc, + xfs_dablk_t blkno, + const unsigned char *name, + unsigned int namelen) +{ + /* Should never see verity xattrs when verity is not enabled. */ + xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, blkno); +} +#endif /* CONFIG_FS_VERITY */ + /* Extended Attributes */ struct xchk_xattr { @@ -194,6 +281,15 @@ xchk_xattr_listent( goto fail_xref; } + /* Check verity xattr geometry */ + if (flags & XFS_ATTR_VERITY) { + xchk_xattr_verity(sx->sc, args.blkno, name, namelen, valuelen); + if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) { + context->seen_enough = 1; + return; + } + } + /* Does this name make sense? */ if (!xfs_attr_namecheck(sx->sc->mp, name, namelen, flags)) { xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); @@ -611,6 +707,12 @@ xchk_xattr( if (error) return error; + if (IS_VERITY(VFS_I(sc->ip))) { + error = xchk_xattr_extract_verity(sc); + if (error) + return error; + } + /* Check the physical structure of the xattr. */ if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) error = xchk_xattr_check_sf(sc); diff --git a/fs/xfs/scrub/attr.h b/fs/xfs/scrub/attr.h index 48fd9402c432..37849ffb0375 100644 --- a/fs/xfs/scrub/attr.h +++ b/fs/xfs/scrub/attr.h @@ -19,6 +19,10 @@ struct xchk_xattr_buf { /* Memory buffer used to extract xattr values. */ void *value; size_t value_sz; + + /* Geometry of the merkle tree attached to this verity file. */ + u64 merkle_tree_size; + unsigned int merkle_blocksize; }; #endif /* __XFS_SCRUB_ATTR_H__ */ diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c index abff79a77c72..dd2ed1f833c5 100644 --- a/fs/xfs/scrub/common.c +++ b/fs/xfs/scrub/common.c @@ -37,6 +37,8 @@ #include "scrub/repair.h" #include "scrub/health.h" +#include + /* Common code for the metadata scrubbers. */ /* @@ -1073,6 +1075,25 @@ xchk_irele( xfs_irele(ip); } +#ifdef CONFIG_FS_VERITY +/* + * Make sure the fsverity information is attached, so we don't have to do that + * later after taking locks. + */ +static inline int +xchk_setup_fsverity( + struct xfs_scrub *sc) +{ + unsigned int dontcare; + u64 alsodontcare; + + return fsverity_merkle_tree_geometry(VFS_I(sc->ip), + &dontcare, &alsodontcare); +} +#else +# define xchk_setup_fsverity(sc) (0) +#endif + /* * Set us up to scrub metadata mapped by a file's fork. Callers must not use * this to operate on user-accessible regular file data because the MMAPLOCK is @@ -1092,6 +1113,12 @@ xchk_setup_inode_contents( /* Lock the inode so the VFS cannot touch this file. */ xchk_ilock(sc, XFS_IOLOCK_EXCL); + if (IS_VERITY(VFS_I(sc->ip))) { + error = xchk_setup_fsverity(sc); + if (error) + goto out; + } + error = xchk_trans_alloc(sc, resblks); if (error) goto out; From patchwork Sun Mar 17 16:32:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594680 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1DDA21CF8B; Sun, 17 Mar 2024 16:32:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693168; cv=none; b=mUbXB1yrrVxbf3PtRkXbCvUbJyZXeX6a/H7duhq1T1oXqiNnA0nBlFcP5EiY4cL2p9wPzUK6TtqdyigL8r5sToruSIIX6fM8AnZSR5yOMKoYkzmrtbRkn/hKFh/qSToHj7xD6KSt48whDkHU3mdGg7PXtWmOaH84HOalifUxAX0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693168; c=relaxed/simple; bh=RE8M70WosxhZ52NRC8S48jNL1RwKrCGZVvwHMDsK9xc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=S17aTehJ4v4RwW1L1/vvSASt+mTBQYTE6RZYHdYHsw11zJoxxm27oLVf7T+S836W0rDIUIQeE0wgIygsQzfVPkCtWM+LZZ9hI1SceW4jeCBXGcm1H/QUcmOpUi+SwyNhixtgUgzqem3x/4645tp70vRuVBWmGiZf/ooB8HcLmCY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ReuGvlM3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ReuGvlM3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD51BC433C7; Sun, 17 Mar 2024 16:32:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693167; bh=RE8M70WosxhZ52NRC8S48jNL1RwKrCGZVvwHMDsK9xc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ReuGvlM3B6qdIFUknKyE97BscQ4zBmwVEEWUqzX+co9C/YSXAVOagwn0Hkit2KHP0 2a5B0QgrYL0vGaALKYUUabjPTYlp7o9zgKDGclGAtLnsv3iXIC7fGZK7dFZx9pokYc BFvEChI/phlXV6sQCi6gTHBZi8I2SGdYD43Oe0DjPRLJXfbS6lFHauzvPyCVxnA5nx 2SJrPhvGtycuTrfhv6bCTPHXBwuqufRCbcN/Jgk8gtEN/PXX22QDABZxGUgGbzSRki WqDV6sn1jL7sRmhVQHGDVG98Dkz9cwgKVulNcb6hOp7/FaS+rASVaOYBcUIG0p5i6J p41mqUcPZWbOw== Date: Sun, 17 Mar 2024 09:32:47 -0700 Subject: [PATCH 36/40] xfs: don't store trailing zeroes of merkle tree blocks From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246485.2684506.6805355726574585050.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong As a minor space optimization, don't store trailing zeroes of merkle tree blocks to reduce space consumption and copying overhead. This really only affects the rightmost blocks at each level of the tree. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/xfs_verity.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index 32891ae42c47..abd95bc1ba6e 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -622,11 +622,6 @@ xfs_verity_read_merkle( if (error) goto out_new_mk; - if (!args.valuelen) { - error = -ENODATA; - goto out_new_mk; - } - mk = xfs_verity_cache_store(ip, key, new_mk); if (mk != new_mk) { /* @@ -681,6 +676,12 @@ xfs_verity_write_merkle( .value = (void *)buf, .valuelen = size, }; + const char *p = buf + size - 1; + + /* Don't store trailing zeroes. */ + while (p >= (const char *)buf && *p == 0) + p--; + args.valuelen = p - (const char *)buf + 1; xfs_verity_merkle_key_to_disk(&name, pos); return xfs_attr_set(&args); From patchwork Sun Mar 17 16:33:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594681 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA6231CD18; Sun, 17 Mar 2024 16:33:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693183; cv=none; b=JkA7P7iCqzPzEdeOWkLIYpIJyJTND29VZIN2abag0D8JZf75of340a6/PGO9rkGYt3u89u/2UjMNoI472rT2Bpng2fxP5Gw3YV3PbcQug1UQsaZnkvyIhVriYW4swDLpFqYT9Ulo5jJibpRWVY2Cr/eSdSmWxwpUM4Z4rkkZrW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693183; c=relaxed/simple; bh=aRlhJXa38cH0oJc/vOYeFKNl9CQRX6ZOK3DYw0Kz8CU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gKJ/nVMN/9dsxjWFh2LtXOQeQaW7obJv8tJigrmQFTUajWzmu2PiIay2i6dQvxWVTF7Qxfnaae4vvSEzSmV1qlc/3zxwR2fHgkZQmAF1QQGeAYe62TNBQkYyRmkPNmDC6e0H6siQ3du+tnJEXve0voHgwZIpzREvLgyKuyPInSI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DqqHKmom; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DqqHKmom" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 50622C433F1; Sun, 17 Mar 2024 16:33:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693183; bh=aRlhJXa38cH0oJc/vOYeFKNl9CQRX6ZOK3DYw0Kz8CU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=DqqHKmomG63eYhtGOqSWLaLJGe3/GbWkEFHBihzmTRKF13iPdS0TI9U8cHb8yZV+t 7mcWeTE1KvkwqQQXW+giF7oTVhiNoT5YCtZKXRsLX9L51gAXLXs5sidFoJBlhTIvWX oAKk4WzWoAKt6OFnlNL5+FVkPYPns7zJWsxq4MmnHEjf67fqsDD9/+jZTcOsZQL/VX LwN5KvgO51G93+LKmORrF7gySjppjuCjDc7XZ8vDw3xwPsINCRAF2kR6uBO3Dert+Y HziE0qaJsM9Ehzeq97+vSLnNRKiLf8gFrj+hGqdNDo2455bQ2cYsZyoHe7Z4kmj4GL CDkmPCZisZs0w== Date: Sun, 17 Mar 2024 09:33:02 -0700 Subject: [PATCH 37/40] xfs: create separate name hash function for xattrs From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246501.2684506.2064171073014791566.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a new hashing function for extended attribute names. The next patch needs this so it can modify the hash strategy for verity xattrs. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/libxfs/xfs_attr.c | 16 ++++++++++++++-- fs/xfs/libxfs/xfs_attr.h | 3 +++ fs/xfs/libxfs/xfs_attr_leaf.c | 4 ++-- fs/xfs/scrub/attr.c | 8 +++++--- fs/xfs/xfs_attr_item.c | 3 ++- fs/xfs/xfs_attr_list.c | 3 ++- 6 files changed, 28 insertions(+), 9 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index b7aa1bc12fd1..b1fa45197eac 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -238,6 +238,16 @@ xfs_attr_get_ilocked( return xfs_attr_node_get(args); } +/* Compute hash for an extended attribute name. */ +xfs_dahash_t +xfs_attr_hashname( + unsigned int attr_flags, + const uint8_t *name, + unsigned int namelen) +{ + return xfs_da_hashname(name, namelen); +} + /* * Retrieve an extended attribute by name, and its value if requested. * @@ -268,7 +278,8 @@ xfs_attr_get( args->geo = args->dp->i_mount->m_attr_geo; args->whichfork = XFS_ATTR_FORK; - args->hashval = xfs_da_hashname(args->name, args->namelen); + args->hashval = xfs_attr_hashname(args->attr_filter, args->name, + args->namelen); /* Entirely possible to look up a name which doesn't exist */ args->op_flags = XFS_DA_OP_OKNOENT; @@ -942,7 +953,8 @@ xfs_attr_set( args->geo = mp->m_attr_geo; args->whichfork = XFS_ATTR_FORK; - args->hashval = xfs_da_hashname(args->name, args->namelen); + args->hashval = xfs_attr_hashname(args->attr_filter, args->name, + args->namelen); /* * We have no control over the attribute names that userspace passes us diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 92711c8d2a9f..19db6c1cc71f 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -619,4 +619,7 @@ extern struct kmem_cache *xfs_attr_intent_cache; int __init xfs_attr_intent_init_cache(void); void xfs_attr_intent_destroy_cache(void); +xfs_dahash_t xfs_attr_hashname(unsigned int attr_flags, + const uint8_t *name_string, unsigned int name_length); + #endif /* __XFS_ATTR_H__ */ diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index ac904cc1a97b..fcece25fd13e 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -911,8 +911,8 @@ xfs_attr_shortform_to_leaf( nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; - nargs.hashval = xfs_da_hashname(sfe->nameval, - sfe->namelen); + nargs.hashval = xfs_attr_hashname(sfe->flags, sfe->nameval, + sfe->namelen); nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK; error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */ ASSERT(error == -ENOATTR); diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index c69dee281984..e7d50589f72d 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -253,7 +253,6 @@ xchk_xattr_listent( .dp = context->dp, .name = name, .namelen = namelen, - .hashval = xfs_da_hashname(name, namelen), .trans = context->tp, .valuelen = valuelen, }; @@ -263,6 +262,7 @@ xchk_xattr_listent( sx = container_of(context, struct xchk_xattr, context); ab = sx->sc->buf; + args.hashval = xfs_attr_hashname(flags, name, namelen); if (xchk_should_terminate(sx->sc, &error)) { context->seen_enough = error; @@ -600,7 +600,8 @@ xchk_xattr_rec( xchk_da_set_corrupt(ds, level); goto out; } - calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen); + calc_hash = xfs_attr_hashname(ent->flags, lentry->nameval, + lentry->namelen); } else { rentry = (struct xfs_attr_leaf_name_remote *) (((char *)bp->b_addr) + nameidx); @@ -608,7 +609,8 @@ xchk_xattr_rec( xchk_da_set_corrupt(ds, level); goto out; } - calc_hash = xfs_da_hashname(rentry->name, rentry->namelen); + calc_hash = xfs_attr_hashname(ent->flags, rentry->name, + rentry->namelen); } if (calc_hash != hash) xchk_da_set_corrupt(ds, level); diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 703770cf1482..4d8264f0a537 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -536,7 +536,8 @@ xfs_attri_recover_work( args->whichfork = XFS_ATTR_FORK; args->name = nv->name.i_addr; args->namelen = nv->name.i_len; - args->hashval = xfs_da_hashname(args->name, args->namelen); + args->hashval = xfs_attr_hashname(attrp->alfi_attr_filter, args->name, + args->namelen); args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK; args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED; diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index fa74378577c5..96169474d023 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -135,7 +135,8 @@ xfs_attr_shortform_list( } sbp->entno = i; - sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen); + sbp->hash = xfs_attr_hashname(sfe->flags, sfe->nameval, + sfe->namelen); sbp->name = sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ From patchwork Sun Mar 17 16:33:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594682 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5889B7F6; Sun, 17 Mar 2024 16:33:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693199; cv=none; b=ZDlZiz/g8IKDaFpftomtTf2p6CJFJeIvHsZovUX7IQqr6h+/ahy6j4C8BoyJ6tuzhO9gImFu2TCn2pblgUykv2ywJ0JPoD3RC54QG/FmTtU9X5XbUwxtgtcpFPg4DeJOnlAynwxJviJTp0TjB/QwxUQKkzFzTArtWigXf6dn3Wc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693199; c=relaxed/simple; bh=p+HzgupUX7ciAFwLxTWigNm12S2HS0MQcNcqVZ1LajE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=W1HXH1kxKpTVZVKIGLkE3kpM1m6qZk0VsCEFgJgsfryl9uHZH22iDHWDi8lRp0Tq6qisFrCtxaa9T1xfCDs6k9s10XYljNufa2XTQAansrTiGOpNMeCA+M16/HJEyEHbEPcOe8SHPmyzEHgQv651eAaCafqLCSppvyLQKqH4Rss= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eDUOv03a; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eDUOv03a" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E4E46C433F1; Sun, 17 Mar 2024 16:33:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693199; bh=p+HzgupUX7ciAFwLxTWigNm12S2HS0MQcNcqVZ1LajE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=eDUOv03adATUnnw94KntnGe+pA+Jhqg8nbfx5x1SayKNJ4XQgDnCfyq41LPyIQEFx R6W3RndXxQYtUUCYyGM18bDE+BbCABgMA3mVT3tsUZWCfMwauINerTJ2dizV2beA8I 2yvhkrPHX5MBnaTypJ9O17NMLT5slxpFwWlQHCFtf4Eu5nm4zMTvnv6YbA7L6FPn// 8gbuHem/ifG8nlfA8oz4JLkPLNYt+oZdX6tR5kj9p2H+RW8wTfWBKDK6UM5jFVl2/E 2mNpVeExtHGcdKKgEDksELNY80YJEvCyRZUhLRLB8B1I3VuoOrwyTCgcbeGRtPh1Ih ZE8N/BIZoRvFQ== Date: Sun, 17 Mar 2024 09:33:18 -0700 Subject: [PATCH 38/40] xfs: use merkle tree offset as attr hash From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246517.2684506.8560170754721057486.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong I was exploring the fsverity metadata with xfs_db after creating a 220MB verity file, and I noticed the following in the debugger output: entries[0-75] = [hashval,nameidx,incomplete,root,secure,local,parent,verity] 0:[0,4076,0,0,0,0,0,1] 1:[0,1472,0,0,0,1,0,1] 2:[0x800,4056,0,0,0,0,0,1] 3:[0x800,4036,0,0,0,0,0,1] ... 72:[0x12000,2716,0,0,0,0,0,1] 73:[0x12000,2696,0,0,0,0,0,1] 74:[0x12800,2676,0,0,0,0,0,1] 75:[0x12800,2656,0,0,0,0,0,1] ... nvlist[0].merkle_off = 0x18000 nvlist[1].merkle_off = 0 nvlist[2].merkle_off = 0x19000 nvlist[3].merkle_off = 0x1000 ... nvlist[71].merkle_off = 0x5b000 nvlist[72].merkle_off = 0x44000 nvlist[73].merkle_off = 0x5c000 nvlist[74].merkle_off = 0x45000 nvlist[75].merkle_off = 0x5d000 Within just this attr leaf block, there are 76 attr entries, but only 38 distinct hash values. There are 415 merkle tree blocks for this file, but we already have hash collisions. This isn't good performance from the standard da hash function because we're mostly shifting and rolling zeroes around. However, we don't even have to do that much work -- the merkle tree block keys are themslves u64 values. Truncate that value to 32 bits (the size of xfs_dahash_t) and use that for the hash. We won't have any collisions between merkle tree blocks until that tree grows to 2^32nd blocks. On a 4k block filesystem, we won't hit that unless the file contains more than 2^49 bytes, assuming sha256. As a side effect, the keys for merkle tree blocks get written out in roughly sequential order, though I didn't observe any change in performance. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/libxfs/xfs_attr.c | 7 +++++++ fs/xfs/libxfs/xfs_da_format.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index b1fa45197eac..7c0f006f972a 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -245,6 +245,13 @@ xfs_attr_hashname( const uint8_t *name, unsigned int namelen) { + if ((attr_flags & XFS_ATTR_VERITY) && + namelen == sizeof(struct xfs_verity_merkle_key)) { + uint64_t off = xfs_verity_merkle_key_from_disk(name); + + return off >> XFS_VERITY_MIN_MERKLE_BLOCKLOG; + } + return xfs_da_hashname(name, namelen); } diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index e4aa7c9a0ccb..58887a1c65fe 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -946,4 +946,6 @@ xfs_verity_merkle_key_from_disk( #define XFS_VERITY_DESCRIPTOR_NAME "vdesc" #define XFS_VERITY_DESCRIPTOR_NAME_LEN (sizeof(XFS_VERITY_DESCRIPTOR_NAME) - 1) +#define XFS_VERITY_MIN_MERKLE_BLOCKLOG (10) + #endif /* __XFS_DA_FORMAT_H__ */ From patchwork Sun Mar 17 16:33:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594683 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C223E17EF; Sun, 17 Mar 2024 16:33:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693214; cv=none; b=LRwnwESWisD3MEpDIH3i/45N9OflsHM4yWro0ozTVAt1QXacIqMdO3wC6fXzdG1lMKuvFX7cCM/ffGY/PaVTt56xZlLahJ8xIbE1QqQlZKuB7zTrd4CpwYBdwE+Y/pMtaJyDz6gTJyPSCkMGATkT/jiSgQbuCYvMxIbmYppmd58= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693214; c=relaxed/simple; bh=ONACup+laAfDNq7cx/v5Ol/o/ikJ0Zhm3Rp1DJWL5uc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DtvEai76COnwOOXixJxfPEd1C8HdduXDqtepmLFbeLpsasxemFitRZanLmBtsJ3Zn390t2+BHhU4YpLS1twbQlJ04Xh1v9Y9iRWd0DmcmnAt1X4bYBZbQiEYESxSsqXnmzBvHN1ioH/rS0CqALKOWzMKyvZw6leSIItDErhHUN4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hH9NWG7t; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hH9NWG7t" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 95DBEC433C7; Sun, 17 Mar 2024 16:33:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693214; bh=ONACup+laAfDNq7cx/v5Ol/o/ikJ0Zhm3Rp1DJWL5uc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hH9NWG7tsGU4g3x8pHr+OCkTFcuf+CwH8cqFZZDuoywHr0pJp4heTbptBkgdVe0d9 c8zJOExyfNbEOPkNsAwfp6NwAhPJW9xOBC0ByNvSbmSqu9Erl8t3nFbP+TS68MIsJA 42yXrnYK8YeyS5ukfDGDtGvHxdgSGO+Kv18AaC8pAAAKXUCSAx3mpM1y/F4CKZiSPr QkLtBKQ6+1xfx5aMIxPWibzz+OxXnINyMBpSr1IPQNlTogrMC6w8fJTgYeoCqXy/6w Qko8ETdIlNGGYR6QHJnXcVP/ZCatkxk1eNHccIOswmZ9jo4yiZmR3Y/nI04ajOQ+L6 ghDMF+D9964hg== Date: Sun, 17 Mar 2024 09:33:34 -0700 Subject: [PATCH 39/40] xfs: don't bother storing merkle tree blocks for zeroed data blocks From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246533.2684506.10607368938981182877.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Now that fsverity tells our merkle tree io functions about what a hash of a data block full of zeroes looks like, we can use this information to avoid writing out merkle tree blocks for sparse regions of the file. For verified gold master images this can save quite a bit of overhead. Signed-off-by: Darrick J. Wong Reviewed-by: Andrey Albershteyn --- fs/xfs/xfs_verity.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_verity.c b/fs/xfs/xfs_verity.c index abd95bc1ba6e..ba96e7049f61 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -619,6 +619,20 @@ xfs_verity_read_merkle( xfs_verity_merkle_key_to_disk(&name, block->offset); error = xfs_attr_get(&args); + if (error == -ENOATTR) { + u8 *p; + unsigned int i; + + /* + * No attribute found. Synthesize a buffer full of the zero + * digests on the assumption that we elided them at write time. + */ + for (i = 0, p = new_mk->data; + i < block->size; + i += req->digest_size, p += req->digest_size) + memcpy(p, req->zero_digest, req->digest_size); + error = 0; + } if (error) goto out_new_mk; @@ -676,12 +690,29 @@ xfs_verity_write_merkle( .value = (void *)buf, .valuelen = size, }; - const char *p = buf + size - 1; + const char *p; + unsigned int i; - /* Don't store trailing zeroes. */ + /* + * If this is a block full of hashes of zeroed blocks, don't bother + * storing the block. We can synthesize them later. + */ + for (i = 0, p = buf; + i < size; + i += req->digest_size, p += req->digest_size) + if (memcmp(p, req->zero_digest, req->digest_size)) + break; + if (i == size) + return 0; + + /* + * Don't store trailing zeroes. Store at least one byte so that the + * block cannot be mistaken for an elided one. + */ + p = buf + size - 1; while (p >= (const char *)buf && *p == 0) p--; - args.valuelen = p - (const char *)buf + 1; + args.valuelen = max(1, p - (const char *)buf + 1); xfs_verity_merkle_key_to_disk(&name, pos); return xfs_attr_set(&args); From patchwork Sun Mar 17 16:33:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13594684 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C3D81CAAE; Sun, 17 Mar 2024 16:33:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693230; cv=none; b=q9Ia+tvjrMmtdlP5V8ZKSTkL+LhP3lT+rK2xMm/CjOVAn00xAx2DU6IKAbHhmZdSD7p3bVSQyTUxkvEbfdUpQ1u9WICCQ5MuyG1t/ak1DiQfGF4CZxHIJhg26NFjKEYVX4FIwI/JPUpoOsL5RfzeOr9/UHnxbR8YKXyVYt7K/Qo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710693230; c=relaxed/simple; bh=gyY/eII/mzWjplxkissoGLEmgFRPREJ2adLdk/vMBuU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ddO3ZUbu6yc4PZGoyt+ezsj/pRBpR4913YitKHBOQBGbjPl506ivMKHfCB0i6xgEbOnHQIlP7ofRtAZoefT9csQwIcPZ5NT2NQR+Zp92EYblaMFW4l92Kcfk9GcBmxjERgmE5F7YYEmR7ss1PWjE8dLed5C138dmkJ7/tXvflQw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ElKK210F; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ElKK210F" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 39B75C433F1; Sun, 17 Mar 2024 16:33:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710693230; bh=gyY/eII/mzWjplxkissoGLEmgFRPREJ2adLdk/vMBuU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ElKK210FGIyjuocmHG1Cw3Gwh40Mzn83HesvO+H+xq04luaWNqrr3C03ecKzuWyBl HlDCEcf8JKem10qw3NjYMDSsstIHIGh2HjJ406dq745MSOdBQgpM5bxRJqko7LR55B uwVlhChqwz6PrtY0xoUiv9GRitatiqzisoerkDarh9Ov6ZQZ/P1xYip7U0HDyZj2az WbQbk2gx1DKkAfJ0sdGA2blRV4oz5+iK2FejOWZo8NPfpBHIEIaAq9ZKfTI/0QjpvS ZsGF+Zxw4odxhC1lfFBMvPOV3/NBcuTxH5OLbJvM3lCFxsK6+1GISc1zwIOlBiYQfb 9Y6biv75v/OOA== Date: Sun, 17 Mar 2024 09:33:49 -0700 Subject: [PATCH 40/40] xfs: enable ro-compat fs-verity flag From: "Darrick J. Wong" To: djwong@kernel.org, ebiggers@kernel.org, aalbersh@redhat.com Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171069246548.2684506.17460791341103657493.stgit@frogsfrogsfrogs> In-Reply-To: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> References: <171069245829.2684506.10682056181611490828.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Andrey Albershteyn Finalize fs-verity integration in XFS by making kernel fs-verity aware with ro-compat flag. Signed-off-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: add spaces] Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_format.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 3ce2902101bc..c3f586d6bf7a 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -355,10 +355,11 @@ xfs_sb_has_compat_feature( #define XFS_SB_FEAT_RO_COMPAT_INOBTCNT (1 << 3) /* inobt block counts */ #define XFS_SB_FEAT_RO_COMPAT_VERITY (1 << 4) /* fs-verity */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ - (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ - XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ - XFS_SB_FEAT_RO_COMPAT_REFLINK| \ - XFS_SB_FEAT_RO_COMPAT_INOBTCNT) + (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ + XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ + XFS_SB_FEAT_RO_COMPAT_REFLINK | \ + XFS_SB_FEAT_RO_COMPAT_INOBTCNT | \ + XFS_SB_FEAT_RO_COMPAT_VERITY) #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL static inline bool xfs_sb_has_ro_compat_feature(