From patchwork Wed Mar 13 17:52:50 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: 13591699 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 6B49D57314; Wed, 13 Mar 2024 17:52: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=1710352371; cv=none; b=mFk18p4MSTws4oWxLXUWq9JZ6vMoUiX2mBsqjv8B80CrPwvygcz5sEvbNPpsvAOmEuYXBjks+rEXZRW/+au9b/aTagSFKby9EGex8yyxX0+9XxITG4ImxYy/JYLQhKRvLhAuHkpExYok2EoezDOyo4FD3qb/mcn3JThuEfRW7pU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352371; c=relaxed/simple; bh=G2GRGQXP7Tmb/LqM7gCxfbjW3s4ehpMaBQYxFXH1REU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=grjNHlkvY1oSjqVHkdd0XJ7LQ6dJbxMB1+lZLLfgcHsxD3zKvKW0Y1Hg+IENU4kgzlXzvfJNLVfqk2fD1OsTPXWKLp1jrbbpAI0DbgEKN47N0i9j1mFyo9rJwwxUuuNueqUtNlWgccpeZ0hFIF/y5O6cotnapWT1rAJjZMdZrXM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZKjitK+z; 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="ZKjitK+z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CAB7FC433C7; Wed, 13 Mar 2024 17:52:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352370; bh=G2GRGQXP7Tmb/LqM7gCxfbjW3s4ehpMaBQYxFXH1REU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZKjitK+zArH2GbUb1kY4WOM2VRzCx8Y29aZS+KrUr4IAVMclbhPCyCMhM6bmQvMBl G/f/B1YBhm774Lj2seSSyNBDnQNpEup7S/CU8D3gIcxVdphxFzNJFVvlSdoUUY1cjB 5DL3SZYpOAudf3f61z9iaRjGVgR6p+aAj4m9XWHaHFj5hPs5dQsZlAwi3HOhBH9JBR elIbrvdwXqyaz6XJCmR6Q3mNtkOjH2YuvwGDcO2WSeHvfq8JkjbqXvcekcuEz8T0FX NB52AeYObHsvRoekOTH8leJhbyQ7HVeZ8w3ZT7T6DidZ2kX5xdOnepxVHW9PWLJq8L SZ3DWVgz+lFCw== Date: Wed, 13 Mar 2024 10:52:50 -0700 Subject: [PATCH 01/29] fsverity: remove hash page spin lock From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: Eric Biggers , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223376.2613863.2659516201876217874.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:53: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: 13591700 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 CEFFF4D108; Wed, 13 Mar 2024 17:53: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=1710352386; cv=none; b=ritQMXyQw4Kq8tnGyBbCq7swrzV5Sp5NChqe1YVJ5XeBY0QgzQeg0puewNr4MtQ3cb/SR9YbPyROnkn2hmyXu1LzQWtxSN5n6cXTqyIpBjjOVLv9cCGbtcIn6osh9sAnrHtfdv0jPGLsmH5AqFOO77O5/kHlq313qRoz3RAKh20= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352386; c=relaxed/simple; bh=kJ2W8LeTyOMmKY5ie73ROB+4axcgcPYqLtLFh1tV8hw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TYN615C1/POqVEYUhOImyNY33QNO9OYJsKVp+Q5mPZSIHIZmZ9xVoVy9x0WXtlnwC6I3C2iP7v62iyJraCs6zzrV8mDhL2Ko2R+NvMLRBG+NIyTur3sAJ9SlEn2zACCr98/VWyCsEuZzlGgQCThCYKuLOd5ZxE0AI3YrCWZlJkI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AKP3qDpJ; 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="AKP3qDpJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 737DFC433C7; Wed, 13 Mar 2024 17:53:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352386; bh=kJ2W8LeTyOMmKY5ie73ROB+4axcgcPYqLtLFh1tV8hw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=AKP3qDpJE4Dadehz0M9eUgLJwm/JwR9jLA8DIBYHBAPKH7duQgfDZ3OxnIXJ5RbfN Iso75j2/nUKHvB4bDciLF/StH3R7I29oGFcNnx4QlPosAx/Suw33dIjkzy4mPDYgvA 8ymMmsevANDMHnaXtZ4fPChzR9+QqaECKEmz4smeyzpqucD92WsPSv0jQ0v6N0pHIV YZwqY4t8PiLnZzWhap9RflWsy/gDSamPhsIfCHeA898xzEcrXmjrGjOQ3EHQr1dSDT 1Vjsy5lmZElkAs7QuCLEo06BumrctjOH+ziyx3bbKXaDSr4IHH0uWW+sFSRKJhyVJD pAj3AfqxaSCQA== Date: Wed, 13 Mar 2024 10:53:05 -0700 Subject: [PATCH 02/29] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223392.2613863.15143059690877826757.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:53: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: 13591701 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 9B95357883; Wed, 13 Mar 2024 17:53:22 +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=1710352402; cv=none; b=t71GbVZ7mF+bMtSybpDyGSXUDIjggUISCBL2iX2+tYshVKhCnb7PBPcLgXokDwlRzDjkaQ6Al3OrMzAO9U2wI5zA9eA4brIDiI+du8PmQm5Dxop5RFMTqPR8DJoGW2r+QJ6n8Lij3BdVDHB/uPrGTQyAfCIjz8AeUIr5wffrJ/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352402; c=relaxed/simple; bh=3PiQWLCvQqjS7LPBm90t4SOaaoJMbpAwofTbsuxbe28=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=I7Vr6CdRG5XTci+X6J82NI/LvmjHino6hW7WLNN+OiTU6TzsitTt8c4T8dbLnPDR+uqIcgRkeM17AMxWtWCea2o+Sn2yCoytuAoNTk3keaPiWskIw6wBnqgyx5rMKekC/gi365vSVhwjCn8FQZSyD3AH3N8lUn6vByJIGtuuN4k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uMsca0I7; 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="uMsca0I7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1EF46C433C7; Wed, 13 Mar 2024 17:53:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352402; bh=3PiQWLCvQqjS7LPBm90t4SOaaoJMbpAwofTbsuxbe28=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=uMsca0I7Y5RMuBVfUKrHGZhMro1DK1OYupPS0SqJZocjzX531WxM7unVMubz1gCi7 VE3U0LkhKax6nlt5SIlkVW5gh7Re/pKrT1yVJ7OUF3Sgx8NE8rm9pOlKgfpT4w95KF PwUWLRVE3hOTIZfeRQFtCp4xjTo8Gsu/NVcCW112CuFzu/CyxPxJPbZc2EPme7gVKk uAHOrktJkK4RYDS4tcb94ffbk6PWtwYLYEadrzpgRJoEvXa4EXvo+xBbklW/AUNAli aIDnlzoQediGjsRlZEuNmTUEsNKAyMYllKsSRDtwgeHgglQjXlAe0UASihxI7Qh4fW In+djyAQfJinw== Date: Wed, 13 Mar 2024 10:53:21 -0700 Subject: [PATCH 03/29] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: Dave Chinner , Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223408.2613863.9861308344244312301.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:53:37 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: 13591702 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 7164913DB9B; Wed, 13 Mar 2024 17:53: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=1710352418; cv=none; b=g+Lt5WbMCJfs7uLAsHWcreV08diyC+XvZqF2cHe4nWR2niGhJsGJYlQQsoZDYqFMdgn00DVErE/TKCQvyc1eOspmv/l3lAeh9BEb/r3zW2j2nqWbbxWnqRz5XERFWPyM9naoeG5/30fpXNNK6eupG9ncKxpRNIyAZFn/ZV/zrqI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352418; c=relaxed/simple; bh=QlJAa+uqVG2dhy6hqzccOs4xjxALGADksKWeBhfsQ3U=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZRQXz++aH7a1vU6EdqR307AYHmPWQ1dh5hDcp1eXS6Mo9QWuQMnFnzaiuVgZsj2+c2Qr3/MZMPClzROKm3jDFqgXxa+IHguMA2gDP3mbEW0BTZ7tfcstBSHuSFx4XqleIVwWqqS1gzGhZvi2K7b14odrZjrcIfMb0J1+BqEgD3Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Yl63tgd+; 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="Yl63tgd+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C8025C433C7; Wed, 13 Mar 2024 17:53:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352417; bh=QlJAa+uqVG2dhy6hqzccOs4xjxALGADksKWeBhfsQ3U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Yl63tgd+CGSnWASffx+TqrUCAEgwkFrQ98E+lRVrEEOK6wrooQ1x1ogLiXj5MdeSh UV54F3ozrk5WCOHlxtXUKVNmLZqpuUExRVCdcm3qlp8+ZQqVZKAd8l8KaAZltnzWia 0Kf8RxJw2hktd86Z1YfrlpplpuI38QK7UNsSPsKsLl/HaA5BuugJ1uC4z98e4Epqlz XedHxyw9y3I1Zqfm2xFv4tCvB+vIcJ7JQuiyio8ZkjQdShDW7zTHrz+fx+im710sCv SaaT4w6L0YFMcVzA1haw94LLwXcnN6ol+1OcImqxn3mX272pfnCFY7kLo0paNoxXYI 59m2wdqaN/g7w== Date: Wed, 13 Mar 2024 10:53:37 -0700 Subject: [PATCH 04/29] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: Allison Henderson , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223424.2613863.10249525423420622979.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:53:53 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: 13591703 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 F057913F434; Wed, 13 Mar 2024 17:53: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=1710352434; cv=none; b=rOTyGO8a/raJ0ZNqeE5FUcLqRNTZvInPYBtNESwCk4Qk0zExOMBtWWad2TVJrW1e+B3tTtCp6sU9eRBdA3/uHcgqji2Foa62nV3nNkPt9/ud8mH4WtpyKE9VknPJT/9QLsFIPbgqZhPigTvtX9epp4zWJ8v6vvrfBBDwn7bLn/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352434; c=relaxed/simple; bh=dtKcdSScfcG6Cfxhp6/Ic3o355SRhRXikVozgstP7bA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CSubexwa/j76HNhkf1qsWop7p5RuUDO3LZsLEQQA4UbKhsFq4n0p9XjL5ELHGQz97RIuoqHfCNRXwwhZrgVNMJ9RYuds2Tt9yHB7bp3AnZ1LMoDUxgKhuiQIyH6mve09nyyDUiHlVu3owKP6GR7E3vR/0DEPu/oOrwmOG5K1GVg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oI9jJYJu; 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="oI9jJYJu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 69C08C43390; Wed, 13 Mar 2024 17:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352433; bh=dtKcdSScfcG6Cfxhp6/Ic3o355SRhRXikVozgstP7bA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=oI9jJYJuC4bw6H9DeJQMpfGBAy/SztnT/GrcZ/4X0vsYnJ+xqPFFU5EomB1Iqu0W+ 32FCIGt1mEKOkkwijIMD9V5+i+kbukIzMcaNzzfLrjFK65pvLo5aQXYnnYi3mX1Efn 51BJL0eRw/zVfZTbDM7KyDKDmvhFIIeKY5RvNHCcFWtCQJZi7+/YT4KoLHOEvWKlpg 4S9HPGKPVGdqB6csvFuKawGb2sdkCIoe2vy+Wghap2vQ2tdBAt5xjgT/u6SF6GGIfY gNdpx2RaMn9TIxGEPD9/wN9limiXU2v3Bl/Oymw+39aTjoWgcfJ5uaXQ/H80RB865r O02ytJrORpA9A== Date: Wed, 13 Mar 2024 10:53:53 -0700 Subject: [PATCH 05/29] fs: add FS_XFLAG_VERITY for verity files From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223440.2613863.8427654020554839588.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:54: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: 13591704 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 884CF6FE0F; Wed, 13 Mar 2024 17:54:09 +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=1710352450; cv=none; b=OMyDVe5hZDgaQNIrL65UjvgZJ7BacKie4PWA0Ia55PdZzsb6H1rtS+E+So+aFzmhM9vwpP0VWO57KGMdVtmwHF5rJVc/Jp/U6Pp4S/46ihKxsDg/zKt7BjLwZFo8R4McYoKsm41Z+ePNuf8JrVQYrHopFrFboM32qPgUFvKT6Fw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352450; c=relaxed/simple; bh=KcBxCsDbbHTMEwAn8JLG5V8IPCr3cER3Edi8B9kP5d4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oZ24ybn50d74/RkugWaBCeUPSVsNRjbMhb4MtSRTIArb8xjM1llCAhdyVWfTEeeLAykcJ10mA5TVmeNPkKPnJO5mgk6BegfE6O5UmHi6L5Q5pLt8jNBh9g2RTZH2EFO83x8jnjC0ntZGuYRzkz6AMuFQsUMp3MOJm6yhIyeMr6s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lIYR5T26; 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="lIYR5T26" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 05945C433C7; Wed, 13 Mar 2024 17:54:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352449; bh=KcBxCsDbbHTMEwAn8JLG5V8IPCr3cER3Edi8B9kP5d4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=lIYR5T26dn7gRHWvHqyI7Zss0ww+toll0b8Xwx4dLXicFSbUzGGwvwGGBOkeL8r5U EZZIKGTTfZkH1Jle72cThtaOXUVf01BWmKXwyKT90DyDNLY90o42D2rgEGmDokNcEQ FfkHLhQmMsuwsntr3CqlR8Dr0qPUk5sOaPRhP2LGHTgtRv9jukq3H5M5zgZ0UAxfIt pqwoS6wMky4jhtH/MhzVx8y5rSJX05gF0yqlYkckZ8/xglIxxBVawTyTsa16IQTF2r OvIe3H2SdT447UigskFFcoDMZmR9B5gc1udtBrOP1cbSqACpS0zkHPNKw/7S/1CT7m RIITrpTBukE6Q== Date: Wed, 13 Mar 2024 10:54:08 -0700 Subject: [PATCH 06/29] fsverity: pass tree_blocksize to end_enable_verity() From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223456.2613863.9854798540968285813.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:54:24 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: 13591705 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 E94E858AAC; Wed, 13 Mar 2024 17:54: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=1710352465; cv=none; b=uPi9vdeuf7eArOThevAw3qfN3rWPZ8emP5RSHPKpXEgNnvd9U36K9XDa/tSdXC4AIKkhfe26jPRd8bTM7sOgya5N7Sc8SwFrMaBaV/ETgXBF+Omjf/H5po5wAsjdAsJeVq1VBzkANbbqpj3KnWZswFhv72p5EhVVUar1ybKM4qI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352465; c=relaxed/simple; bh=FC+paGrNxsjCbjU/yjE7JUcL1xa0Tbz8cr6Qe2XCNhQ=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Qo+oco8ar3cajUDuWZgFjaeB4ZXWd4G3XzVt/sO+bZ9cP07PEieu3PocLjfXBQltYwnVU+FUD65PnReE2vM0WqomTGvy/UGeOij6bm7vBtzJ3MnsvGJuGY6VKQHRnEA0dDbluQkXnFBRzRFIqPcZiLsoMpctRps1FMpV2e63iwo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SbHxkBu1; 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="SbHxkBu1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B7FCFC433C7; Wed, 13 Mar 2024 17:54:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352464; bh=FC+paGrNxsjCbjU/yjE7JUcL1xa0Tbz8cr6Qe2XCNhQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=SbHxkBu1xyCvwVm7K4CsUvhva0eePB/mUTRJntzjs/9uKlOYo4H1duQHLS0H3cEpg tu1vy5kA/XvTf4Y3CWDTMKnxCncxgjB9sHtRaLBDDzX09eXxx/qhrx1C29YzSHX27p F4w3gQeoXfiHqnhyP6ZrJj0ZJNZmHkrpbmUwmOk5yrirV4mG9Qmr8A2iV1p915CvZ3 1+S3jttu3x6PxtMEEGwGhr7xeTd12adOvIP/6rTPL33RzTwWQhS96dLKfIw4qN8neu PYZD78iIXjaxwZlGWPpm4fwvesBDxHNdHNye9rqC6e31XYr7zS0FV30vn3XT2j8MSi 3mTy8NGK67P4g== Date: Wed, 13 Mar 2024 10:54:24 -0700 Subject: [PATCH 07/29] fsverity: support block-based Merkle tree caching From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223472.2613863.100005049884204420.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:54: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: 13591706 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 DBC816FE2C; Wed, 13 Mar 2024 17:54:40 +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=1710352481; cv=none; b=HeIfqlaV3A5bJgw4Y8XqZl2WILX6Em4seRwrWWGuHiE4LhHddHUdLpwc/9l86C2qomJPQ/390GqDlrzsFTUZQHfzuC4k2kjZyxExpL4uqhH6rv1qHGzlL2QqBxPqgkpwb1MTnw+VX/1tLvusx1f+JUAObfVKJPf4Lavx9iU5wqg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352481; c=relaxed/simple; bh=Jga8LsAuSK0NzpEyTkqZak5vw6dw9HXNVyIkYjY6U3U=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Gi1hxee1bJZN8yxeOVH7RgSVYeEeVdAHTQoGFOHn9F9Prhpf3d41+AbDBM+QWSZ/3AL+To2zjpz4loTNqhkbWjQS5baqZXOqUoKl0VPS8iH7NWBiHsCUOsvF8U/Kki4GS4DP6Q1B5Btmb6O9wQm5z1v3g1iV4C4YVufr+zSdSso= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Pa+si+qD; 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="Pa+si+qD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59E03C433F1; Wed, 13 Mar 2024 17:54:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352480; bh=Jga8LsAuSK0NzpEyTkqZak5vw6dw9HXNVyIkYjY6U3U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Pa+si+qDPR56IJIDMtHS+aMO+O9xYOWkGl5LtAeO/LmaBxrwDtXh7gn/k+vj+ma4z GsZ2AF08HSCtvhFXMYMkhyakiKiGBIubh1meDmaaIRkE8KUuWvmxsmsm09StY8PIHH FgfIp+YPZjYs2mfd2TxR1VgbKikfr+KrpwDMAMVa1HYJTvuuGGk1JhHe8IXlJK/cf/ tReiWahStW+NGw/Iz5hrYUtIHotTPhtMxKMEKIq2vQsI5G2YFyIA/jHUURY9JhdFR+ dT6PRQj9q/561JpIP7HPfxDLEfdtTSF4QF82teciBRHJQmfsidgp//m2IOHZWC6ISv igacJoQ81Md7g== Date: Wed, 13 Mar 2024 10:54:39 -0700 Subject: [PATCH 08/29] fsverity: add per-sb workqueue for post read processing From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223488.2613863.7583467519759571221.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:54: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: 13591707 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 95A5B58112; Wed, 13 Mar 2024 17:54:56 +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=1710352496; cv=none; b=QirPQg6TbOPUkkLVw2yM677+NpkEMdrWjvFfc3YVHNo0LbP8wV84O3APjie4y+jzIqp54M2QLwWtq8NTE8QMpBx/SKveXiHwR5WqjSIB2jrb8hGMxUN+BZOWmxHxMzypHT3EHcHsVbzQuuuMxZf4wZ1pNAx34gKH+mJVKmMd4jE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352496; 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=m2W43s00basV9ZK9HD0Ua2vV9apbYIKBwI3p+wxXdIqJBC1TKto6nxncFTgMO0AbAgGToQ/FBzCr8IYXFCoib9wH7M++hc2PA1eTNRXCkBXh++WyQiT5R9WxHb9VPwlT4wl1tBdUwZfssJlZi24qRS6G2NFJznhXYiQs4KFMPPk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JjFosTPO; 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="JjFosTPO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1182EC433F1; Wed, 13 Mar 2024 17:54:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352496; bh=Cfc8Wh5ih1PbHmvtZBPxYw2Ha/gR/b+FltBbCXvcgOg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=JjFosTPOeMaAbfWsbIbbmOWl5Nz9LjqqMMvZOfuYCz6U8uZTbldgV7YXqznCnTnwa Uwisqut4UNw0tSCnIA/L4ROfyJUj1W2VMlPjZO9Vh+C6UpUFNOse1tJrk7SlqO6V8D gfjYE6zAvHwHqZefb3ZLeGishNVSPchnwggqBwb63aYf9SgjqNu2UKenM68g3zLgyf Vs32CkDnOxQ15IrKGvDQJf6yDDKP3MttuOr/W6ROX0kVg/WUHEe2pdjYJXz6GGe0DM znOys9irvMFdkndGT5u7wdblhAYzwfOym3GVa2Evm9tWBEpn8Qrpn/QQjuDWsQ31NF AycE6s+P33KXQ== Date: Wed, 13 Mar 2024 10:54:55 -0700 Subject: [PATCH 09/29] fsverity: add tracepoints From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223503.2613863.2210260897626144087.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:55:11 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: 13591708 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 3E5A558AB8; Wed, 13 Mar 2024 17:55: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=1710352512; cv=none; b=nlNWz2Ldi0v2TW4G24ogC7OCnoaxS6jx4+LaNiOv8ByqoVJNzy9HpPxe7nIkqazAIlf8V3x/Q8DR2YxEp/R025iETkfChluxze/8zv4cYsu1BBQHw02ACdGUCwEo8R5nerGgIj8pTPqEiDdMn4BuAppE2Bi/XKPU3ucfejPxOyA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352512; c=relaxed/simple; bh=8uxd87nDK26U75DT/QB9AwLkCWL2IwnONr4z5q81X38=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SyBfb4F6PyYls2Rj11grwWslMidLVBH+Y0kCU01k+S7kPT3o5n7FEvwNTqgJHAfseOMhWPGFbYnhHOsetaBiccQrNwP3KPTKgoc0Si3zfZ4bacozFIOFFenDDFTh4vbTcXhLqAXxMlVtEBg0pPJRMUN8reg8/Amz9jMTizrce5A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CVNCTees; 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="CVNCTees" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A45A2C433C7; Wed, 13 Mar 2024 17:55:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352511; bh=8uxd87nDK26U75DT/QB9AwLkCWL2IwnONr4z5q81X38=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=CVNCTeesDCP76Lzc9/kailZEql5Xke11g1NXjyZRr/k2H9IakdKvh0QGWv2DA+f8z gNtKggDUYcS01Z8lbwD7eUmFe1hsKka7TEetFdyghwn+4Ngnu7IzjuXmcSD0H4KRy1 X7lWHSHfMwwE1Q63+GH2Go7w3zTQ3HIYWg2BICIS3x91f5Bx76/AT/ED7DOMyJQACG UuWDj5exaAxNwixmXy8fDULQ6MHBBbi+6wPvuIfEhSR/GGWA2upBMNb7ZgII7qc33g bRBEEqTG/mVQM1qXbdO3lZYljD7arR6ftfgXqIyOH8n6JNDGB64xHlBJ0pIbgg8f0b KkDOcut41gPLw== Date: Wed, 13 Mar 2024 10:55:11 -0700 Subject: [PATCH 10/29] fsverity: fix "support block-based Merkle tree caching" From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223520.2613863.1075926534889446359.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:55: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: 13591709 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 CED2B58AB8; Wed, 13 Mar 2024 17:55: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=1710352527; cv=none; b=jMHjhoQLA8MQ6zT9C0i5hXXi6ewLc9t9Fro7Yd8JA9vrLu1Ebwb2Rh1NDNuB/7yKdQO54tNjVCaA4M4yyFtRN1ymK2bkCAuJ1E68kUSJb07tqUn3Jobu37TibPJzt14LfXlMDuxQHDTIXOAmvOJTd/V8U4z7oYwxx8pkmbOCAkA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352527; c=relaxed/simple; bh=1MnT1ZpW/vtlTpR5rEaheiz7VcBK8zfu40pO4zxZE80=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aqCrWTnht85MSmeqATvFfU0SjdGaiffQpWHH0AxmV0LTuP2PdazesW+WMz+Lw6EerA3sjiLdz3ODOJKUClchuqYX8ZGc/w+4zmZj3BFalvk7b1jdstWdLevcfmSf6Wn4fOhyZStKqCGm03j6VSNu84JzhcxlCbsl10+SJ6YA1w8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=I1y19isz; 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="I1y19isz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59820C433F1; Wed, 13 Mar 2024 17:55:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352527; bh=1MnT1ZpW/vtlTpR5rEaheiz7VcBK8zfu40pO4zxZE80=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=I1y19iszyvoBhRU8wom9YBKnvD6z1n+V7R4pLgvvh+S8NssQcCwAqsjA2Hwxy2HM5 eq+x2y5AGELIXjRj4hJ0zH65NBLjqVkU/S9sYZnjgcNkpcr6FqKbB/5hGiiFEtKp1H qAnGiO0TJYWktBLMYnb3zGGnelC/wlfYa3e+JTRYZQRjb0RWIEDihXG3JJSj8JuiES AV5318zAXChqVlKVE0rtG2bMyE3+VJH1DVopKyYbAdlGR+CO2jfTTuUUlXdQ3cOkeI 1RYQyYs9dtipkDvBVubthXaXRJ/7wX1XLvuLgfEU9OKcReY3+TN0N2bX5WvfyrJ+6t tsgLPjeGWhnTA== Date: Wed, 13 Mar 2024 10:55:26 -0700 Subject: [PATCH 11/29] fsverity: send the level of the merkle tree block to ->read_merkle_tree_block From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223536.2613863.16457126075122515194.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:55: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: 13591710 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 67EC358AB8; Wed, 13 Mar 2024 17:55:43 +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=1710352543; cv=none; b=IC5SdNzj8v2NW+UY8waV8EkVfbX6L6b+SW/OhfnzI4gPMvQalyjaXIsOvk6ElLrWoVRN4XEXnBp16AIfd7TlHH0a/Lm0q0CB+KtmVJ8GYYh+rcNnFGdZd/67XNIjOmJ6+kwBXkhqyQQVYJE0YdMIyPVE5bRaCcx+py5tMB85XBE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352543; c=relaxed/simple; bh=RWvS6hYxLBMDy+8cpkZisjZ45FWaV2WRXSY+F3T1zmE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=kafRXGfMPykSwSgRV4N9yvnGByW3U8VeqfpcI/cjydc04wi+gTLswmvGMIrfDCGP+Zz+Mp0dx3+EbaUf6r60BTghMbnuG9OYnmpCCUUAF1QZMvxAs/IxRmbJ5gh9yUwbOptefkGT5+MPhFVQyyrifoU6DqpiKBLyf6Ijl3hCGsc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ma9f8UYj; 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="ma9f8UYj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E4694C433F1; Wed, 13 Mar 2024 17:55:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352542; bh=RWvS6hYxLBMDy+8cpkZisjZ45FWaV2WRXSY+F3T1zmE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ma9f8UYjbM2p5OIKh/5OmQn5uoCCqw/1W4xM7Ia5xB1JZOlDt/8F9pQ99o8LftnBO e+kOG50jhnIGE76FRoiSZEKdqIEiaWqC9hS4sN0DSco6WhUL54Ai/SCbl8viOb14WD HnTzuRxuceLnwwxZPzV2XHKlDFpRNDzayKJgK52SM6vBz+FwA9EmcQWlmtXKQExBod pNZsAUoPjh3QyDhirlie7wfxSNe29qge3kpKuXNqdYcvvdnAtkYQefds5joh5qyeCK DPqTRqOBJmNe65T8vzZQGyMZ4wyQSMX5lKw4S+R5vbEEA0hf6oPpCqNjyOZ4NvfBLY ZIaQaQJOQlg0w== Date: Wed, 13 Mar 2024 10:55:42 -0700 Subject: [PATCH 12/29] fsverity: pass the new tree size and block size to ->begin_enable_verity From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223552.2613863.13214675612130115848.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:55:58 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: 13591711 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 043C058AC5; Wed, 13 Mar 2024 17:55: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=1710352559; cv=none; b=g6IE6fXSq4WHv4iiiHup5HfZHq9Ae7gFTeWjGvg5lsqGdQUQyPuQ91tOzUcZyd4A6pODxNFbsod1SbGxpuPoCfSkVOYfDIMCzzp5rotaFJtEvdBZf92znM1ZUt7igznxQ+lJLonxuIiw5yeFRQHFRa35LfPor8UXUySFRs8VU+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352559; c=relaxed/simple; bh=kMdqz7RLV569ab/XXjmmU/XwIDmkNbuvXEq3UWvjaMk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nUk/4ASyBEl3SH3WOsKFqyR5Lp29/kzgrTRWZIdweFGif7AHZezRfXzT4WEZ1qeNzpsUyhCyFB7u5SuC6CCGgIQOKdxuzszZ7Chq65If4Q7r/CpDs2NN9qv0qNk6B9UyfukdTu85gYnQrE7wy+CCZEI8ogXM8k/SETIlbKZTnbc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Tqd8d32S; 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="Tqd8d32S" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8049AC4166B; Wed, 13 Mar 2024 17:55:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352558; bh=kMdqz7RLV569ab/XXjmmU/XwIDmkNbuvXEq3UWvjaMk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Tqd8d32SPrM/Q+9QfN+LaIUCtlJfaksXsZ0OsjGQBCMkzvmcfGKVeC+azvctN7qHP Ey5DdeL0CGSipalmGOhr0IRj7zjy1C9GHs0Kgxr0p/Z4Ex95ESIu3fZrflycLba78V 7jA0REUdQsnJVQr7sOBqCbDqV/Y4G9kJQ1TeSaV8rNQqukqShsN7+9ZEztnn5MBiWE NPM4YVCH/a/5/PsBZmOwrJFREVRrFA/krRILQohStdtpW/GwY4pgSjbhcGGrv6Lygw GEHFUx33wBHAF1kJgoC167ic2NFUj2CZi/Ic08/fU6R3cw74BLVvybfxf2nC+oT8is kjJ+Epx5dBo9A== Date: Wed, 13 Mar 2024 10:55:58 -0700 Subject: [PATCH 13/29] iomap: integrate fs-verity verification into iomap's read path From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: Christoph Hellwig , linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223568.2613863.4052027843522117859.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:56: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: 13591712 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 A0BB31448D7; Wed, 13 Mar 2024 17:56: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=1710352574; cv=none; b=OzeCNwDuvljDHQxYFoBWzv35PJkgMgynp71VUV5R+EHgz9EetmGTq8q4Y0LxeMBQZlYg2EmoOjI4eUvHqR+79dgpjPFrLFn1ur6tS8B/qlVz5NGnw37YCpiqZcNZzy2KUGsDIjL8VhQ+CyuLShN8y79pVEXNl2tqnFIcfSw8yMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352574; c=relaxed/simple; bh=YV2FpcHp1T9nZAjzqj8IXFCQoFgRWZQjMLPyND0pLlc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tTZIsJinkdPVH6Kmg5crl7/BNWjQ2oLkOw27sUZ9bOjqKhnGTJtoyE05pORmPBXoyU79v5/zCs5VhD51/FlA9eEJeQWPGTJoWr+ixyJ75Qke80SEefioX2Lyyy7un16P4TZAYCbLJM/eobRy/6NjWBkbuDzSj27pOPd76Q/XBtE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fcOnwz55; 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="fcOnwz55" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2A23AC433C7; Wed, 13 Mar 2024 17:56:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352574; bh=YV2FpcHp1T9nZAjzqj8IXFCQoFgRWZQjMLPyND0pLlc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=fcOnwz55kBmBXX+/GHlIC3az89npUUmVu5tv0Y6sZXt3ayFWw4IhlcgxGIK+N/fY+ LNJc4a/+KX5Rlxrp4PNaHNKqcoRn1ijooyzt7Mb2zE3zFp/y4/1KpepUd+ZwUwYY5k fvzfA6S1+m27VNSPqAW2lhKdmvn1DYInEOAv0j52XUuU4QAHeBEJ2a9HY7z+r1LmvN nuIjRySKCh2XU1OVfJRr1yWvzXuUUPJ3HeAe0DgFkO8lxNlptUlBh7XA6TjnZaK4cG oKMpZ74BHahly6PaU7v1RhzD7qi89OLMOdKZ9VsvxXcAOOyeVw0UTDKqBv7IgsBsjp ZouKvWyu5E2eA== Date: Wed, 13 Mar 2024 10:56:13 -0700 Subject: [PATCH 14/29] xfs: add attribute type for fs-verity From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223583.2613863.2342282023194573649.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:56: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: 13591713 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 555A91448C1; Wed, 13 Mar 2024 17:56: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=1710352590; cv=none; b=LsyDSEA9KzDqP6yfoF4w2+Q5YtoIDe3dcueI30qf8r1i34IX6vTnBw6FIfva9RWKR0P5dDKYILo5o1NPm2JjBvo3knSyp/7J4ttt86kVHETyrAZlI2Fx1xxR2OfniQ5c3sOyVHRDF8UadVFodFduFOA8D5PXT0a9x3mM3K9CoWQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352590; c=relaxed/simple; bh=FzNl6nZ5sppQ85tcUujB6tjeJo5nqun0Z4MKseE0oes=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MU8L5Kzdt4htj0XrlRKyYKtBr94kAcyjF4kRYYUyszVMZfrXmfXAmMYX9C95FQ26pD/3GltyyFEEfDMiYgffpl28bKoXckhKohShgMsmDwypls2JQPT7hKGi2J8D9XeKaYqmXMfz89uRF8YONpkGId1+dMxRVomp9YgpO/xNz1I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=c/VZSL5o; 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="c/VZSL5o" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CB2A2C433C7; Wed, 13 Mar 2024 17:56:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352589; bh=FzNl6nZ5sppQ85tcUujB6tjeJo5nqun0Z4MKseE0oes=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=c/VZSL5oQEV9qlu1whlxfzuBUJqxXyijksgdSBkJTa1mSGAJL11U84A/qBDCm/Br+ Cx2EAy6v2OtzyMGoT1VIn2Ei2Y2Fg7fKS9dYCw/z96X1fzY9nUIj0yW34kfkfLJXrQ MPvc6AeqAA68v8dM+ietXm89lzirke0s3++RvMAZ7czPt4axJnGyOxgH9k8q+EXFn3 YiQPSTPezAMOkH205yS74h5HbZD/xA6DYbzKkU4f7GRpMVi7VBQYXaMAzR4VMPHFc6 IP20pg2TZJ3/kfuJFDFiI84+HG13Tss8Td5PCduH/6nAAE18aaJ8NBR1IZdveCdmBJ qqWqxTr+NiQmA== Date: Wed, 13 Mar 2024 10:56:29 -0700 Subject: [PATCH 15/29] xfs: add fs-verity ro-compat flag From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223599.2613863.9328414681604065824.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:56: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: 13591714 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 A051959163; Wed, 13 Mar 2024 17:56: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=1710352605; cv=none; b=VtKdcecsDsFLezGx3+C4aorlFUydh3wc+eucPocV1TcBA45v4I8u9BnjU9z4Pir1q2U0jAizTzB9BBAPzGNpaFJIUYT70EV087MsbP9q0OdW6X9vtWMqKtzvVneg6QwQIe8fELrlNleZUdgQZXwFRC+L/tctCzHX/zAyNpvG6kE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352605; c=relaxed/simple; bh=tXbnyqEYd6P7nbzJPZXz7zhP2hgKT0AzmTorGbDebQg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DUht7fqb3BTP2gvb3ONoFKHblC41n/ZN+9sqxAn6+wLXnLtKKQHiic1+jLneoo5hPtLC+GSXWbAFuuSBpO9Ywc2ZYRbzXb+SQB2jN0L4CEJ8ydbDwORLAzy0iRLQSJzr85c9rFddy5R0tSuvyBGWc14Vavk5mLV6WOzxJGhLQmg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iU2cat1I; 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="iU2cat1I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 75AE4C433F1; Wed, 13 Mar 2024 17:56:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352605; bh=tXbnyqEYd6P7nbzJPZXz7zhP2hgKT0AzmTorGbDebQg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iU2cat1I9W1dzSExp1cD76i0vspl7fdnC7h2wHb9DGN3tksQeY6jXPnhffZ/4YOnt hNv1Ab4p3labB/o77x1bJfIX/Hc+qyK8jHXwSmpFgUAeEYv9yHObodPmjhpC+WrW9t OVVVo7fK6jMGeXJjQAURUlS+E3G/jRmBESYlkMTsX/nkn3pYD86wGe4B2DWD6pTatj apyFOGwjT1NxcX2LMI84mYAUMHhB2Qxken6ELrQevB+PrSZ2zPG4S/YBlwzNbjThmB 744g6B8N1UPLxKHSuCt8lXutQKYFqmvDXGTivv+zr/DqJJ+0HaqOzFD7AFei8V//CP KD4hsZgtud3jA== Date: Wed, 13 Mar 2024 10:56:44 -0700 Subject: [PATCH 16/29] xfs: add inode on-disk VERITY flag From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223615.2613863.15297615361006376900.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:57: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: 13591752 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 8E76C145328; Wed, 13 Mar 2024 17:57:01 +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=1710352621; cv=none; b=Uo/cM7wTBUPDYmNNQProBq5qafHkxe/tYIFA5j4jveCfTKErXvZsXHlUtvyAe2jQO5w9BZtl2yESGFyjIU/6t53JS/FeUd2Itsb6iGZJ3e/ng4ADLh1ONsCEE+ddG+QoK6gocmuNTE14Lj2B6UCMGpbVinVSQqv7RYMe4XCe+F0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352621; c=relaxed/simple; bh=IbdxCYJ2BOtFhytk6YBJUGUCJBZ0PkrYYAYsg50vfqg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MuOT0+vcOzC/P91ExPhNIcs0WTGqqMEjQJOzleH2cgFSCxpBQOr/Ygwr54qgpRwRUk+EvF8BrEqcvOBnx72rMOCSGHMp54ofilpjB7rTm3H+CL7eKAKb2KdROq2yoTBF5OTLbZaXywhtcR2MhXJ6eFxqTSfZ1XFaYRJIhksbwew= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=V9V5s+K0; 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="V9V5s+K0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 14EFAC433C7; Wed, 13 Mar 2024 17:57:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352621; bh=IbdxCYJ2BOtFhytk6YBJUGUCJBZ0PkrYYAYsg50vfqg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=V9V5s+K014XjtIcD2gE5copbAH5iN82hVkYuOjAqlGxzf0qiGrFoHKTfzlvewC41Y VvtdKXyKBOIRqhd7dQno6+X1ODp/toqZKD4niwzdOQcBWCmzuVQ+YDbqRU1CXKwMfF VwYiBzTi3C9zSoS+k7zng31oyMkav6fhbb0BZIeK0DU7d7akzReQd0APeLbUatqRV3 fwvaQ8qTd08nFp0P+yBbSUT0OsCZj2XOayz/DwUDPs/9fmGqDEhtdM+MMoW3lj5Apd 72919oXtxNt4gtbO/7NiLQpozXkn6HpjFAjBMVnctFfVPbermdBlmmHLFjYFFxAkSW uDfyaDxbfDKfQ== Date: Wed, 13 Mar 2024 10:57:00 -0700 Subject: [PATCH 17/29] xfs: initialize fs-verity on file open and cleanup on inode destruction From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223631.2613863.8250273414508285661.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:57:16 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: 13591753 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 D2519145333; Wed, 13 Mar 2024 17:57: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=1710352636; cv=none; b=r5jKo942YE7qkW8JLnGIzlFV2KY6EPkbu8cZH1SHbHAPx2tnz7gJmwUFxn+qvpMDqto+quLM6GRwO9AmdvMIEQwY7QS3TcqJoAgWgp87Ez/Frc6wDjmOqCns0CAWPusKq/MyGIxY3s8PFPVy6aWHdUx+6K9PqI+Rkptu+DgEbAw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352636; c=relaxed/simple; bh=mB3EmY4L8UVv1yUNzGfufjLv8z0elMsZvlto+EA/uYI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DDkzyP8EGwwDnFdd9h2UJvCRc8y9JPg9I4byK5Ch52zq5uLdiCRMQ/hvCItesHlZoxlc/z1vS0hTdimPeQEMa4csUiEfs6Ywh7dUSnRN+i1PBqKwnHxGQPzoga3I2Mu72qtbhPDZaX3hjVROdifoFmYQV2vW+ZDPsnxM6RRlPxQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rlYt4qu1; 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="rlYt4qu1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AB257C433C7; Wed, 13 Mar 2024 17:57:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352636; bh=mB3EmY4L8UVv1yUNzGfufjLv8z0elMsZvlto+EA/uYI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=rlYt4qu17Qb7Z59LtEGLwJDiEwrF1rKAkcnqciKASghPCntZ1tszqv5Ow8l6OjTAi oRtB47pR4mBFp1THM6RjQ2sfcT9Ekwrj7XysfyOrJsT+pl1yPt9L8LYHoi6AzOvYfR jIGNgaueJRjPtty6VPZzpj93TF4bQcHwJXjxUHdYo6Fa3KSKfjp+rjMcff4XkoHI9X h7s16acBIQl9aLjBuqc7b9QreAJwMJqRmWoUqVc6IzfapvO+LasGljNQiaYoqgokG0 8QfgmHh9g0cKjcgf3FXwM0is4l9AWAc5EnI8N/6R9fwLJi5VBFim1KfVY1/81EDcIN +sUhyF9o19cLQ== Date: Wed, 13 Mar 2024 10:57:16 -0700 Subject: [PATCH 18/29] xfs: don't allow to enable DAX on fs-verity sealed inode From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223647.2613863.14260697427402894964.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:57: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: 13591754 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 84AFA59B44; Wed, 13 Mar 2024 17:57: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=1710352652; cv=none; b=UVg3/8ZU2K77rtSpgrjzwqc+mR3tO7BCIff4/+HxqglfGX94nOPbXCXNJAHtKmdrZIZWJB9rPB/8J2mp0Zw085sxLWPkfHsN+c0f/YJ0VQQer2KzXTOeW2i1qsgRvu3SJ0l4ATrbC8uFJUGLsf38LXC4K9PbL5RSvS/xPmdZL+0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352652; c=relaxed/simple; bh=SlQI136CHhejSV55+uq80fnqYG4X2Ac5Dqu6QQDTOlo=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Af4X2s72vQzzGDTuUE+QsVRoB4hN/VDU4XLw3RGUQ7wGYK/NRRG8vYlulAf9KREfJ13kVmnXCsoXEwGEtrYuuqvSSDPiLITbbkV1R1t0XXN2DJWh9BX1S8KaPBwgIYXGEnsxxtz6ilwnoMgKe8jCIvl3KSlNcSYiGvP1bH/xD6s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DCWnTH0K; 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="DCWnTH0K" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4CC42C433C7; Wed, 13 Mar 2024 17:57:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352652; bh=SlQI136CHhejSV55+uq80fnqYG4X2Ac5Dqu6QQDTOlo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=DCWnTH0KHwn7h+NQs0JgOCTsdd/PX45PmxdLnsZz5+FUIJy7B5L5zweoMUZM7xksA n7fo+I3zGhcKDm0zu7CDRisJsGS5brBrPDIb0tnOqanbJX1c5x6DKcwR/aTAPC5ked mzDp2ITGeXkmOEbn13lfzsPHASGjhbEZBsTTqixZg5dOlsnqesLNojs7OJOg4psb2a yWv6bSoN1Zc/DqZNL7jEC1Pt0WG4Lozj2VLXvZHqHiPUWjrI9j3UD8bsrRAo/iJULo jkA/bLnbE1tKvUhTo+ukBoCjXajRGqa8QPNIsYzsja2LiFY9GEV1VKNW3xsV+Vh1P8 Jjy/zQwWhtpYw== Date: Wed, 13 Mar 2024 10:57:31 -0700 Subject: [PATCH 19/29] xfs: disable direct read path for fs-verity files From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223662.2613863.13145834890665570172.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:57: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: 13591755 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 50AAD42AA7; Wed, 13 Mar 2024 17:57:48 +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=1710352668; cv=none; b=D+K8t0eQ8IpWsJoVY9Q7z7uKIEauEDcVAaT5T9yHlWCxocgPtlCFhjZZpHPyClwIi/FCZU/4kNt1wbkY4t7vaARUb0GZQWladOCXx3oOzFtTR2h5/sFe4TQ6tvtqMIHXUmnfNjiloyNqnTcKlHZya7uGzPtjZPuTfUeNj7EUaJU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352668; c=relaxed/simple; bh=el7fu9wQ+wCYZSmj8Df/MzRCK0qEMwnhbP3oOjYhriU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NsdDzX4uFFxEN8K77amgZ+0Aqt7bt6MxpYdx44z7UIQWk0hL4d5xtF4ixzWXH1zuVmj0swUOnt2mq49FTqDCDIWoCm/tjNS8MpePkYzk67YYrm5SAZ1PW9Do/vHG7D9jxWsLnB4Ho4kakyikP5DLLhODxXuTfpG21bCUNO0n490= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UjkpcVej; 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="UjkpcVej" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4A71C433C7; Wed, 13 Mar 2024 17:57:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352667; bh=el7fu9wQ+wCYZSmj8Df/MzRCK0qEMwnhbP3oOjYhriU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UjkpcVejTHtGyFY63tJeroN/SvzunTZcg3gO9gqcUVE3jIQ3ivMRwI+sxEysUNU95 7WCxli0N2QgYHcXE0XnyYiq4P0SMkQwDQKl1ACY9rVmLxpuVrEjLt+F0FV8LIAo/0p 1tBQS/eX6EGHXVfGK2uPKasu+6nbOqM6DClmNFQb3SgVGPKUAg+vPh/fE/0XbLGK4T 4lBkC6tnV8y3Dz/OZZrR1ymicsetvLFYCqf22hXzzsoK7jLqZ74mGe8MrYvM6KofzE WQHNtlsDxLcOGKBtnTihtFp5LooUdXxm5y3Kq0a+kKoqXq7OI8DEYD99CpGG3dNXsP EoVNonj07Wq7A== Date: Wed, 13 Mar 2024 10:57:47 -0700 Subject: [PATCH 20/29] xfs: widen flags argument to the xfs_iflags_* helpers From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223678.2613863.14018255073725223372.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:58:03 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: 13591756 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 A2CF14CE13; Wed, 13 Mar 2024 17:58: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=1710352683; cv=none; b=k7e3xuzEh40ixrEh32/TPKvdb7nn3WpjV73CLmiDf3ay+9xa7NDLkyTHiMSojS/CWZbLQmm5K43S7G7yL6Bz8HJ7SvaGdeEsh036qsBDjA8Im9bDeigZBJwBtK9VMOScAtg5H+2wQO/nZaXR0mreG1APOSWZe+14Vuwe7Gb4AIY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352683; c=relaxed/simple; bh=otBM5hpwR46eG0j/1XUqSqZWfYVJN3udcv1PxRmECuA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=V/0tlhiG9Jc5W7iFGJJfkyRQimKrn914A0Hsomb4eyPQVqtuC3GXa3dj8LTtIykS4xwkfEOjLtmkZJLY9Y5Z2bOiAc6RCH8LCheduxmaHDWVoDume0eIGy2Rpy0J8mvwmj1SXgsa6ASb3Efg7Ft60B1ZbLo732Cx/BinKdYEKVA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NKaWMnJJ; 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="NKaWMnJJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6EE46C433F1; Wed, 13 Mar 2024 17:58:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352683; bh=otBM5hpwR46eG0j/1XUqSqZWfYVJN3udcv1PxRmECuA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NKaWMnJJKSTjmm/tROxEN7BRW9QAZH7gUgEpIJLMPduM84YgMi/hYT++PEUTYPE8e hBkJL9eWZ0z5O/xMSXx9pW96XbabRWAtOSz2hRdGzGHix3HjHyPxYKcpF6KC5gE+ax k+23C4S4hziuLB9WIx8Kyo3Dbcpbd84aKHvkTy7XF95oqGtY0BnRF551WaSOp9t6Ul 6NYLH1+mTEbUNMohqvwSd9DroZZeYaRmGFCcF3aBPq2x0C7JS0XUtotlc9sA6DjNsl kpZ9xiZ5Tf1T9xSlzxN5Jf8PcHsEujpXwAe1V9uZZYC/Nhq3zTyUlF1ry8Q57lJDIU mt/ZwxvfvRc/A== Date: Wed, 13 Mar 2024 10:58:03 -0700 Subject: [PATCH 21/29] xfs: add fs-verity support From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223693.2613863.3986547716372413007.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 | 14 + fs/xfs/libxfs/xfs_ondisk.h | 3 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 | 477 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_verity.h | 20 ++ 10 files changed, 581 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..a3aea521b0d2 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_fsverity_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..bb04fde4a800 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -914,4 +914,18 @@ 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 offsets into merkle tree. + */ +struct xfs_fsverity_merkle_key { + __be64 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..64adc0a45644 100644 --- a/fs/xfs/libxfs/xfs_ondisk.h +++ b/fs/xfs/libxfs/xfs_ondisk.h @@ -194,6 +194,9 @@ 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 descriptor xattr name */ + 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..9f3bcc9150d2 --- /dev/null +++ b/fs/xfs/xfs_verity.c @@ -0,0 +1,477 @@ +/* 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; + + /* blob data, must be last! */ + unsigned char data[]; +}; + +/* Size of a merkle tree cache block */ +static inline size_t sizeof_xfs_merkle_blob(unsigned int blocksize) +{ + return struct_size_t(struct xfs_merkle_blob, data, blocksize); +} + +/* + * 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 = kvzalloc(sizeof_xfs_merkle_blob(blocksize), GFP_KERNEL); + if (!mk) + return NULL; + + /* Caller owns this refcount. */ + refcount_set(&mk->refcount, 1); + 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); +} + +/* 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 inline void +xfs_fsverity_merkle_key_to_disk( + struct xfs_fsverity_merkle_key *key, + u64 offset) +{ + key->merkleoff = cpu_to_be64(offset); +} + +static inline u64 +xfs_fsverity_merkle_key_from_disk( + void *attr_name) +{ + struct xfs_fsverity_merkle_key *key = attr_name; + + return be64_to_cpu(key->merkleoff); +} + +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_fsverity_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_fsverity_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_fsverity_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_fsverity_merkle_key name; + struct xfs_da_args args = { + .dp = ip, + .attr_filter = XFS_ATTR_VERITY, + .name = (const uint8_t *)&name, + .namelen = sizeof(struct xfs_fsverity_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_fsverity_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_fsverity_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); + } + + /* We might have loaded this in from disk, fsverity must recheck */ + fsverity_invalidate_block(req->inode, block); + +out_hit: + block->kaddr = (void *)mk->data; + block->context = mk; + return 0; + +out_new_mk: + xfs_merkle_blob_rele(new_mk); + return error; +} + +static int +xfs_verity_write_merkle( + struct inode *inode, + const void *buf, + u64 pos, + unsigned int size) +{ + struct xfs_inode *ip = XFS_I(inode); + struct xfs_fsverity_merkle_key name; + struct xfs_da_args args = { + .dp = ip, + .whichfork = XFS_ATTR_FORK, + .attr_filter = XFS_ATTR_VERITY, + .namelen = sizeof(struct xfs_fsverity_merkle_key), + .value = (void *)buf, + .valuelen = size, + }; + + xfs_fsverity_merkle_key_to_disk(&name, pos); + args.name = (const uint8_t *)&name.merkleoff; + + return xfs_attr_set(&args); +} + +static void +xfs_verity_drop_merkle( + struct fsverity_blockbuf *block) +{ + struct xfs_merkle_blob *mk = block->context; + + 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 Wed Mar 13 17:58: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: 13591757 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 315F659B63; Wed, 13 Mar 2024 17:58: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=1710352699; cv=none; b=N+i0LKBwn4Gs0Q1eibVVf3jgAwxaxKvR7kzes8UPBFlzvKjrpcnVLhLZI84Qqx9zn6515Hmd16LgECFkGRE15l45SbeA0YmUz71VXT5KzY2Xl0WMe2LmisW9ariCdZSOq2/BySG8OmfCpMYpsOs25Gp8ta5+duRVXSpQzyDCymo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352699; c=relaxed/simple; bh=9aNnEIVecuTEfZ9EOGAhAn3k+OtIpt0Q6d1/0iL//H0=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sqFcd6Y75Q5rh4d2YzSyAWKr6nOJ8rPMSXJSeEVAGq0c2Dsr/5OnnGq07ORWfihRIjvoMLtAcXbwTK2nEmozQuMNQyrIp70tv1NF8dxQhZOztXEffNkrAsKTW1KcTNIuh5uko/+yBGAGAPTK/Z49kW37eb3i92nFUM0IaYkyqec= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KH61lwNy; 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="KH61lwNy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0DB79C433F1; Wed, 13 Mar 2024 17:58:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352699; bh=9aNnEIVecuTEfZ9EOGAhAn3k+OtIpt0Q6d1/0iL//H0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=KH61lwNyzfAIYMle/RCbOX/DSB5i2ZR6TJlJ8Nf3kWx7Bk7869LjJnHwiI3UgpNvO PAqAek987egO9bGA7g/kKIoXOeXcrGTwecleO+N+xtfwULWZON3uAfjdrB0zntvzXk vic9SvCR+pCQSHs8PXtzaVy/HSnWKfsgGrQClIRTJ+OHLgYV0BVcHNZGEebQG0TcF+ Odq6OiHqaLKDauvfGnwSkmA4IxSsscsQmOYz5WCwj3Y4R+yTUGVc7Yt492f1SxyQRe jtHhxA+dcQ8dl+VjQ9m5mNDlPsjQDgKm/l731MPil+JHlCPcnqTdM//xOrOd0IK+Ny ZTprXzHaOXLgA== Date: Wed, 13 Mar 2024 10:58:18 -0700 Subject: [PATCH 22/29] xfs: create a per-mount shrinker for verity inodes merkle tree blocks From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223710.2613863.3703735595488208587.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 9f3bcc9150d2..25d10e00698b 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 /* @@ -217,6 +218,82 @@ xfs_fsverity_merkle_key_from_disk( return be64_to_cpu(key->merkleoff); } +/* 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 Wed Mar 13 17:58: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: 13591758 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 1770059B4D; Wed, 13 Mar 2024 17:58: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=1710352715; cv=none; b=rKZBF+Ba6fS0xAqtmj/xi3Bt6RBmLp9Xrs/WJJ/t3Sw7wZQZ2Nsc/48PfTlw1FWr/enfdaxkRpt6Gb09M26+7XnzsNHsc3WkIdV9RQCiML4Q3iAi5ZHgdEN3YzUg0fJ/y7CAqM4wj0dQ1TaTmmallJBSLTWLImR0lns6ALeSsQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352715; c=relaxed/simple; bh=T5hhQLQ+6RvBs6vxLwsCHoMD6JXynzk5glvZrMbA04k=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PHiDp4xewrAN+cntK9jSpdGvM2T/zrq4fgdRw4bWdvwubPQXQ9mwhJoCMy4io4QcjcqlzryI4MEYmTrEgtY9VAH6T2+yl8Vekp9czdOls5ouLb4xfnmysy1om2KQuokLN5AvI4OtZYbn/TP3BCHdsKJVmeyhCmwJFPrX3Q9U6L0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HdINZqkG; 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="HdINZqkG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A1272C433C7; Wed, 13 Mar 2024 17:58:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352714; bh=T5hhQLQ+6RvBs6vxLwsCHoMD6JXynzk5glvZrMbA04k=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=HdINZqkGimy6+cXYl+Wc3+I2RHbBvhvHIVagDZYV1GC1g9EDPrng8VYF+Vsat4rpN AIBqd6ySC37NugudUD6M3ZanNGgc2AwseMVG6EDIKOFj/5jbgHzLtKAIQ/IW5OaNtt MllZvarxcxJoHoExH+eDii+Cfk6hUUjyRLtRrwn2/cx8jMqajVOIhFTaoaVnKe3rx1 +g5Yj2EKtFYnqtRp5lUuifTj5YBhrpX4DVwW37xp0GwZSFuVhGda2JDqtM2O8hVkC/ KdjtVyXkrcb6bVp+LOLKFIUm+ytoDGvr0VpaTupNX35JQPi/vNr0wYijPtqdODLfyl PfUawYmzGX3KQ== Date: Wed, 13 Mar 2024 10:58:34 -0700 Subject: [PATCH 23/29] xfs: create an icache tag for files with cached merkle tree blocks From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223726.2613863.11814486602875673946.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 25d10e00698b..5d698383ed21 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -236,18 +236,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 Wed Mar 13 17:58: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: 13591759 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 B08584D135; Wed, 13 Mar 2024 17:58: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=1710352730; cv=none; b=trvbXlBu03ABDQC+NE8g8Z6l5mtij9szwSeq2hn6McXqLVCZStiAmP5AIVc2W+TOKDa1YldXdmCok/g6+OlUlLnoKyyUls+lXpxm2UIVrPevjGuhdj65I3Z+XS4/AkAUnZ5CErLSfI99MuLFbu0jZV+eVyoaUhvwqG4LvgnloY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352730; c=relaxed/simple; bh=DPAgxv3Q4uy9579uRuOaPirjLjDerwFfZUZuJEme2wU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dCwBERRn4pcq95G33k0KXNPjkogfQAdrF5oA/7tycl+129dl7OyK97+kYZJv8kjG9k7jqFAVMGyCv0F5WFr2/mm1CzUZWGSUk017OSa7svJS0LG05yXE4bJqhF1jrLliCh9091iqTGZB2PZsFZXexvZPUbGxKpL/0yn6FUu32/s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fgmwVkFu; 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="fgmwVkFu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48D67C433F1; Wed, 13 Mar 2024 17:58:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352730; bh=DPAgxv3Q4uy9579uRuOaPirjLjDerwFfZUZuJEme2wU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=fgmwVkFu2aZK/Goijdzlg7qFfTIm96tn+sxO9YZmhdZB5ebLgxm5uZQn10xN1N6f2 +mqPUa6aPhS4lLrHYivf9KaGOEmpJmXkHL+ExThJJmTsDsDrNTiWctlGw4GoA68I7C 0HITK6iuA2GjB+Y6J6wBbp7stmTwtMDMxTnQu3xe2sv9WKMdX0Px7lfXIIuDb16ZLB uK2z1ZNPTU7qzUpINYHrzX0z4Vw+ztcIAPvCIOECzFWGWvhPyVNBWr9sp/U9Fsp0v6 /dPsnyZ/mT853j7H+OTum5ow2OjkHslpqlLyXjzRmNSOeyidkuveyVqvbxpvHx7k5L Nc34MM4Ze31Cw== Date: Wed, 13 Mar 2024 10:58:49 -0700 Subject: [PATCH 24/29] xfs: shrink verity blob cache From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223742.2613863.15483199528192039477.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 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 5d698383ed21..bb4ca8716c34 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; + /* blob data, must be last! */ unsigned char data[]; }; @@ -97,8 +100,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) { @@ -106,10 +111,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 */ @@ -168,6 +176,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; @@ -182,6 +191,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) { @@ -244,12 +255,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; } @@ -522,6 +594,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); } /* We might have loaded this in from disk, fsverity must recheck */ @@ -530,6 +609,13 @@ xfs_verity_read_merkle( out_hit: block->kaddr = (void *)mk->data; block->context = mk; + + /* + * 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 Wed Mar 13 17:59: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: 13591760 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 0EA4D5A103; Wed, 13 Mar 2024 17:59: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=1710352746; cv=none; b=C6hqtUJ0D3e0ZzpBWhhso/meVx/XqlU1iUrriqbdMoml+99ppd5hWqJ1lPVj0qxP7afc41+2EUjP0xcVI2MUm6STw3ynzXgqfoOXanXqksNzkP73KqDJ6DytBMHQZi4W3w8RAahTvWA3taps+1Ncp9xrY+FYTDwb3yyDHcXMJdM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352746; c=relaxed/simple; bh=494y+3iuQlrODS2eWZyrS+vexwRjyUKAwpufvVwqiUw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=plTPVRj7FxhG00dxii3M2bEwLl2qMQMxl6IbBjiVWbVWboTOM0OAN63R04Bn9XWoTp3E/LIZP9LLIzX80pEPDFwTjrxxqOxvfo3Agooag/n/A0iq0/FLOSl1EwvivOQrSi751h7RnkuV1zfgfyJbeWplbbDgCxTg4t9c68N1JIo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZuiBDpvm; 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="ZuiBDpvm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB632C43390; Wed, 13 Mar 2024 17:59:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352745; bh=494y+3iuQlrODS2eWZyrS+vexwRjyUKAwpufvVwqiUw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZuiBDpvmBbndX8saE6/Vtv4H7ePrc7lZ/QtozgOMSbDT3yKBxHuzYKGhpe50IVR/V r88K7EPiEAiqUdpacXtpWeqBpHjWDliKL4J038LtMRUHuqZ6pOlb2rXqxqH3rM2blN ArGYYJ1twnZ0U21qcGXd9v3pJhDOcU8xso+obqwaqp3FI/v+UzMZh4mNsCB5rGFEGF kzJn6+KhA+eWXhzkI1FrMYzd2QE0tA+GXVmxxhxDlvtHRT9JuZ3A6ZdOtcy19NqOMd PFBmFKZYi8s1IZx0dQRkS5kXJ6K/huIAXHLz1q9UGyTeWCttMQsnk9oZ/BFzN5CAJD MoVsJ1WatydYw== Date: Wed, 13 Mar 2024 10:59:05 -0700 Subject: [PATCH 25/29] xfs: clean up stale fsverity metadata before starting From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223758.2613863.14784213448726046229.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 --- 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 bb4ca8716c34..cfa50534bfc4 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -422,6 +422,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_fsverity_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_fsverity_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_fsverity_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, @@ -430,7 +468,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); @@ -440,7 +477,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 Wed Mar 13 17:59: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: 13591761 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 115764D135; Wed, 13 Mar 2024 17:59: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=1710352762; cv=none; b=cbkC9kNKI3suv5voo5OMFhUSn5Uy8tCmbJ8hkEoOuc+c1HSdacldDUmEYqTruWhCiq7MWLogecDEeRuCexSM6AS4k++L6ZAZIGlwx+4T/hKx34tboaK2ItTUTcTOS8RF24y/q6ztR9TSkaKi20XV9DPsS7TrgNAQsufi29w2bTI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352762; c=relaxed/simple; bh=dZH6mab6ory8PxMFPpIIz5eqeCK/0qXhs2JYxBc+knc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qFPe+vlBcd/d8Cwz4Yh2dJ3vImPznMxXAGtR3iRBtY8Qz3VtddA+NkNnba+ucDGwjXWZWcBhqJyss0yDhQJsjdf8xnHuy+XnPwYwHAo7xgzGcCxJ+qgdrT7Ami6EzLdRSTmJSMUr1PsaXbkrx9cY4K1clLY7HePNays2N0H4nD4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=l2BhzbXA; 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="l2BhzbXA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B909C433F1; Wed, 13 Mar 2024 17:59:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352761; bh=dZH6mab6ory8PxMFPpIIz5eqeCK/0qXhs2JYxBc+knc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=l2BhzbXAOSaKjbIzL2WynuZSP6EEIDMOJvkjtm39pY60n7XUTW5dvRaZ+7Z61iox/ u7AGobpLy+1GLgxaiHcTAhsw5NiqZp7G7bnS5IoUXG+QfGrTOCusKHr5FGg/+1/xj2 4yV1PDjZLSreaD8gKjux6yWnaE349TyaRemwTRuzEuGR4BDVKPVH9WTm4+q95mhfPo 2pvVzBYnllTQRw8Q8xOlrBWWupQmvzhvBNIawmGetqcMRBivnmN51iQmMohT1OPEJ6 UUaxtdS+YF2IJd4C7bt8hc6ydaxBnoxxooKPnBtbtvot4Sd+Wsy1GWc2p61K4AsrJ+ ES2vtZo5Byzlw== Date: Wed, 13 Mar 2024 10:59:21 -0700 Subject: [PATCH 26/29] xfs: better reporting and error handling in xfs_drop_merkle_tree From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223773.2613863.987001035342644557.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 --- 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 cfa50534bfc4..3dcc2af084fc 100644 --- a/fs/xfs/xfs_verity.c +++ b/fs/xfs/xfs_verity.c @@ -481,15 +481,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_fsverity_merkle_key name; - int error = 0; - u64 offset = 0; struct xfs_da_args args = { .dp = ip, .whichfork = XFS_ATTR_FORK, @@ -500,6 +499,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; @@ -507,6 +508,8 @@ xfs_drop_merkle_tree( for (offset = 0; offset < merkle_tree_size; offset += tree_blocksize) { xfs_fsverity_merkle_key_to_disk(&name, offset); error = xfs_attr_set(&args); + if (error == -ENOATTR) + error = 0; if (error) return error; } @@ -514,7 +517,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; } @@ -573,9 +577,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 Wed Mar 13 17:59: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: 13591762 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 BDE415A0F2; Wed, 13 Mar 2024 17:59: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=1710352777; cv=none; b=XS1R5Bmv4OCUTquVa0txGn8IdkOYVUATnFzi61Gz6Uf+uI6wiYgQ9rv5EqRiOsZkT9G5+0gLeJdDclrJEN1TZKsLa6xMvp8XGhwOBZiyk+xUgDPzy7dJbasRFMWyjNiRu0mBetZqoX/RkX/vw4mBHZT25aCNnnvg3+s1MV2mero= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352777; c=relaxed/simple; bh=PJf7MhulP7KKfLxtmjzccQbLC0uIEQngYqJwN54SY7Q=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VTthoBAS6A/3yfKjWKXAAWr5cgR9hBuMtXG9h8IGdfhmzZ2K6mviWegaYyUUzSxk5UMoD3vqCmiAVrgUdx1FGg/A2rffMnx/dlNxUQ73JAfAiJTB4GtlW/kNLk6a4vGOm62V5uxF3KaSvXUtGItALo3c0hTRCc0EGpZzaHDIuPA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HqHVl3k0; 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="HqHVl3k0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3335AC433C7; Wed, 13 Mar 2024 17:59:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352777; bh=PJf7MhulP7KKfLxtmjzccQbLC0uIEQngYqJwN54SY7Q=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=HqHVl3k0XwBOmrE9c+hyoBNAkXospKmHXOpb+RZ+N6ZiZaLla0tUn4JD9sAO5nhuw 3tUPJAujQpqkH8/QDyekEdZeakeiOw8wrSpzDutX/CV3+9R6iM1WOOWdPwHR3IF0cr Fzk/gz9JQ1IIFS+Qd896iX+/lQz6Tq5h8lBmGbz6iwzb6IcF9UyBd8aMDnzKJwsuBr Kipk2MG35eFyQatyg35cZWCeSH8pbGkqfuQMVCakP3oeuxlqo+Bll4GvbOM901jBWA w/xXq0ATnAmZ6c+nTI5B2SR0kFKA0W2fvC1RvBBejE8KIuAYzC9h02kU0O0HjXC4yy PgmfA6k6B+aNQ== Date: Wed, 13 Mar 2024 10:59:36 -0700 Subject: [PATCH 27/29] xfs: make scrub aware of verity dinode flag From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223789.2613863.9923257124399937228.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 Wed Mar 13 17:59: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: 13591763 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 4C47D5A784; Wed, 13 Mar 2024 17:59:52 +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=1710352793; cv=none; b=M9RxFycrOTcmCGouzIWelarSVUE1cLvbAiGQDpntzlx6DIYh0VANJR5IbT0bGLJtJFKoLG/eYJGkndmAgd4y4XK3NoY9cmCEvqJ797DHL+2V73tE2Y/U94ziuCqejBB0tUU0DCeT54VAIhRv17+ET7hJJmMYl/GqHJm/fQsyfM8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352793; c=relaxed/simple; bh=K25MtlZeHCUYvDWQdXo11USD++UAUl09pmm3BMqm2Cg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=UcYu816v2FiYbSKhvShRcdSY6CgASiyOs4NgqAKlQY+AKj7KXTBbhu8A+AcU1Dr1tIQsowhEaUjhcRlOisjs8qR2n/C6dH1Q5dT1Exxn6Vj2WGZEwxGAXUSzSkIpjImcFKpWmwp9M7oYky0rvh0iwhtL2j0PoCDayzj6zGnxM0o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DJiS9H3s; 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="DJiS9H3s" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C79DAC433C7; Wed, 13 Mar 2024 17:59:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352792; bh=K25MtlZeHCUYvDWQdXo11USD++UAUl09pmm3BMqm2Cg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=DJiS9H3sj/24lE4B1J1XLpKU18ZAaZTar2LC3Fa2VNwbzm8vKYwEMyuum5/NVrvZL 8kjQl4lOHz6nwcOG8oZOmy0Tm0evKGrDRBL/5F6X8nLEOoe3GuPHt6+Kz0YCmz2dGt LxocLY8NFrNZnHO3PMeW5u7jcqTSIokPP/G2+BmTcUxXXcbUHVZAP0UALAgzJvindX JwvnJfSXjXgXo7TRS+xZXViQJ8jBO9S8/Y1mVG4Fg12UZfxlHf88GG09XmAk8Qbj1k dWFNsbDgfx72bMaNutNGuCfWszeythhRBEeXlF0ev0yt157m/67FjTQiSoj5pjNaYQ lJ5hYqIzLVlug== Date: Wed, 13 Mar 2024 10:59:52 -0700 Subject: [PATCH 28/29] xfs: add fs-verity ioctls From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223804.2613863.13648555925178352663.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index ab61d7d552fb..4763d20c05ff 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,22 @@ xfs_file_ioctl( return error; } + case FS_IOC_ENABLE_VERITY: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_enable(filp, (const void __user *)arg); + + case FS_IOC_MEASURE_VERITY: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_measure(filp, (void __user *)arg); + + case FS_IOC_READ_VERITY_METADATA: + if (!xfs_has_verity(mp)) + return -EOPNOTSUPP; + return fsverity_ioctl_read_metadata(filp, + (const void __user *)arg); + default: return -ENOTTY; } From patchwork Wed Mar 13 18:00:07 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: 13591764 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 C7AE55A4EF; Wed, 13 Mar 2024 18:00: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=1710352808; cv=none; b=eBlRFJnsVwl99KX2fXd1sSpCOzJ1XeaFAQELsBJ70PEQsQ2A2sKLq9vgxmaXguX2jDU+5lri520oFmP9v7ysmqr0lJNofqrQOhd4tPMGIJRwOl+5m3UpJQDM5GhJDajUkVvbJjLIOHcAgHwMLeTCeEuxzi97UyfqQNCTLMbQyMA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710352808; 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=QrtbfWiMhkrGWcl5ZteUF1t6v+iGw9v6Of740V9lCHi2ddgdC6K8mTJ+GEX2nCqYTpoIcvIdN52EyA20kk+GsxGK2gJM+5/vrzrWwdtgVXJjiicEcPCdgPM70CxNAfy5bcJpQGcpFxD6yjR+BraJRBne2fgOeMiDj55IAzcY8C4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=s/sJp5pD; 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="s/sJp5pD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 56646C433C7; Wed, 13 Mar 2024 18:00:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710352808; bh=gyY/eII/mzWjplxkissoGLEmgFRPREJ2adLdk/vMBuU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=s/sJp5pDwOwOAvK8aUNmsjpJmMf7KOZAS2PQHVuw84hfqkvIbJ0x+gI+hlpEDoeiA CRIIKYC7a3rbSTg8wEChY/9RYIkomjoiuBbbedXt3w4MQeD0NqSaJj7GTdrWMU1Qw1 gSIY/N/zZwX7m5uqX2Oye17Pxu8GF1LLPU2/VAbP1/WAzj4/CGPQErOT9pcGyBpqya 3c5MD/OiTaLOItWgMnVmB/lIheGrscd3xntB45vUThxf8q/NdW+MrmiLBHHmqQiE90 UlF256YbwWFhAl7JsNEsrI4ksFVr7UCg9Td/GGTArv8ANfEyPLW2I7ItMjKk+inBlJ GXiilD29e9WqQ== Date: Wed, 13 Mar 2024 11:00:07 -0700 Subject: [PATCH 29/29] xfs: enable ro-compat fs-verity flag From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@redhat.com, ebiggers@kernel.org Cc: linux-fsdevel@vger.kernel.org, fsverity@lists.linux.dev, linux-xfs@vger.kernel.org Message-ID: <171035223820.2613863.11590371205606569859.stgit@frogsfrogsfrogs> In-Reply-To: <171035223299.2613863.12196197862413309469.stgit@frogsfrogsfrogs> References: <171035223299.2613863.12196197862413309469.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(