All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ext4: fix EXT4_IOC_SWAP_BOOT
@ 2018-10-02 23:38 Theodore Ts'o
  2018-10-03 12:55 ` Christoph Hellwig
  0 siblings, 1 reply; 3+ messages in thread
From: Theodore Ts'o @ 2018-10-02 23:38 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o, stable

The code EXT4_IOC_SWAP_BOOT ioctl hasn't been updated in a while, and
it's a bit broken with respect to more modern ext4 kernels, especially
metadata checksums.

Other problems fixed with this commit:

* Don't allow installing a DAX, swap file, or an encrypted file as a
  boot loader.

* Respect the immutable and append-only flags.

* Wait until any DIO operations are finished *before* calling
  truncate_inode_pages().

* Don't swap inode->i_flags, since these flags have nothing to do with
  the inode blocks --- and it will give the IMA/audit code heartburn
  when the inode is evicted.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
Reported-by: syzbot+e81ccd4744c6c4f71354@syzkaller.appspotmail.com
---
 fs/ext4/ioctl.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index a7074115d6f6..d7ed7487e630 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -67,7 +67,6 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
 	ei1 = EXT4_I(inode1);
 	ei2 = EXT4_I(inode2);
 
-	swap(inode1->i_flags, inode2->i_flags);
 	swap(inode1->i_version, inode2->i_version);
 	swap(inode1->i_blocks, inode2->i_blocks);
 	swap(inode1->i_bytes, inode2->i_bytes);
@@ -85,6 +84,21 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
 	i_size_write(inode2, isize);
 }
 
+static void reset_inode_seed(struct inode *inode)
+{
+	struct ext4_inode_info *ei = EXT4_I(inode);
+	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+	__le32 inum = cpu_to_le32(inode->i_ino);
+	__le32 gen = cpu_to_le32(inode->i_generation);
+	__u32 csum;
+
+	if (!ext4_has_metadata_csum(inode->i_sb))
+		return;
+
+	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, sizeof(inum));
+	ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, sizeof(gen));
+}
+
 /**
  * Swap the information from the given @inode and the inode
  * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
@@ -102,10 +116,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
 	struct inode *inode_bl;
 	struct ext4_inode_info *ei_bl;
 
-	if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode))
+	if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) ||
+	    IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) ||
+	    ext4_has_inline_data(inode))
 		return -EINVAL;
 
-	if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
+	if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) ||
+	    !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
@@ -120,13 +137,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
 	 * that only 1 swap_inode_boot_loader is running. */
 	lock_two_nondirectories(inode, inode_bl);
 
-	truncate_inode_pages(&inode->i_data, 0);
-	truncate_inode_pages(&inode_bl->i_data, 0);
-
 	/* Wait for all existing dio workers */
 	inode_dio_wait(inode);
 	inode_dio_wait(inode_bl);
 
+	truncate_inode_pages(&inode->i_data, 0);
+	truncate_inode_pages(&inode_bl->i_data, 0);
+
 	handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
 	if (IS_ERR(handle)) {
 		err = -EINVAL;
@@ -159,6 +176,8 @@ static long swap_inode_boot_loader(struct super_block *sb,
 
 	inode->i_generation = prandom_u32();
 	inode_bl->i_generation = prandom_u32();
+	reset_inode_seed(inode);
+	reset_inode_seed(inode_bl);
 
 	ext4_discard_preallocations(inode);
 
@@ -169,6 +188,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
 			inode->i_ino, err);
 		/* Revert all changes: */
 		swap_inode_data(inode, inode_bl);
+		ext4_mark_inode_dirty(handle, inode);
 	} else {
 		err = ext4_mark_inode_dirty(handle, inode_bl);
 		if (err < 0) {
@@ -178,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
 			/* Revert all changes: */
 			swap_inode_data(inode, inode_bl);
 			ext4_mark_inode_dirty(handle, inode);
+			ext4_mark_inode_dirty(handle, inode_bl);
 		}
 	}
 	ext4_journal_stop(handle);
-- 
2.18.0.rc0

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] ext4: fix EXT4_IOC_SWAP_BOOT
  2018-10-02 23:38 [PATCH] ext4: fix EXT4_IOC_SWAP_BOOT Theodore Ts'o
@ 2018-10-03 12:55 ` Christoph Hellwig
  2018-10-03 14:54   ` Theodore Y. Ts'o
  0 siblings, 1 reply; 3+ messages in thread
From: Christoph Hellwig @ 2018-10-03 12:55 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Ext4 Developers List, stable

On Tue, Oct 02, 2018 at 07:38:08PM -0400, Theodore Ts'o wrote:
> The code EXT4_IOC_SWAP_BOOT ioctl hasn't been updated in a while, and
> it's a bit broken with respect to more modern ext4 kernels, especially
> metadata checksums.

Do you have any reports of anyone but sysbot actually using it?
Maybe it is a better idea to drop it unless it also gets coverage
in xfstests?

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] ext4: fix EXT4_IOC_SWAP_BOOT
  2018-10-03 12:55 ` Christoph Hellwig
@ 2018-10-03 14:54   ` Theodore Y. Ts'o
  0 siblings, 0 replies; 3+ messages in thread
From: Theodore Y. Ts'o @ 2018-10-03 14:54 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Ext4 Developers List

On Wed, Oct 03, 2018 at 05:55:20AM -0700, Christoph Hellwig wrote:
> On Tue, Oct 02, 2018 at 07:38:08PM -0400, Theodore Ts'o wrote:
> > The code EXT4_IOC_SWAP_BOOT ioctl hasn't been updated in a while, and
> > it's a bit broken with respect to more modern ext4 kernels, especially
> > metadata checksums.
> 
> Do you have any reports of anyone but sysbot actually using it?
> Maybe it is a better idea to drop it unless it also gets coverage
> in xfstests?

Adding xfstests coverage is on my todo list.  I need to clean up an
ext4-ioc.c test program so it can be added to xfstests/src, but yes, I
noticed that the lack of test coverage is what led to the code
bitrot.

There was recent discussion that perhaps Grub should use this instead
of chasing file system format changes (which was the original
intention of this patch) so I had been examining the code path looking
for potential problems anyway.  So I'd rather not drop it for now.

This will allow us to future-proof ext4 in case we ever grow support
for reflink (which I understand from Darrick has been an issue for
XFS :-).

						- Ted

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-10-03 21:42 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-02 23:38 [PATCH] ext4: fix EXT4_IOC_SWAP_BOOT Theodore Ts'o
2018-10-03 12:55 ` Christoph Hellwig
2018-10-03 14:54   ` Theodore Y. Ts'o

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.