Skip to contentSkip to conversation

ext4: refuse encryption when block size > page size

PATCH In review Alberto Garcia 4 participants 9 messages Sep 25 – Oct 24

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover ext4: refuse encryption when block size > page size

Hi,

encryption is not supported when a filesystem's block size is larger than the page size. Although the kernel refuses to mount such a filesystem if the "encrypt" feature is already set, it is possible to enable it on a mounted filesystem with e.g. tune2fs.

# mkfs.ext4 -b 16384 /dev/vdb
# mount /dev/vdb /mnt/
# tune2fs -O encrypt /dev/vdb
# mkdir /mnt/foo
# fscrypt setup /mnt
# fscrypt encrypt /mnt/foo/
# head -c 20M /dev/urandom > /mnt/foo/data
# sync
[  116.014221] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 130040)
[  116.014235] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)
[  116.014241] Buffer I/O error on device vdb, logical block 130040
[...]
[  116.014264] Buffer I/O error on device vdb, logical block 130049
[  116.015505] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 66552)
[  116.015520] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)
[  116.016451] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 65784)
[  116.016459] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)

This affects all kernels starting from v6.19 up to v7.3-rc4.

Note that this still allows encrypted inodes even when the 'encrypt' feature is missing as long as block size <= page size. With v1 encryption policies they can be used normally.

There's an additional bug that only affects kernels between v6.19 and v7.2 (but not v7.3), which will be dealt with separately.

Regards,

Berto

Alberto Garcia (2):
ext4: refuse encryption when block size > page size
ext4: reject encrypted inodes when block size > page size

 fs/ext4/crypto.c | 9 +++++++++
 fs/ext4/inode.c  | 6 ++++++
 2 files changed, 15 insertions(+)
Signature · 1 line
2.47.3
#1 lore raw

PATCH 1/2 ext4: refuse encryption when block size > page size

Encryption is not supported when a filesystem's block size is larger than the page size, and commit 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS") added a check to refuse mounting such a filesystem.

However, it is also possible to enable the "encrypt" feature on a filesystem that is already mounted (with tune2fs -O encrypt). Once that happens it won't be possible to mount the filesystem again in the future, but there is nothing preventing the user from setting an encryption policy while the filesystem is still mounted.

Fix this by refusing to set an fscrypt context in ext4_set_context() when the block size is larger than the page size.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+
---
 fs/ext4/crypto.c | 9 +++++++++
 1 file changed, 9 insertions(+)
fs/ext4/crypto.c +9 -0
index 1a0fccb084ef..318b2eaea741 100644
@@ -156,6 +156,15 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
 	if (ext4_test_inode_flag(inode, EXT4_INODE_DAX))
 		return -EOPNOTSUPP;
 
+	/*
+	 * Encryption is not supported when the block size is larger
+	 * than the page size.  This is rejected at mount time by
+	 * ext4_check_large_folio(), and this check here is for the case
+	 * when the 'encrypt' feature is enabled on a mounted filesystem.
+	 */
+	if (inode->i_sb->s_blocksize > PAGE_SIZE)
+		return -EOPNOTSUPP;
+
 	res = ext4_convert_inline_data(inode);
 	if (res)
 		return res;
Signature · 1 line
2.47.3
#2 lore raw
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 11 lines

Encryption is not supported when a filesystem's block size is larger than the page size, and commit 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS") added a check to refuse mounting such a filesystem.

However, it is also possible to enable the "encrypt" feature on a filesystem that is already mounted (with tune2fs -O encrypt). Once that happens it won't be possible to mount the filesystem again in the future, but there is nothing preventing the user from setting an encryption policy while the filesystem is still mounted.

Quoted 6 lines

Fix this by refusing to set an fscrypt context in ext4_set_context() when the block size is larger than the page size.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+

Sashiko has reviewed this patch and found no issues. It looks great!

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
reviewer Reviewed-by on v1 1/2
#3 lore raw
In reply to Alberto Garcia
Quoted 11 lines · Alberto Garcia

Encryption is not supported when a filesystem's block size is larger than the page size, and commit 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS") added a check to refuse mounting such a filesystem.

However, it is also possible to enable the "encrypt" feature on a filesystem that is already mounted (with tune2fs -O encrypt). Once that happens it won't be possible to mount the filesystem again in the future, but there is nothing preventing the user from setting an encryption policy while the filesystem is still mounted.

Quoted 6 lines

Fix this by refusing to set an fscrypt context in ext4_set_context() when the block size is larger than the page size.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+

Thanks for the patch, feel free to add:

Quoted 24 lines
---
 fs/ext4/crypto.c | 9 +++++++++
 1 file changed, 9 insertions(+)
fs/ext4/crypto.c +9 -0
index 1a0fccb084ef..318b2eaea741 100644
@@ -156,6 +156,15 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
 	if (ext4_test_inode_flag(inode, EXT4_INODE_DAX))
 		return -EOPNOTSUPP;
 
+	/*
+	 * Encryption is not supported when the block size is larger
+	 * than the page size.  This is rejected at mount time by
+	 * ext4_check_large_folio(), and this check here is for the case
+	 * when the 'encrypt' feature is enabled on a mounted filesystem.
+	 */
+	if (inode->i_sb->s_blocksize > PAGE_SIZE)
+		return -EOPNOTSUPP;
+
 	res = ext4_convert_inline_data(inode);
 	if (res)
 		return res;
#4 lore raw

PATCH 2/2 ext4: reject encrypted inodes when block size > page size

In reply to Alberto Garcia

Encryption is not supported when a filesystem's block size is larger than the page size. ext4_check_large_folio() refuses to mount a filesystem like that if the "encrypt" feature is already enabled, and ext4_set_context() refuses to create encrypted inodes if the feature is enabled after mounting.

However, a corrupted or hand-crafted filesystem can still have encrypted inodes even if the "encrypt" feature is not set, and those inodes can be unlocked if they're using v1 policies.

Check this in __ext4_iget() and reject them as corrupted.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+
---
 fs/ext4/inode.c | 6 ++++++
 1 file changed, 6 insertions(+)
fs/ext4/inode.c +6 -0
index 26f0f9714f03..31248fef8bce 100644
@@ -5671,6 +5671,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
 		ret = -EFSCORRUPTED;
 		goto bad_inode;
 	}
+	if (IS_ENCRYPTED(inode) && sb->s_blocksize > PAGE_SIZE) {
+		ext4_error_inode(inode, function, line, 0,
+				 "encrypted inode with block size larger than page size");
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
 
 	ext4_set_inode_mapping_order(inode);
 
Signature · 1 line
2.47.3
#5 lore raw

Re: [PATCH 2/2] ext4: reject encrypted inodes when block size > page size

Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines

Encryption is not supported when a filesystem's block size is larger than the page size. ext4_check_large_folio() refuses to mount a filesystem like that if the "encrypt" feature is already enabled, and ext4_set_context() refuses to create encrypted inodes if the feature is enabled after mounting.

However, a corrupted or hand-crafted filesystem can still have encrypted inodes even if the "encrypt" feature is not set, and those inodes can be unlocked if they're using v1 policies.

Quoted 6 lines

Check this in __ext4_iget() and reject them as corrupted.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+

Sashiko has reviewed this patch and found no issues. It looks great!

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
reviewer Reviewed-by on v1 2/2
#6 lore raw

Re: [PATCH 2/2] ext4: reject encrypted inodes when block size > page size

In reply to Alberto Garcia
Quoted 10 lines · Alberto Garcia

Encryption is not supported when a filesystem's block size is larger than the page size. ext4_check_large_folio() refuses to mount a filesystem like that if the "encrypt" feature is already enabled, and ext4_set_context() refuses to create encrypted inodes if the feature is enabled after mounting.

However, a corrupted or hand-crafted filesystem can still have encrypted inodes even if the "encrypt" feature is not set, and those inodes can be unlocked if they're using v1 policies.

Quoted 6 lines

Check this in __ext4_iget() and reject them as corrupted.

Fixes 709f0f1f1bf5 ("ext4: add checks for large folio incompatibilities when BS > PS")
Cc [email protected] # v6.19+

Looks good, feel free to add:

Quoted 21 lines
---
 fs/ext4/inode.c | 6 ++++++
 1 file changed, 6 insertions(+)
fs/ext4/inode.c +6 -0
index 26f0f9714f03..31248fef8bce 100644
@@ -5671,6 +5671,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
 		ret = -EFSCORRUPTED;
 		goto bad_inode;
 	}
+	if (IS_ENCRYPTED(inode) && sb->s_blocksize > PAGE_SIZE) {
+		ext4_error_inode(inode, function, line, 0,
+				 "encrypted inode with block size larger than page size");
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
 
 	ext4_set_inode_mapping_order(inode);
 
maintainer Reviewed-by on the v1 series
#7 lore raw
In reply to Alberto Garcia
Quoted 38 lines · Alberto Garcia

Hi,

encryption is not supported when a filesystem's block size is larger than the page size. Although the kernel refuses to mount such a filesystem if the "encrypt" feature is already set, it is possible to enable it on a mounted filesystem with e.g. tune2fs.

# mkfs.ext4 -b 16384 /dev/vdb
# mount /dev/vdb /mnt/
# tune2fs -O encrypt /dev/vdb
# mkdir /mnt/foo
# fscrypt setup /mnt
# fscrypt encrypt /mnt/foo/
# head -c 20M /dev/urandom > /mnt/foo/data
# sync
[  116.014221] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 130040)
[  116.014235] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)
[  116.014241] Buffer I/O error on device vdb, logical block 130040
[...]
[  116.014264] Buffer I/O error on device vdb, logical block 130049
[  116.015505] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 66552)
[  116.015520] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)
[  116.016451] EXT4-fs warning (device vdb): ext4_end_bio:360: I/O error 19 writing to inode 19 starting block 65784)
[  116.016459] EXT4-fs (vdb): failed to convert unwritten extents to written extents -- potential data loss!  (inode 19, error -5)

This affects all kernels starting from v6.19 up to v7.3-rc4.

Note that this still allows encrypted inodes even when the 'encrypt' feature is missing as long as block size <= page size. With v1 encryption policies they can be used normally.

There's an additional bug that only affects kernels between v6.19 and v7.2 (but not v7.3), which will be dealt with separately.

Regards,

Berto

Quoted 7 lines

Alberto Garcia (2):
ext4: refuse encryption when block size > page size
ext4: reject encrypted inodes when block size > page size

 fs/ext4/crypto.c | 9 +++++++++
 fs/ext4/inode.c  | 6 ++++++
 2 files changed, 15 insertions(+)

- Eric