Skip to contentSkip to conversation

ext4: oops in ext4_finish_bio() after enabling encryption on a mounted fs

REGRESSION Alberto Garcia 5 participants 15 messages Sep 23 – Sep 29 ext4 file system

lore
Share & tools
lore
#0 lore raw

Hi,

I'd like to report a bug in the ext4 code. I confirm that it happens with the latest stable kernel (7.2.7), but mainline (7.3-rc4) does not seem to be affected.

The problem is very easy to reproduce:

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt
2) Create an empty directory and encrypt it (fscrypt encrypt /foo or whatever).
3) Write some data to it (head -c head -c 10M /dev/urandom > /foo/file.bin)
4) sync

[   42.962615] BUG: kernel NULL pointer dereference, address: 0000000000000028
[   42.965440] #PF: supervisor read access in kernel mode
[   42.967480] #PF: error_code(0x0000) - not-present page
[   42.969475] PGD 0 P4D 0 
[   42.970460] Oops: Oops: 0000 [#1] SMP NOPTI
[   42.972141] CPU: 0 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 7.2.7-vanilla #2 PREEMPT(lazy) 
[   42.975502] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   42.977650] Workqueue: ext4-rsv-conversion ext4_end_io_rsv_work
[   42.978499] RIP: 0010:ext4_finish_bio+0xf8/0x400
[   42.979452] Code: 38 00 00 00 00 48 8b 44 24 08 4c 01 f8 48 89 04 24 48 83 7b 18 00 0f 84 d7 02 00 00 41 0f b6 7d 1a 40 84 ff 0f 85 7d 02 00 00 <4c> 8b 63 28 45 31 f6 49 8d 44 24 5c 48 89 c7 48 89 44 24 20 e8 6f
[   42.982351] RSP: 0018:ffffd0290006bd40 EFLAGS: 00010246
[   42.983090] RAX: 0000000000001000 RBX: 0000000000000000 RCX: 000fffffc0000201
[   42.984204] RDX: fffff64a40226f00 RSI: fffff64a400afcc0 RDI: 0000000000000000
[   42.985203] RBP: 0000000000001000 R08: 0000000000001000 R09: ffffffff8a49cb8a
[   42.986203] R10: 0000000000001fff R11: ffff8b4f81926200 R12: ffff8b4f8521b540
[   42.987213] R13: ffff8b4f81927f00 R14: 0000000000000001 R15: 0000000000000000
[   42.988351] FS:  0000000000000000(0000) GS:ffff8b507105e000(0000) knlGS:0000000000000000
[   42.989478] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   42.990292] CR2: 0000000000000028 CR3: 000000000bcb9000 CR4: 0000000000350ef0
[   42.991291] Call Trace:
[   42.991709]  <TASK>
[   42.992042]  ext4_release_io_end+0x55/0x120
[   42.992650]  ext4_end_io_end+0x4c/0xe0
[   42.993194]  ext4_end_io_rsv_work+0xaa/0x100
[   42.993807]  process_one_work+0x19e/0x370
[   42.994382]  worker_thread+0x1a6/0x310
[   42.994925]  ? __pfx_worker_thread+0x10/0x10
[   42.995806]  kthread+0xe4/0x120
[   42.996313]  ? __pfx_kthread+0x10/0x10
[   42.996856]  ret_from_fork+0x2b1/0x340
[   42.997397]  ? __pfx_kthread+0x10/0x10
[   42.997941]  ret_from_fork_asm+0x1a/0x30
[   42.998505]  </TASK>

The problem does not happen if you unmount the filesystem after setting the encryption feature, and then mount it again.

The cause seems to be that encryption does not support large folios, but after commit 709f0f1f1bf5c ("ext4: add checks for large folio incompatibilities when BS > PS") this is only checked at mount time, so enabling encryption on a mounted fs bypasses this check.

This solves the crash for me, but I suppose that it also needs an additional check to decide whether encryption can be enabled on a filesystem (i.e. if sb->s_blocksize > PAGE_SIZE).

fs/ext4/inode.c +2 -1
@@ -5287,7 +5287,8 @@ void ext4_set_inode_mapping_order(struct inode *inode)
 	if (!min_order && !S_ISREG(inode->i_mode))
 		return;
 
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) ||
+	    ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT))
 		max_order = min_order;
 
 	mapping_set_folio_order_range(inode->i_mapping, min_order, max_order);

Regards,

Berto

#1 lore raw
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 13 lines

Hi,

I'd like to report a bug in the ext4 code. I confirm that it happens with the latest stable kernel (7.2.7), but mainline (7.3-rc4) does not seem to be affected.

The problem is very easy to reproduce:

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt
2) Create an empty directory and encrypt it (fscrypt encrypt /foo or whatever).
3) Write some data to it (head -c head -c 10M /dev/urandom > /foo/file.bin)
4) sync

Quoted 8 lines
[   42.962615] BUG: kernel NULL pointer dereference, address: 0000000000000028
[   42.965440] #PF: supervisor read access in kernel mode

[ ... ]
mapping_set_folio_order_range(inode->i_mapping, min_order, max_order);

Regards,

Berto

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
#2 lore raw
In reply to Alberto Garcia
Quoted 9 lines · Alberto Garcia

Hi,

I'd like to report a bug in the ext4 code. I confirm that it happens with the latest stable kernel (7.2.7), but mainline (7.3-rc4) does not seem to be affected.

The problem is very easy to reproduce:

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt

Is it valid to enable encrypt at mount time?

Regards,
Baokun

Quoted 66 lines

2) Create an empty directory and encrypt it (fscrypt encrypt /foo or whatever).
3) Write some data to it (head -c head -c 10M /dev/urandom > /foo/file.bin)
4) sync

[   42.962615] BUG: kernel NULL pointer dereference, address: 0000000000000028
[   42.965440] #PF: supervisor read access in kernel mode
[   42.967480] #PF: error_code(0x0000) - not-present page
[   42.969475] PGD 0 P4D 0 
[   42.970460] Oops: Oops: 0000 [#1] SMP NOPTI
[   42.972141] CPU: 0 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 7.2.7-vanilla #2 PREEMPT(lazy) 
[   42.975502] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   42.977650] Workqueue: ext4-rsv-conversion ext4_end_io_rsv_work
[   42.978499] RIP: 0010:ext4_finish_bio+0xf8/0x400
[   42.979452] Code: 38 00 00 00 00 48 8b 44 24 08 4c 01 f8 48 89 04 24 48 83 7b 18 00 0f 84 d7 02 00 00 41 0f b6 7d 1a 40 84 ff 0f 85 7d 02 00 00 <4c> 8b 63 28 45 31 f6 49 8d 44 24 5c 48 89 c7 48 89 44 24 20 e8 6f
[   42.982351] RSP: 0018:ffffd0290006bd40 EFLAGS: 00010246
[   42.983090] RAX: 0000000000001000 RBX: 0000000000000000 RCX: 000fffffc0000201
[   42.984204] RDX: fffff64a40226f00 RSI: fffff64a400afcc0 RDI: 0000000000000000
[   42.985203] RBP: 0000000000001000 R08: 0000000000001000 R09: ffffffff8a49cb8a
[   42.986203] R10: 0000000000001fff R11: ffff8b4f81926200 R12: ffff8b4f8521b540
[   42.987213] R13: ffff8b4f81927f00 R14: 0000000000000001 R15: 0000000000000000
[   42.988351] FS:  0000000000000000(0000) GS:ffff8b507105e000(0000) knlGS:0000000000000000
[   42.989478] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   42.990292] CR2: 0000000000000028 CR3: 000000000bcb9000 CR4: 0000000000350ef0
[   42.991291] Call Trace:
[   42.991709]  <TASK>
[   42.992042]  ext4_release_io_end+0x55/0x120
[   42.992650]  ext4_end_io_end+0x4c/0xe0
[   42.993194]  ext4_end_io_rsv_work+0xaa/0x100
[   42.993807]  process_one_work+0x19e/0x370
[   42.994382]  worker_thread+0x1a6/0x310
[   42.994925]  ? __pfx_worker_thread+0x10/0x10
[   42.995806]  kthread+0xe4/0x120
[   42.996313]  ? __pfx_kthread+0x10/0x10
[   42.996856]  ret_from_fork+0x2b1/0x340
[   42.997397]  ? __pfx_kthread+0x10/0x10
[   42.997941]  ret_from_fork_asm+0x1a/0x30
[   42.998505]  </TASK>

The problem does not happen if you unmount the filesystem after setting the encryption feature, and then mount it again.

The cause seems to be that encryption does not support large folios, but after commit 709f0f1f1bf5c ("ext4: add checks for large folio incompatibilities when BS > PS") this is only checked at mount time, so enabling encryption on a mounted fs bypasses this check.

This solves the crash for me, but I suppose that it also needs an additional check to decide whether encryption can be enabled on a filesystem (i.e. if sb->s_blocksize > PAGE_SIZE).

fs/ext4/inode.c +2 -1
@@ -5287,7 +5287,8 @@ void ext4_set_inode_mapping_order(struct inode *inode)
 	if (!min_order && !S_ISREG(inode->i_mode))
 		return;
 
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) ||
+	    ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT))
 		max_order = min_order;
 
 	mapping_set_folio_order_range(inode->i_mapping, min_order, max_order);

Regards,

Berto

reviewer
#4 lore raw
Quoted 9 lines · Alberto Garcia
Quoted 2 lines · Baokun Li
Quoted 1 line

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt

Is it valid to enable encrypt at mount time?

Good question, I always understood that it was allowed and tune2fs certainly doesn't forbid it (compare with casefold):

https://github.com/tytso/e2fsprogs/blob/v1.47.4/misc/tune2fs.c#L1599

Berto

If enabling encryption on a mounted ext4 fs is allowed, I think the current change is fine.

Ted, Eric - would either of you know the details here?

Regards,
Baokun

#5 lore raw
Quoted 9 lines · Baokun Li
Quoted 8 lines · Alberto Garcia
Quoted 2 lines · Baokun Li
Quoted 1 line

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt

Is it valid to enable encrypt at mount time?

Good question, I always understood that it was allowed and tune2fs certainly doesn't forbid it (compare with casefold):

https://github.com/tytso/e2fsprogs/blob/v1.47.4/misc/tune2fs.c#L1599

Quoted 7 lines
Quoted 1 line

Berto

If enabling encryption on a mounted ext4 fs is allowed, I think the current change is fine.

Ted, Eric - would either of you know the details here?

Yes, it is allowed.

The proposed patch looks good, even though the problem seems to be gone on mainline already due to the removal of the code path that used the non-large-folio-compatible function fscrypt_encrypt_pagecache_blocks().

There can be another patch that removes both that check and the mount-time check, if they're truly no longer needed (I don't know of any reason why they would be, but it needs to be properly tested).

- Eric

reviewer
#6 lore raw
Quoted 15 lines · Eric Biggers
Quoted 14 lines · Baokun Li
Quoted 9 lines · Alberto Garcia
Quoted 2 lines · Baokun Li
Quoted 1 line

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt

Is it valid to enable encrypt at mount time?

Good question, I always understood that it was allowed and tune2fs certainly doesn't forbid it (compare with casefold):

https://github.com/tytso/e2fsprogs/blob/v1.47.4/misc/tune2fs.c#L1599

Berto

If enabling encryption on a mounted ext4 fs is allowed, I think the current change is fine.

Quoted 6 lines
Quoted 1 line

Ted, Eric - would either of you know the details here?

Yes, it is allowed.

The proposed patch looks good, even though the problem seems to be gone on mainline already due to the removal of the code path that used the non-large-folio-compatible function fscrypt_encrypt_pagecache_blocks().

Agreed, then this current modification can be made into a separate bugfix for backporting to stable.

Quoted 4 lines

There can be another patch that removes both that check and the mount-time check, if they're truly no longer needed (I don't know of any reason why they would be, but it needs to be properly tested).

After removing both checks, I ran

    kvm-xfstests -c ext4/32k -g encrypt

16 of the 29 tests still fail.  blk-crypto-fallback still en/decrypts one page at a time, while the data unit size is 32k with a block size larger than the page size.  It doesn't crash, but the writes fail with BLK_STS_INVAL, so write() succeeds while the data never reaches the disk, and reads fail once the page cache is dropped.

Supporting data units larger than a page is simple enough.  A rough implementation of mine already gives 30%~50% higher buffered I/O throughput with 32k blocks than with 4k blocks.  The patches are still being polished, and I'll send them out in the next two days.

Thanks,
Baokun

#7 lore raw
In reply to Eric Biggers
Quoted 1 line · Eric Biggers

The proposed patch looks good

As I said, I think we need an additional check to detect if encryption is set on a mounted filesystem that has blocksize > pagesize.

Such a filesystem cannot be mounted (ext4_check_large_folio refuses), but if you do it after the fs is mounted you can crash the kernel using the same method.

# mkfs.ext4 -b 16384 /dev/vdb 
# mount /dev/vdb /mnt/
# fscrypt setup /mnt
# tune2fs -O encrypt /dev/vdb 
# mkdir /mnt/foo
# fscrypt encrypt /mnt/foo/

The other patch alone does not prevent this.

With this additional change, FS_IOC_SET_ENCRYPTION_POLICY returns -EOPNOTSUPP, so tune2fs succeeds, but 'fscrypt encrypt' fails:

[ERROR] fscrypt encrypt: encryption not enabled on filesystem /mnt (/dev/vdb).

fs/ext4/crypto.c +3 -0
@@ -156,6 +156,9 @@ 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;
 
+	if (inode->i_sb->s_blocksize > PAGE_SIZE)
+		return -EOPNOTSUPP;
+
 	res = ext4_convert_inline_data(inode);
 	if (res)
 		return res;

That prevents the crash, but the filesystem cannot be remounted:

kernel: EXT4-fs (vdb): bs(16384) > ps(4096) unsupported for encrypt

Would this be enough or is there anything else to take into account?

Regards,

Berto

#8 lore raw
Quoted 37 lines · Alberto Garcia
Quoted 1 line · Eric Biggers

The proposed patch looks good

As I said, I think we need an additional check to detect if encryption is set on a mounted filesystem that has blocksize > pagesize.

Such a filesystem cannot be mounted (ext4_check_large_folio refuses), but if you do it after the fs is mounted you can crash the kernel using the same method.

# mkfs.ext4 -b 16384 /dev/vdb 
# mount /dev/vdb /mnt/
# fscrypt setup /mnt
# tune2fs -O encrypt /dev/vdb 
# mkdir /mnt/foo
# fscrypt encrypt /mnt/foo/

The other patch alone does not prevent this.

With this additional change, FS_IOC_SET_ENCRYPTION_POLICY returns

(quoted diff) +0 -1
-EOPNOTSUPP, so tune2fs succeeds, but 'fscrypt encrypt' fails:
 
   [ERROR] fscrypt encrypt: encryption not enabled on filesystem /mnt (/dev/vdb).
fs/ext4/crypto.c +3 -0
@@ -156,6 +156,9 @@ 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;
 
+	if (inode->i_sb->s_blocksize > PAGE_SIZE)
+		return -EOPNOTSUPP;
+
 	res = ext4_convert_inline_data(inode);
 	if (res)
 		return res;
Quoted 5 lines

That prevents the crash, but the filesystem cannot be remounted:

   kernel: EXT4-fs (vdb): bs(16384) > ps(4096) unsupported for encrypt

Would this be enough or is there anything else to take into account?

Right, encryption should work with large folios now, but not with fs_block_size > PAGE_SIZE. For the latter, for now I think we need a few different things to prevent it:

* (Already present) A mount-time check, to prevent mounting when the encrypt feature flag is set and fs_block_size > PAGE_SIZE;

* A check in ext4_set_context(), as you suggested, to prevent new encrypted files from being created when fs_block_size > PAGE_SIZE after the encrypt feature flag was set at runtime;

* tune2fs should disallow setting the encrypt feature flag in the first place when fs_block_size > PAGE_SIZE;

* And maybe a check in __ext4_iget() to prevent existing encrypted inodes from being loaded when fs_block_size > PAGE_SIZE. This would be needed for fuzzing robustness, where a fuzzer generates a filesystem that has encrypted files without the encrypt feature flag. (I don't remember whether ext4 claims to support this level of fuzzing robustness, though. __ext4_iget() has a few similar checks for other filesystem features, but it's very incomplete, so I'm not sure.)

- Eric

#9 lore raw
Quoted 4 lines · Eric Biggers

* And maybe a check in __ext4_iget() to prevent existing encrypted inodes from being loaded when fs_block_size > PAGE_SIZE. This would be needed for fuzzing robustness, where a fuzzer generates a filesystem that has encrypted files without the encrypt feature flag.

Does the kernel reject encrypted files on a fs without the encrypt flag? I'm asking in general, regardless of the block size. Should it?

Berto

#10 lore raw
Quoted 8 lines · Alberto Garcia
Quoted 4 lines · Eric Biggers

* And maybe a check in __ext4_iget() to prevent existing encrypted inodes from being loaded when fs_block_size > PAGE_SIZE. This would be needed for fuzzing robustness, where a fuzzer generates a filesystem that has encrypted files without the encrypt feature flag.

Does the kernel reject encrypted files on a fs without the encrypt flag? I'm asking in general, regardless of the block size. Should it?

On a filesystem without the encrypt flag, ext4 rejects creating new encrypted directories, but it doesn't reject accessing existing encrypted directories.

It *should* reject accessing existing encrypted directories. I think the fact that it doesn't is a holdout from the bug that ext4 originally had where it didn't enforce the encrypt feature flag at all.

ext4 encryption was first supported in Linux v4.1. ext4 incorrectly allowed creating new encrypted directories on filesystems without the encrypt feature flag until commit 9a200d075e5 ("ext4: require encryption feature for EXT4_IOC_SET_ENCRYPTION_POLICY") in Linux v4.9. ext4 also allowed the FS_IOC_GET_ENCRYPTION_POLICY ioctl on filesystems without the encrypt feature flag until commit 0642ea2409f3bf ("ext4 crypto: fix to check feature status before get policy") in Linux v5.4.

Since v5.4 (7 years ago), ext4 has enforced ext4_has_feature_encrypt(sb) for all encryption ioctls.

I think at this point would be pretty safe for ext4_iget() to reject any encrypted inodes when the filesystem doesn't have the encrypt flag. The only caveat is that, technically, if an existing encrypted directory is using the old policy version (which before v5.4 was the only option), it can be unlocked and accessed without executing any of the encryption ioctls. So in theory someone could be depending on that on a filesystem without the encrypt flag. I think it's unlikely at this point, though.

(Android for example certainly isn't depending on that, since I updated it to use 'tune2fs -O encrypt' many years ago. Also, its keyctl() based unlocking code was removed and only the ioctls are used now.)

So I would suggest we just fix this as well.

- Eric

#11 lore raw
Quoted 11 lines · Eric Biggers

On a filesystem without the encrypt flag, ext4 rejects creating new encrypted directories, but it doesn't reject accessing existing encrypted directories.

It *should* reject accessing existing encrypted directories. [...] The only caveat is that, technically, if an existing encrypted directory is using the old policy version (which before v5.4 was the only option), it can be unlocked and accessed without executing any of the encryption ioctls. So in theory someone could be depending on that on a filesystem without the encrypt flag. I think it's unlikely at this point, though.

One problem that I see is that e2fsck does not seem to detect such filesystems. Wouldn't it make sense to fix it there first? (I suppose by setting the encrypt feature if an encrypted inode is found)

Berto

reviewer
#12 lore raw
Quoted 13 lines · Alberto Garcia
Quoted 11 lines · Eric Biggers

On a filesystem without the encrypt flag, ext4 rejects creating new encrypted directories, but it doesn't reject accessing existing encrypted directories.

It *should* reject accessing existing encrypted directories. [...] The only caveat is that, technically, if an existing encrypted directory is using the old policy version (which before v5.4 was the only option), it can be unlocked and accessed without executing any of the encryption ioctls. So in theory someone could be depending on that on a filesystem without the encrypt flag. I think it's unlikely at this point, though.

Quoted 3 lines

One problem that I see is that e2fsck does not seem to detect such filesystems. Wouldn't it make sense to fix it there first? (I suppose by setting the encrypt feature if an encrypted inode is found)

Yes, that sounds like a worthwhile thing to do to me.

Honza

Signature · 2 lines
Jan Kara <[email protected]>
SUSE Labs, CR
reviewer
#13 lore raw
In reply to Alberto Garcia

Hi!

Quoted 3 lines · Alberto Garcia

I'd like to report a bug in the ext4 code. I confirm that it happens with the latest stable kernel (7.2.7), but mainline (7.3-rc4) does not seem to be affected.

Hum, so 709f0f1f1bf5c was merged to 6.19. So did you have a look what has fixed the problem in 7.3-rc4? Because I'm not aware of any ext4 change that should fix this.

Honza

Quoted 70 lines

The problem is very easy to reproduce:

1) Enable encryption on an ext4 filesystem with tune2fs -O encrypt
2) Create an empty directory and encrypt it (fscrypt encrypt /foo or whatever).
3) Write some data to it (head -c head -c 10M /dev/urandom > /foo/file.bin)
4) sync

[   42.962615] BUG: kernel NULL pointer dereference, address: 0000000000000028
[   42.965440] #PF: supervisor read access in kernel mode
[   42.967480] #PF: error_code(0x0000) - not-present page
[   42.969475] PGD 0 P4D 0 
[   42.970460] Oops: Oops: 0000 [#1] SMP NOPTI
[   42.972141] CPU: 0 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 7.2.7-vanilla #2 PREEMPT(lazy) 
[   42.975502] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   42.977650] Workqueue: ext4-rsv-conversion ext4_end_io_rsv_work
[   42.978499] RIP: 0010:ext4_finish_bio+0xf8/0x400
[   42.979452] Code: 38 00 00 00 00 48 8b 44 24 08 4c 01 f8 48 89 04 24 48 83 7b 18 00 0f 84 d7 02 00 00 41 0f b6 7d 1a 40 84 ff 0f 85 7d 02 00 00 <4c> 8b 63 28 45 31 f6 49 8d 44 24 5c 48 89 c7 48 89 44 24 20 e8 6f
[   42.982351] RSP: 0018:ffffd0290006bd40 EFLAGS: 00010246
[   42.983090] RAX: 0000000000001000 RBX: 0000000000000000 RCX: 000fffffc0000201
[   42.984204] RDX: fffff64a40226f00 RSI: fffff64a400afcc0 RDI: 0000000000000000
[   42.985203] RBP: 0000000000001000 R08: 0000000000001000 R09: ffffffff8a49cb8a
[   42.986203] R10: 0000000000001fff R11: ffff8b4f81926200 R12: ffff8b4f8521b540
[   42.987213] R13: ffff8b4f81927f00 R14: 0000000000000001 R15: 0000000000000000
[   42.988351] FS:  0000000000000000(0000) GS:ffff8b507105e000(0000) knlGS:0000000000000000
[   42.989478] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   42.990292] CR2: 0000000000000028 CR3: 000000000bcb9000 CR4: 0000000000350ef0
[   42.991291] Call Trace:
[   42.991709]  <TASK>
[   42.992042]  ext4_release_io_end+0x55/0x120
[   42.992650]  ext4_end_io_end+0x4c/0xe0
[   42.993194]  ext4_end_io_rsv_work+0xaa/0x100
[   42.993807]  process_one_work+0x19e/0x370
[   42.994382]  worker_thread+0x1a6/0x310
[   42.994925]  ? __pfx_worker_thread+0x10/0x10
[   42.995806]  kthread+0xe4/0x120
[   42.996313]  ? __pfx_kthread+0x10/0x10
[   42.996856]  ret_from_fork+0x2b1/0x340
[   42.997397]  ? __pfx_kthread+0x10/0x10
[   42.997941]  ret_from_fork_asm+0x1a/0x30
[   42.998505]  </TASK>

The problem does not happen if you unmount the filesystem after setting the encryption feature, and then mount it again.

The cause seems to be that encryption does not support large folios, but after commit 709f0f1f1bf5c ("ext4: add checks for large folio incompatibilities when BS > PS") this is only checked at mount time, so enabling encryption on a mounted fs bypasses this check.

This solves the crash for me, but I suppose that it also needs an additional check to decide whether encryption can be enabled on a filesystem (i.e. if sb->s_blocksize > PAGE_SIZE).

fs/ext4/inode.c +2 -1
@@ -5287,7 +5287,8 @@ void ext4_set_inode_mapping_order(struct inode *inode)
 	if (!min_order && !S_ISREG(inode->i_mode))
 		return;
 
-	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+	if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) ||
+	    ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT))
 		max_order = min_order;
 
 	mapping_set_folio_order_range(inode->i_mapping, min_order, max_order);

Regards,

Berto

Signature · 2 lines
Jan Kara <[email protected]>
SUSE Labs, CR
#14 lore raw
Quoted 7 lines · Jan Kara
Quoted 3 lines

I'd like to report a bug in the ext4 code. I confirm that it happens with the latest stable kernel (7.2.7), but mainline (7.3-rc4) does not seem to be affected.

Hum, so 709f0f1f1bf5c was merged to 6.19. So did you have a look what has fixed the problem in 7.3-rc4? Because I'm not aware of any ext4 change that should fix this.

I suspect it is this ("the original filesystem-layer file contents encryption implementation is removed, and the blk-crypto implementation is now used unconditionally"):

https://lore.kernel.org/linux-ext4/20260817173311.GB8327@quark/

Berto