diff mbox series

[27/29] xfs: make it possible to disable fsverity

Message ID 171175869006.1988170.17755870506078239341.stgit@frogsfrogsfrogs (mailing list archive)
State New
Headers show
Series [01/29] xfs: use unsigned ints for non-negative quantities in xfs_attr_remote.c | expand

Commit Message

Darrick J. Wong March 30, 2024, 12:43 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Create an experimental ioctl so that we can turn off fsverity.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_fs_staging.h |    3 ++
 fs/xfs/xfs_fsverity.c          |   73 ++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_fsverity.h          |    3 ++
 fs/xfs/xfs_ioctl.c             |    6 +++
 4 files changed, 85 insertions(+)

Comments

Andrey Albershteyn April 2, 2024, 5:15 p.m. UTC | #1
On 2024-03-29 17:43:06, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> Create an experimental ioctl so that we can turn off fsverity.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> ---
>  fs/xfs/libxfs/xfs_fs_staging.h |    3 ++
>  fs/xfs/xfs_fsverity.c          |   73 ++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_fsverity.h          |    3 ++
>  fs/xfs/xfs_ioctl.c             |    6 +++
>  4 files changed, 85 insertions(+)
> 
> 

Looks good to me:
Reviewed-by: Andrey Albershteyn <aalbersh@redhat.com>
Eric Biggers April 2, 2024, 11:25 p.m. UTC | #2
On Fri, Mar 29, 2024 at 05:43:06PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> Create an experimental ioctl so that we can turn off fsverity.

The concept of "experimental ioctls" seems problematic.  What if people start
relying on them?  Linux tends not to have "experimental" system calls, and
probably for good reason...

Also, what is the use case for this ioctl?  Is it necessary to have this when
userspace can already just replace a verity file with a copy that has verity
disabled?  That's less efficient, but it does not require any kernel support and
does not require CAP_SYS_ADMIN.

And of course, if do we add this ioctl it shouldn't be XFS-specific.

- Eric
Darrick J. Wong April 3, 2024, 1:26 a.m. UTC | #3
On Tue, Apr 02, 2024 at 04:25:10PM -0700, Eric Biggers wrote:
> On Fri, Mar 29, 2024 at 05:43:06PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > Create an experimental ioctl so that we can turn off fsverity.
> 
> The concept of "experimental ioctls" seems problematic.  What if people start
> relying on them?  Linux tends not to have "experimental" system calls, and
> probably for good reason...

They're trapped in my enormous backlog of patches.  They get this
special treatment so that I can show them to developers without anyone
getting any fancy ideas about merging them.  Once I get close enough to
actually consider merging it, I'll move it out from under EXPERIMENTAL.

IOWs: I'm not planning to push xfs_fs_staging.h itself to upstream ever.

> Also, what is the use case for this ioctl?  Is it necessary to have this when
> userspace can already just replace a verity file with a copy that has verity
> disabled?  That's less efficient, but it does not require any kernel support and
> does not require CAP_SYS_ADMIN.

No, of course it isn't needed if replacing the file is easy.  That
however assumes that replacing /is/ easy.

The use case for this is: "I enabled fsverity on my backup volume so I
could detect bitrot, then the primary disk died, and when I went to
restore the primary, I got a verity error."

Being able to read known-bad corrupted contents are less bad than losing
the entire file or having to do surgery with xfs_db to turn off
fsverity.

Just for my own convenience, this would enable me to try out fsverity in
a few places while being able to undo it quickly if <cough> we end up
changing the ondisk format during review.

> And of course, if do we add this ioctl it shouldn't be XFS-specific.

Yes, this is a proof of concept.  I'd lift it to fs/verity/ if you
accept the premise.

--D

> - Eric
>
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_fs_staging.h b/fs/xfs/libxfs/xfs_fs_staging.h
index 899a56a569d50..4c29167a2b190 100644
--- a/fs/xfs/libxfs/xfs_fs_staging.h
+++ b/fs/xfs/libxfs/xfs_fs_staging.h
@@ -229,4 +229,7 @@  struct xfs_map_freesp {
  */
 #define XFS_IOC_MAP_FREESP	_IOWR('X', 64, struct xfs_map_freesp)
 
+/* Turn off fs-verity */
+#define FS_IOC_DISABLE_VERITY	_IO('f', 133)
+
 #endif /* __XFS_FS_STAGING_H__ */
diff --git a/fs/xfs/xfs_fsverity.c b/fs/xfs/xfs_fsverity.c
index bfa5c70beec24..f57d8acbd858a 100644
--- a/fs/xfs/xfs_fsverity.c
+++ b/fs/xfs/xfs_fsverity.c
@@ -792,3 +792,76 @@  const struct fsverity_operations xfs_fsverity_ops = {
 	.drop_merkle_tree_block		= xfs_fsverity_drop_merkle,
 	.fail_validation		= xfs_fsverity_fail_validation,
 };
+
+/* Turn off fs-verity. */
+int
+xfs_fsverity_disable(
+	struct file		*file)
+{
+	struct inode		*inode = file_inode(file);
+	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_trans	*tp;
+	u64			merkle_tree_size;
+	unsigned int		merkle_blocksize;
+	int			error;
+
+	BUILD_BUG_ON(FS_IOC_DISABLE_VERITY == FS_IOC_ENABLE_VERITY);
+
+	if (!xfs_has_verity(mp))
+		return -EOPNOTSUPP;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+	if (!IS_VERITY(inode)) {
+		error = 0;
+		goto out_iolock;
+	}
+
+	if (xfs_iflags_test(ip, XFS_VERITY_CONSTRUCTION)) {
+		error = -EBUSY;
+		goto out_iolock;
+	}
+
+	error = xfs_qm_dqattach(ip);
+	if (error)
+		goto out_iolock;
+
+	error = fsverity_merkle_tree_geometry(inode, &merkle_blocksize,
+			&merkle_tree_size);
+	if (error)
+		goto out_iolock;
+
+	xfs_fsverity_cache_drop(ip);
+
+	/* Clear fsverity inode flag */
+	error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange, 0, 0, false,
+			&tp);
+	if (error)
+		goto out_iolock;
+
+	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)
+		goto out_iolock;
+
+	inode->i_flags &= ~S_VERITY;
+	fsverity_cleanup_inode(inode);
+
+	/* Remove the fsverity xattrs. */
+	error = xfs_fsverity_delete_metadata(ip, merkle_tree_size,
+			merkle_blocksize);
+	if (error)
+		goto out_iolock;
+
+out_iolock:
+	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+	return error;
+}
diff --git a/fs/xfs/xfs_fsverity.h b/fs/xfs/xfs_fsverity.h
index 21ba0d82f26d8..4b9fff6b0d2c4 100644
--- a/fs/xfs/xfs_fsverity.h
+++ b/fs/xfs/xfs_fsverity.h
@@ -17,6 +17,8 @@  struct xfs_icwalk;
 int xfs_fsverity_scan_inode(struct xfs_inode *ip, struct xfs_icwalk *icw);
 
 extern const struct fsverity_operations xfs_fsverity_ops;
+
+int xfs_fsverity_disable(struct file *file);
 #else
 # define xfs_fsverity_cache_init(ip)		((void)0)
 # define xfs_fsverity_cache_drop(ip)		((void)0)
@@ -24,6 +26,7 @@  extern const struct fsverity_operations xfs_fsverity_ops;
 # define xfs_fsverity_register_shrinker(mp)	(0)
 # define xfs_fsverity_unregister_shrinker(mp)	((void)0)
 # define xfs_fsverity_scan_inode(ip, icw)	(0)
+# define xfs_fsverity_disable(ip)			(-EOPNOTSUPP)
 #endif	/* CONFIG_FS_VERITY */
 
 #endif	/* __XFS_FSVERITY_H__ */
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 0aa0ceb9ec153..24deaaf5eb0f5 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -44,6 +44,7 @@ 
 #include "xfs_file.h"
 #include "xfs_exchrange.h"
 #include "xfs_rtgroup.h"
+#include "xfs_fsverity.h"
 
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -2712,6 +2713,11 @@  xfs_file_ioctl(
 	case XFS_IOC_MAP_FREESP:
 		return xfs_ioc_map_freesp(filp, arg);
 
+#ifdef CONFIG_XFS_EXPERIMENTAL_IOCTLS
+	case FS_IOC_DISABLE_VERITY:
+		return xfs_fsverity_disable(filp);
+#endif
+
 	case FS_IOC_ENABLE_VERITY:
 		if (!xfs_has_verity(mp))
 			return -EOPNOTSUPP;