From: Greg Kroah-Hartman Date: Wed, 15 Jul 2026 10:20:00 +0000 (+0200) Subject: 7.1-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba19cd1be528cc994ae8a624d23568469fe3c9f0;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: block-partitions-fix-of_node-refcount-leak-in-of_partition.patch btrfs-check-and-set-extent_delalloc_new-before-clearing-extent_delalloc.patch btrfs-do-not-trim-a-device-which-is-not-writeable.patch btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch crypto-af_alg-remove-zero-copy-support-from-skcipher-and-aead.patch crypto-atmel-sha204a-drop-hwrng-quality-reduction-for-atsha204a.patch crypto-atmel-sha204a-fail-on-hwrng-registration-error-in-probe-path.patch crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps-again.patch crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps.patch crypto-ccp-do-not-initialize-snp-for-ioctl-snp_commit.patch crypto-ccp-do-not-initialize-snp-for-ioctl-snp_config.patch crypto-ccp-do-not-initialize-snp-for-ioctl-snp_vlek_load.patch crypto-ccp-do-not-initialize-snp-for-sev-ioctls.patch crypto-chacha20poly1305-validate-poly1305-template-argument.patch crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch crypto-drbg-fix-drbg_max_addtl-on-64-bit-kernels.patch crypto-drbg-fix-ineffective-sanity-check.patch crypto-drbg-fix-misaligned-writes-in-ctr_drbg-and-hash_drbg.patch crypto-drbg-fix-returning-success-on-failure-in-ctr_drbg.patch crypto-drbg-fix-the-fips_enabled-priority-boost.patch crypto-ecc-fix-carry-overflow-in-vli-multiplication.patch crypto-hisi-trng-remove-crypto_rng-interface.patch crypto-loongson-remove-broken-and-unused-loongson-rng.patch crypto-loongson-select-crypto_rng.patch crypto-pcrypt-restore-callback-for-non-parallel-fallback.patch crypto-tegra-fix-refcount-leak-in-tegra_se_host1x_submit.patch dm-ioctl-report-an-error-if-a-device-has-no-table.patch hwrng-jh7110-fix-refcount-leak-in-starfive_trng_read.patch isofs-bound-rock-ridge-symlink-components-to-the-sl-record.patch nvme-multipath-set-bio_remapped-on-bios-remapped-to-per-path-namespace-disks.patch nvme-target-rdma-fix-ndev-refcount-leak-on-queue-connect.patch nvmet-auth-validate-reply-message-payload-bounds-against-transfer-length.patch nvmet-fix-pre-auth-out-of-bounds-heap-read-in-discovery-get-log-page.patch partitions-aix-bound-the-pp_count-scan-to-the-ppe-array.patch udf-validate-free-block-extents-against-the-partition-length.patch udf-validate-sparing-table-length-as-an-entry-count-not-a-byte-count.patch udf-validate-vat-header-length-against-the-vat-inode-size.patch --- diff --git a/queue-7.1/block-partitions-fix-of_node-refcount-leak-in-of_partition.patch b/queue-7.1/block-partitions-fix-of_node-refcount-leak-in-of_partition.patch new file mode 100644 index 0000000000..7bcdacb2d1 --- /dev/null +++ b/queue-7.1/block-partitions-fix-of_node-refcount-leak-in-of_partition.patch @@ -0,0 +1,54 @@ +From 148cd4873115feb266c002d4d4618ea7f14342d9 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Tue, 26 May 2026 10:21:24 +0000 +Subject: block: partitions: fix of_node refcount leak in of_partition() + +From: Wentao Liang + +commit 148cd4873115feb266c002d4d4618ea7f14342d9 upstream. + +of_partition() calls of_node_get() on the parent device node at the +beginning of the function, storing the reference in 'partitions_np'. +This reference is leaked in two paths: + +1. The compatibility check at the top of the function returns 0 + without releasing partitions_np when the node exists but is not + "fixed-partitions" compatible. + +2. The function returns 1 at the end after successfully processing + all partitions without releasing partitions_np. + +Fix both leaks by adding of_node_put(partitions_np) on each path. + +Fixes: 2e3a191e89f9 ("block: add support for partition table defined in OF") +Cc: stable@vger.kernel.org +Signed-off-by: Wentao Liang +Reviewed-by: Md Haris Iqbal +Link: https://patch.msgid.link/20260526102124.2283846-1-vulab@iscas.ac.cn +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/partitions/of.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/block/partitions/of.c ++++ b/block/partitions/of.c +@@ -74,8 +74,10 @@ int of_partition(struct parsed_partition + struct device_node *partitions_np = of_node_get(ddev->of_node); + + if (!partitions_np || +- !of_device_is_compatible(partitions_np, "fixed-partitions")) ++ !of_device_is_compatible(partitions_np, "fixed-partitions")) { ++ of_node_put(partitions_np); + return 0; ++ } + + slot = 1; + /* Validate parition offset and size */ +@@ -104,5 +106,6 @@ int of_partition(struct parsed_partition + + seq_buf_puts(&state->pp_buf, "\n"); + ++ of_node_put(partitions_np); + return 1; + } diff --git a/queue-7.1/btrfs-check-and-set-extent_delalloc_new-before-clearing-extent_delalloc.patch b/queue-7.1/btrfs-check-and-set-extent_delalloc_new-before-clearing-extent_delalloc.patch new file mode 100644 index 0000000000..f8f6c2d953 --- /dev/null +++ b/queue-7.1/btrfs-check-and-set-extent_delalloc_new-before-clearing-extent_delalloc.patch @@ -0,0 +1,265 @@ +From 95ee2231896d5f2a31760411429075a99d6045a7 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Mon, 20 Apr 2026 18:32:49 +0930 +Subject: btrfs: check and set EXTENT_DELALLOC_NEW before clearing EXTENT_DELALLOC + +From: Qu Wenruo + +commit 95ee2231896d5f2a31760411429075a99d6045a7 upstream. + +[WARNING] +When running test cases with injected errors or shutdown, e.g. +generic/388 or generic/475, there is a chance that the following kernel +warning is triggered: + + BTRFS info (device dm-2): first mount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff + BTRFS info (device dm-2): using crc32c checksum algorithm + BTRFS info (device dm-2): checking UUID tree + BTRFS info (device dm-2): turning on async discard + BTRFS info (device dm-2): enabling free space tree + BTRFS critical (device dm-2 state E): emergency shutdown + ------------[ cut here ]------------ + WARNING: extent_io.c:1742 at extent_writepage_io+0x437/0x520 [btrfs], CPU#2: kworker/u43:2/651591 + CPU: 2 UID: 0 PID: 651591 Comm: kworker/u43:2 Tainted: G W OE 7.0.0-rc6-custom+ #365 PREEMPT(full) 5804053f02137e627472d94b5128cc9fcb110e88 + RIP: 0010:extent_writepage_io+0x437/0x520 [btrfs] + Call Trace: + + extent_write_cache_pages+0x2a5/0x820 [btrfs 70299925d0856939e93b17d480651713b3cbba58] + btrfs_writepages+0x74/0x130 [btrfs 70299925d0856939e93b17d480651713b3cbba58] + do_writepages+0xd0/0x160 + __writeback_single_inode+0x42/0x340 + writeback_sb_inodes+0x22d/0x580 + wb_writeback+0xc6/0x360 + wb_workfn+0xbd/0x470 + process_one_work+0x198/0x3b0 + worker_thread+0x1c8/0x330 + kthread+0xee/0x120 + ret_from_fork+0x2a6/0x330 + ret_from_fork_asm+0x11/0x20 + + ---[ end trace 0000000000000000 ]--- + BTRFS error (device dm-2 state E): root 5 ino 259 folio 1323008 is marked dirty without notifying the fs + BTRFS error (device dm-2 state E): failed to submit blocks, root=5 inode=259 folio=1323008 submit_bitmap=0: -117 + BTRFS info (device dm-2 state E): last unmount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff + +[CAUSE] +Inside btrfs we have the following pattern in several locations, for +example inside btrfs_dirty_folio(): + + btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block, + EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, + cached); + + ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, + extra_bits, cached); + if (ret) + return ret; + +However btrfs_set_extent_delalloc() can return IO errors other than -ENOMEM +through the following callchain: + + btrfs_set_extent_delalloc() + \- btrfs_find_new_delalloc_bytes() + \- btrfs_get_extent() + \- btrfs_lookup_file_extent() + \- btrfs_search_slot() + +When such IO error happened, the previous btrfs_clear_extent_bit() has +cleared the EXTENT_DELALLOC for the range, and we're expecting +btrfs_set_extent_delalloc() to re-set EXTENT_DELALLOC. + +But since btrfs_set_extent_delalloc() failed before +btrfs_set_extent_bit(), EXTENT_DELALLOC flag is no longer present. + +And if the folio range is dirty before entering +btrfs_set_extent_delalloc(), we got a dirty folio but no EXTENT_DELALLOC +flag now. + +Then we hit the folio writeback: + + extent_writepage() + |- writepage_delalloc() + | No ordered extent is created, as there is no EXTENT_DELALLOC set + | for the folio range. + | This also means the folio has no ordered flag set. + | + |- extent_writepage_io() + \- if (unlikely(!folio_test_ordered(folio)) + Now we hit the warning. + +[FIX] +Introduce a new helper, btrfs_reset_extent_delalloc() to replace the +currently open-coded btrfs_clear_extent_bit() + +btrfs_set_extent_delalloc() combination. + +Instead of calling btrfs_clear_extent_bit() first, update +EXTENT_DELALLOC_NEW first, as that part can fail due to metadata IO, +meanwhile btrfs_clear_extent_bit() and btrfs_set_extent_bit() won't +return any error but retry memory allocation until succeeded. + +This allows us to fail early without clearing EXTENT_DELALLOC bit, so +even if that new btrfs_reset_extent_delalloc() failed before touching +EXTENT_DELALLOC, the existing dirty range will still have their old +EXTENT_DELALLOC flag present, thus avoid the warning. + +CC: stable@vger.kernel.org # 6.1+ +Reviewed-by: Filipe Manana +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/btrfs_inode.h | 2 + + fs/btrfs/file.c | 25 ++------------------ + fs/btrfs/inode.c | 61 +++++++++++++++++++++++++++++++++++++++++++------ + fs/btrfs/reflink.c | 4 --- + 4 files changed, 60 insertions(+), 32 deletions(-) + +--- a/fs/btrfs/btrfs_inode.h ++++ b/fs/btrfs/btrfs_inode.h +@@ -569,6 +569,8 @@ int btrfs_start_delalloc_roots(struct bt + int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end, + unsigned int extra_bits, + struct extent_state **cached_state); ++int btrfs_reset_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end, ++ unsigned int extra_bits, struct extent_state **cached_state); + + struct btrfs_new_inode_args { + /* Input */ +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -93,16 +93,8 @@ int btrfs_dirty_folio(struct btrfs_inode + + end_of_last_block = start_pos + num_bytes - 1; + +- /* +- * The pages may have already been dirty, clear out old accounting so +- * we can set things up properly +- */ +- btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block, +- EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, +- cached); +- +- ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, +- extra_bits, cached); ++ ret = btrfs_reset_extent_delalloc(inode, start_pos, end_of_last_block, ++ extra_bits, cached); + if (ret) + return ret; + +@@ -1966,18 +1958,7 @@ again: + } + } + +- /* +- * page_mkwrite gets called when the page is firstly dirtied after it's +- * faulted in, but write(2) could also dirty a page and set delalloc +- * bits, thus in this case for space account reason, we still need to +- * clear any delalloc bits within this page range since we have to +- * reserve data&meta space before lock_page() (see above comments). +- */ +- btrfs_clear_extent_bit(io_tree, page_start, end, +- EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | +- EXTENT_DEFRAG, &cached_state); +- +- ret = btrfs_set_extent_delalloc(inode, page_start, end, 0, &cached_state); ++ ret = btrfs_reset_extent_delalloc(inode, page_start, end, 0, &cached_state); + if (ret < 0) { + btrfs_unlock_extent(io_tree, page_start, page_end, &cached_state); + goto out_unlock; +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -2810,7 +2810,13 @@ int btrfs_set_extent_delalloc(struct btr + unsigned int extra_bits, + struct extent_state **cached_state) + { +- WARN_ON(PAGE_ALIGNED(end)); ++ const u32 blocksize = inode->root->fs_info->sectorsize; ++ ++ /* Basic alignment check. */ ++ ASSERT(IS_ALIGNED(start, blocksize), "start=%llu blocksize=%u", ++ start, blocksize); ++ ASSERT(IS_ALIGNED(end + 1, blocksize), "inclusive end=%llu blocksize=%u", ++ end, blocksize); + + if (start >= i_size_read(&inode->vfs_inode) && + !(inode->flags & BTRFS_INODE_PREALLOC)) { +@@ -3035,6 +3041,52 @@ int btrfs_writepage_cow_fixup(struct fol + return -EAGAIN; + } + ++/* ++ * Clear the old accounting flags and set EXTENT_DELALLOC for the range. ++ * ++ * Return <0 for error, in that case no range has EXTENT_DELALLOC bit cleared or set. ++ */ ++int btrfs_reset_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end, ++ unsigned int extra_bits, struct extent_state **cached_state) ++{ ++ const u32 blocksize = inode->root->fs_info->sectorsize; ++ ++ /* The @extra_bits can only be EXTENT_NORESERVE for now. */ ++ ASSERT(!(extra_bits & ~EXTENT_NORESERVE), "extra_bits=0x%x", extra_bits); ++ ++ /* Basic alignment check. */ ++ ASSERT(IS_ALIGNED(start, blocksize), "start=%llu blocksize=%u", ++ start, blocksize); ++ ASSERT(IS_ALIGNED(end + 1, blocksize), "inclusive end=%llu blocksize=%u", ++ end, blocksize); ++ ++ /* ++ * Check and set DELALLOC_NEW flag, this needs to search tree thus can ++ * fail early. Thus we want to do this before clearing EXTENT_DELALLOC. ++ */ ++ if (start >= i_size_read(&inode->vfs_inode) && ++ !(inode->flags & BTRFS_INODE_PREALLOC)) { ++ /* ++ * There can't be any extents following EOF in this case so just ++ * set the delalloc new bit for the range directly. ++ */ ++ extra_bits |= EXTENT_DELALLOC_NEW; ++ } else { ++ int ret; ++ ++ ret = btrfs_find_new_delalloc_bytes(inode, start, end + 1 - start, ++ NULL); ++ if (unlikely(ret)) ++ return ret; ++ } ++ /* Clear the old accounting as the range may already be dirty. */ ++ btrfs_clear_extent_bit(&inode->io_tree, start, end, ++ EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | ++ EXTENT_DEFRAG, cached_state); ++ return btrfs_set_extent_bit(&inode->io_tree, start, end, ++ EXTENT_DELALLOC | extra_bits, cached_state); ++} ++ + static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, u64 file_pos, + struct btrfs_file_extent_item *stack_fi, +@@ -5181,12 +5233,7 @@ again: + goto again; + } + +- btrfs_clear_extent_bit(&inode->io_tree, block_start, block_end, +- EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, +- &cached_state); +- +- ret = btrfs_set_extent_delalloc(inode, block_start, block_end, 0, +- &cached_state); ++ ret = btrfs_reset_extent_delalloc(inode, block_start, block_end, 0, &cached_state); + if (ret) { + btrfs_unlock_extent(io_tree, block_start, block_end, &cached_state); + goto out_unlock; +--- a/fs/btrfs/reflink.c ++++ b/fs/btrfs/reflink.c +@@ -94,9 +94,7 @@ static int copy_inline_to_page(struct bt + if (ret < 0) + goto out_unlock; + +- btrfs_clear_extent_bit(&inode->io_tree, file_offset, range_end, +- EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, NULL); +- ret = btrfs_set_extent_delalloc(inode, file_offset, range_end, 0, NULL); ++ ret = btrfs_reset_extent_delalloc(inode, file_offset, range_end, 0, NULL); + if (ret) + goto out_unlock; + diff --git a/queue-7.1/btrfs-do-not-trim-a-device-which-is-not-writeable.patch b/queue-7.1/btrfs-do-not-trim-a-device-which-is-not-writeable.patch new file mode 100644 index 0000000000..c35cf0c9ea --- /dev/null +++ b/queue-7.1/btrfs-do-not-trim-a-device-which-is-not-writeable.patch @@ -0,0 +1,140 @@ +From 1b1937eb08f51319bf71575484cde2b8c517aedc Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Tue, 2 Jun 2026 13:34:46 +0930 +Subject: btrfs: do not trim a device which is not writeable + +From: Qu Wenruo + +commit 1b1937eb08f51319bf71575484cde2b8c517aedc upstream. + +[BUG] +There is a bug report that btrfs/242 can randomly fail with the +following NULL pointer dereference: + + run fstests btrfs/242 at 2026-06-01 10:25:08 + BTRFS: device fsid d4d7f234-487c-4787-88e4-47a8b68c9874 devid 1 transid 9 /dev/sdc (8:32) scanned by mount (122609) + BTRFS info (device sdc): first mount of filesystem d4d7f234-487c-4787-88e4-47a8b68c9874 + BTRFS info (device sdc): using crc32c checksum algorithm + BTRFS warning (device sdc): devid 2 uuid fbe72d72-3272-482d-80fb-ab88ed398192 is missing + BTRFS warning (device sdc): devid 2 uuid fbe72d72-3272-482d-80fb-ab88ed398192 is missing + BTRFS info (device sdc): allowing degraded mounts + BTRFS info (device sdc): turning on async discard + BTRFS info (device sdc): enabling free space tree + Unable to handle kernel NULL pointer dereference at virtual address 0000000000000018 + user pgtable: 4k pages, 48-bit VAs, pgdp=000000013fd6b000 + CPU: 4 UID: 0 PID: 122625 Comm: fstrim Not tainted 7.0.10-2-default #1 PREEMPT(full) openSUSE Tumbleweed e9a5f6b24978fba3bf015a992f865837fdfff3dd + Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20250812-19.fc42 08/12/2025 + pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) + pc : btrfs_trim_fs+0x34c/0xa00 [btrfs] + lr : btrfs_trim_fs+0x1f0/0xa00 [btrfs] + Call trace: + btrfs_trim_fs+0x34c/0xa00 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] (P) + btrfs_ioctl_fitrim+0xe8/0x178 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] + btrfs_ioctl+0xdd4/0x2bd8 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] + __arm64_sys_ioctl+0xac/0x108 + invoke_syscall.constprop.0+0x5c/0xd0 + el0_svc_common.constprop.0+0x40/0xf0 + do_el0_svc+0x24/0x40 + el0_svc+0x40/0x1d0 + el0t_64_sync_handler+0xa0/0xe8 + el0t_64_sync+0x1b0/0x1b8 + Code: 17ffff83 f94017e0 f9002be0 f9402ea0 (f9400c00) + ---[ end trace 0000000000000000 ]--- + +Also the reporter is very kind to test the following ASSERT() added to +btrfs_trim_free_extents_throttle(): + + ASSERT(device->bdev, + "devid=%llu path=%s dev_state=0x%lx\n", + device->devid, btrfs_dev_name(device), device->dev_state); + +And it shows the following output: + + assertion failed: device->bdev, in extent-tree.c:6630 (devid=2 path=/dev/sdd dev_state=0x82) + +Which means the device->bdev is NULL, and the dev_state is +BTRFS_DEV_STATE_IN_FS_METADATA | BTRFS_DEV_STATE_ITEM_FOUND, without +BTRFS_DEV_STATE_WRITEABLE flag set. + +[CAUSE] +The pc points to the following call chain: + + btrfs_trim_fs() + |- btrfs_trim_free_extents() + |- btrfs_trim_free_extents_throttle() + |- bdev_max_discard_sectors(device->bdev) + +So the NULL pointer dereference is caused by device->bdev being NULL. + +This looks impossible by a quick glance, as just before calling +btrfs_trim_free_extents_throttle(), we have skipped any device that has +BTRFS_DEV_STATE_MISSING flag set. + +However in this particular case, there is a window where the missing +device is later re-scanned, causing btrfs to remove the +BTRFS_DEV_STATE_MISSING flag: + + btrfs_control_ioctl() + |- btrfs_scan_one_device() + |- device_list_add() + |- rcu_assign_pointer(device->name, name); + | This updates the missing device's path to the new good path. + | + |- clear_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state) + This removes the BTRFS_DEV_STATE_MISSING flag. + +This allows the missing device to re-appear and clear the +BTRFS_DEV_STATE_MISSING flag. However the device still does not have +the BTRFS_DEV_STATE_WRITEABLE flag set, nor is its bdev pointer updated. + +The bdev pointer remains NULL, triggering the crash later. + +[FIX] +This is a big de-synchronization between BTRFS_DEV_STATE_MISSING and +device->bdev pointer, and shows a gap in btrfs's re-appearing-device +handling. + +The proper handling of re-appearing device will need quite some extra +work, which is out of the context of this small fix. + +Thankfully the regular bbio submission path has already handled it well +by checking if the device->bdev is NULL before submitting. + +So here we just fix the crash by checking if the device is writeable and +has a bdev pointer before calling bdev_max_discard_sectors(). + +Reported-by: Su Yue +Link: https://lore.kernel.org/linux-btrfs/wlwir19t.fsf@damenly.org/ +Fixes: 499f377f49f0 ("btrfs: iterate over unused chunk space in FITRIM") +CC: stable@vger.kernel.org # 5.10+ +Reviewed-by: Filipe Manana +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/extent-tree.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -6613,12 +6613,16 @@ static int btrfs_trim_free_extents_throt + + *trimmed = 0; + +- /* Discard not supported = nothing to do. */ +- if (!bdev_max_discard_sectors(device->bdev)) ++ /* ++ * The caller only filters out MISSING devices, but a device that was ++ * missing at mount and later rescanned has MISSING cleared while bdev ++ * is still NULL and WRITEABLE is still unset. Skip those here. ++ */ ++ if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) || !device->bdev) + return 0; + +- /* Not writable = nothing to do. */ +- if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) ++ /* Discard not supported = nothing to do. */ ++ if (!bdev_max_discard_sectors(device->bdev)) + return 0; + + /* No free space = nothing to do. */ diff --git a/queue-7.1/btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch b/queue-7.1/btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch new file mode 100644 index 0000000000..2337b9ca1b --- /dev/null +++ b/queue-7.1/btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch @@ -0,0 +1,185 @@ +From 66ff4d366e7eb4d31813d2acabf3af512ce03aa5 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Thu, 4 Jun 2026 09:59:46 +0930 +Subject: btrfs: fix false IO failure after falling back to buffered write + +From: Qu Wenruo + +commit 66ff4d366e7eb4d31813d2acabf3af512ce03aa5 upstream. + +[BUG] +The test case generic/362 will fail with "nodatasum" mount option (*): + + MOUNT_OPTIONS -- -o nodatasum /dev/mapper/test-scratch1 /mnt/scratch + +# generic/362 0s ... - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) +# --- tests/generic/362.out 2024-08-24 15:31:37.200000000 +0930 +# +++ /home/adam/xfstests/results//generic/362.out.bad 2026-05-27 10:21:17.574771567 +0930 +# @@ -1,2 +1,3 @@ +# QA output created by 362 +# +First write failed: Input/output error +# Silence is golden +# ... + +*: If the test case has been executed before with default data checksum, +the failure will not reproduce. Need the following fix to make it +reliably reproducible: +https://lore.kernel.org/linux-btrfs/20260528111659.87113-1-wqu@suse.com/ + +[CAUSE] +Inside __iomap_dio_rw(), the -EFAULT/-ENOTBLK error is not directly returned. +Thus we never got an error pointer from __iomap_dio_rw(). + +The call chain looks like this: + + btrfs_direct_write() + |- btrfs_dio_write() + |- __iomap_dio_rw() + | |- iomap_iter() + | | |- btrfs_dio_iomap_begin() + | | Now an ordered extent is allocated for the 4K write. + | | + | |- iomi.status = iomap_dio_iter() + | | Where iomap_dio_iter() returned -EFAULT. + | | + | |- ret = iomap_iter() + | | |- btrfs_dio_iomap_end() + | | | |- btrfs_finish_ordered_extent(uptodate = false) + | | | | |- can_finish_ordered_extent() + | | | | |- btrfs_mark_ordered_extent_error() + | | | | |- mapping_set_error() + | | | | Now the address space is marked error. + | | | | return -ENOTBLK + | | |- return -ENOTBLK + | |- if (ret == -ENOTBLK) { ret = 0; } + | Now the return value is reset to 0. + | Thus no error pointer will be returned. + | + |- ret = iomap_dio_complete() + | Since no byte is submitted, @ret is 0. + | + |- Fallback to buffered IO + | And the buffered write finished without error + | + |- filemap_fdatawait_range() + |- filemap_check_errors() + The previous error is recorded, thus an error is returned + +However the buffered write is properly submitted and finished, the error +is from the btrfs_finish_ordered_extent() call with @uptodate = false. + +[FIX] +When a short dio write happened, any range that is submitted will have +btrfs_extract_ordered_extent() to be called, thus the submitted range +will always have an OE just covering the submitted range. + +The remaining OE range is never submitted, thus they should be treated +as truncated, not an error. So that we can properly reclaim and not +insert an unnecessary file extent item, without marking the mapping as +error. + +Extract a helper, btrfs_mark_ordered_extent_truncated(), and utilize +that helper to mark the direct IO ordered extent as truncated, so it +won't cause failure for the later buffered fallback. + +[REASON FOR NO FIXES TAG] +The bug itself is pretty old, at commit f85781fb505e ("btrfs: switch to +iomap for direct IO") we're already passing @uptodate=false finishing +the OE. +But at that time OE with IOERR won't call mapping_set_error(), so it's +not exposed. +Later commit d61bec08b904 ("btrfs: mark ordered extent and inode with +error if we fail to finish") finally exposed the bug, but that commit +is doing a correct job, not the root cause. + +Anyway the bug is very old, dating back to 5.1x days, thus only CC to +stable. + +CC: stable@vger.kernel.org # 5.15+ +Reviewed-by: Boris Burkov +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/direct-io.c | 17 ++++++++++++++--- + fs/btrfs/inode.c | 6 +----- + fs/btrfs/ordered-data.c | 12 ++++++++++++ + fs/btrfs/ordered-data.h | 2 ++ + 4 files changed, 29 insertions(+), 8 deletions(-) + +--- a/fs/btrfs/direct-io.c ++++ b/fs/btrfs/direct-io.c +@@ -624,12 +624,23 @@ static int btrfs_dio_iomap_end(struct in + if (submitted < length) { + pos += submitted; + length -= submitted; +- if (write) ++ if (write) { ++ /* ++ * We have a short write, if there is any range ++ * that is submitted properly, that part will have ++ * its own OE split from the original one. ++ * ++ * So for the OE at dio_data->ordered, it's the part ++ * that is not submitted, and should be marked ++ * as fully truncated. ++ */ ++ btrfs_mark_ordered_extent_truncated(dio_data->ordered, 0); + btrfs_finish_ordered_extent(dio_data->ordered, +- pos, length, false); +- else ++ pos, length, true); ++ } else { + btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos, + pos + length - 1, NULL); ++ } + ret = -ENOTBLK; + } + if (write) { +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -7776,11 +7776,7 @@ static void btrfs_invalidate_folio(struc + EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | + EXTENT_DEFRAG, &cached_state); + +- spin_lock(&inode->ordered_tree_lock); +- set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); +- ordered->truncated_len = min(ordered->truncated_len, +- cur - ordered->file_offset); +- spin_unlock(&inode->ordered_tree_lock); ++ btrfs_mark_ordered_extent_truncated(ordered, cur - ordered->file_offset); + + /* + * If the ordered extent has finished, we're safe to delete all +--- a/fs/btrfs/ordered-data.c ++++ b/fs/btrfs/ordered-data.c +@@ -357,6 +357,18 @@ void btrfs_mark_ordered_extent_error(str + mapping_set_error(ordered->inode->vfs_inode.i_mapping, -EIO); + } + ++void btrfs_mark_ordered_extent_truncated(struct btrfs_ordered_extent *ordered, ++ u64 truncate_len) ++{ ++ struct btrfs_inode *inode = ordered->inode; ++ ++ ASSERT(truncate_len <= ordered->num_bytes); ++ spin_lock(&inode->ordered_tree_lock); ++ set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); ++ ordered->truncated_len = min(ordered->truncated_len, truncate_len); ++ spin_unlock(&inode->ordered_tree_lock); ++} ++ + static void finish_ordered_fn(struct btrfs_work *work) + { + struct btrfs_ordered_extent *ordered_extent; +--- a/fs/btrfs/ordered-data.h ++++ b/fs/btrfs/ordered-data.h +@@ -226,6 +226,8 @@ bool btrfs_try_lock_ordered_range(struct + struct btrfs_ordered_extent *btrfs_split_ordered_extent( + struct btrfs_ordered_extent *ordered, u64 len); + void btrfs_mark_ordered_extent_error(struct btrfs_ordered_extent *ordered); ++void btrfs_mark_ordered_extent_truncated(struct btrfs_ordered_extent *ordered, ++ u64 truncate_len); + int __init ordered_data_init(void); + void __cold ordered_data_exit(void); + diff --git a/queue-7.1/btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch b/queue-7.1/btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch new file mode 100644 index 0000000000..d06ae35941 --- /dev/null +++ b/queue-7.1/btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch @@ -0,0 +1,196 @@ +From ff66fe6662330226b3f486014c375538d91c44aa Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Thu, 4 Jun 2026 09:59:47 +0930 +Subject: btrfs: fix incorrect buffered IO fallback for append direct writes + +From: Qu Wenruo + +commit ff66fe6662330226b3f486014c375538d91c44aa upstream. + +[BUG] +With the previous bug of short direct writes fixed, test case +generic/362 (*) still fails with the following error with nodatasum +mount option: + +# generic/362 0s ... - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) +# - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) +# --- tests/generic/362.out 2024-08-24 15:31:37.200000000 +0930 +# +++ /home/adam/xfstests/results//generic/362.out.bad 2026-05-27 10:13:09.072485767 +0930 +# @@ -1,2 +1,3 @@ +# QA output created by 362 +# +Wrong file size after first write, got 8192 expected 4096 +# Silence is golden +# ... + +*: If the test case has been executed before with default data checksum, +the failure will not reproduce. Need the following fix to make it +reliably reproducible: +https://lore.kernel.org/linux-btrfs/20260528111659.87113-1-wqu@suse.com/ + +[CAUSE] +Inside btrfs_dio_iomap_begin() for a direct write, we increase the isize +if it's beyond the current isize. + +But if the direct io finished short, we do not revert the isize to the +previous value nor to the short write end. + +Then if we need to fall back to buffered writes, and the write has +IOCB_APPEND flag, then the buffered write will be positioned at the +incorrect isize. + +The call chain looks like this: + + btrfs_direct_write(pos=0, length=4K) + |- __iomap_dio_rw() + | |- iomap_iter() + | | |- btrfs_dio_iomap_begin() + | | |- btrfs_get_blocks_direct_write() + | | |- i_size_write() + | | Which updates the isize to the write end (4K). + | | + | |- iomap_dio_iter() + | | Failed with -EFAULT on the first page. + | | + | |- iomap_iter() + | | |- btrfs_dio_iomap_end() + | | Detects a short write, return -ENOTBLK + | |- if (ret == -ENOTBLK) { ret = 0;} + | Which resets the return value. + | + |- ret = iomap_dio_complet() + | Which returns 0. + | + |- btrfs_buffered_write(iocb, from); + |- generic_write_checks() + |- iocb->ki_pos = i_size_read() + Which is still the new size (4K), other than the original + isize 0. + +[FIX] +Introduce the following btrfs_dio_data members: + +- old_isize + +- updated_isize + If the direct write has enlarged the isize. + +Then if we got a short write, and btrfs_dio_data::updated_isize is set, +revert to the correct isize based on old_isize and current file +position. + +And here we call i_size_write() without holding an extent lock, which is +a very special case that we're safe to do: + + - Only a single writer can be enlarging isize + Enlarging isize will take the exclusive inode lock. + + - Buffered readers need to wait for the OE we're holding + Buffered readers will lock extent and wait for OE of the folio range. + Sometimes we can skip the OE wait, but since all page cache is + invalidated, the OE wait can not be skipped. + +But I do not think this is the most elegant solution, nor covers all +cases. E.g. if the bio is submitted but IO failed, we are unable to do +the revert. + +I believe the more elegant one would be extend the EXTENT_DIO_LOCKED +lifespan for direct writes, so that we can update the isize when a +write beyond EOF finished successfully. + +However that change is too huge for a small bug fix. +So only implement the minimal partial fix for now. + +[REASON FOR NO FIXES TAG] +The bug is again very old, before commit f85781fb505e ("btrfs: switch to +iomap for direct IO") we are already increasing isize without a +proper rollback for short writes. + +Thus only a CC to stable. + +CC: stable@vger.kernel.org # 5.15+ +Reviewed-by: Boris Burkov +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/direct-io.c | 43 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 42 insertions(+), 1 deletion(-) + +--- a/fs/btrfs/direct-io.c ++++ b/fs/btrfs/direct-io.c +@@ -15,10 +15,12 @@ + + struct btrfs_dio_data { + ssize_t submitted; ++ loff_t old_isize; + struct extent_changeset *data_reserved; + struct btrfs_ordered_extent *ordered; + bool data_space_reserved; + bool nocow_done; ++ bool updated_isize; + }; + + struct btrfs_dio_private { +@@ -228,6 +230,7 @@ static int btrfs_get_blocks_direct_write + bool space_reserved = false; + u64 len = *lenp; + u64 prev_len; ++ loff_t old_isize; + int ret = 0; + + /* +@@ -341,8 +344,14 @@ static int btrfs_get_blocks_direct_write + * Need to update the i_size under the extent lock so buffered + * readers will get the updated i_size when we unlock. + */ +- if (start + len > i_size_read(inode)) ++ old_isize = i_size_read(inode); ++ if (start + len > old_isize) { ++ if (!dio_data->updated_isize) { ++ dio_data->old_isize = old_isize; ++ dio_data->updated_isize = true; ++ } + i_size_write(inode, start + len); ++ } + out: + if (ret && space_reserved) { + btrfs_delalloc_release_extents(BTRFS_I(inode), len); +@@ -626,6 +635,38 @@ static int btrfs_dio_iomap_end(struct in + length -= submitted; + if (write) { + /* ++ * Got a short write and have updated the isize, need to ++ * revert the isize change. ++ * ++ * Normally we need to update isize with extent lock hold, ++ * but we're safe due to the following factors: ++ * ++ * - Only a single writer can be enlarging isize ++ * Enlarging isize will take the exclusive inode lock. ++ * ++ * - Buffered readers need to wait for the OE we're holding ++ * Buffered readers will lock extent and wait for OE ++ * of the folio range, and since page cache is invalidated ++ * the OE wait can not be skipped. ++ * ++ * So here we are safe to revert the isize before ++ * finishing the OE, and no reader of the remaining range ++ * can see the enlarged size. ++ * ++ * TODO: Extend the DIO_LOCKED lifespan for direct writes, ++ * and only enlarge isize after a successful write. ++ */ ++ if (dio_data->updated_isize) { ++ u64 new_isize; ++ ++ if (submitted == 0) ++ new_isize = dio_data->old_isize; ++ else ++ new_isize = max(dio_data->old_isize, pos); ++ i_size_write(inode, new_isize); ++ dio_data->updated_isize = false; ++ } ++ /* + * We have a short write, if there is any range + * that is submitted properly, that part will have + * its own OE split from the original one. diff --git a/queue-7.1/crypto-af_alg-remove-zero-copy-support-from-skcipher-and-aead.patch b/queue-7.1/crypto-af_alg-remove-zero-copy-support-from-skcipher-and-aead.patch new file mode 100644 index 0000000000..a05d35c95d --- /dev/null +++ b/queue-7.1/crypto-af_alg-remove-zero-copy-support-from-skcipher-and-aead.patch @@ -0,0 +1,211 @@ +From ffdd2bc378953b525aca61902534e753f1f8e734 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 4 May 2026 15:53:28 -0700 +Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead + +From: Eric Biggers + +commit ffdd2bc378953b525aca61902534e753f1f8e734 upstream. + +The zero-copy support is one of the riskiest aspects of AF_ALG. It +allows userspace to request cryptographic operations directly on +pagecache pages of files like the 'su' binary. It also allows userspace +to concurrently modify the memory which is being operated on, a recipe +for TOCTOU vulnerabilities. + +While zero-copy support is more valuable in other areas of the kernel +like the frequently used networking and file I/O code, it has far less +value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists +for backwards compatibility with a small set of userspace programs such +as 'iwd' that haven't yet been fixed to use userspace crypto code. + +Originally AF_ALG was intended to be used to access hardware crypto +accelerators. However, it isn't an efficient interface for that anyway, +and it turned out to be rarely used in this way in practice. + +Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its +benefits. Let's just remove it. + +This commit removes it from the "skcipher" and "aead" algorithm types. +"hash" will be handled separately. + +This is a soft break, not a hard break. Even after this commit, it +still works to use splice() or sendfile() to transfer data to an AF_ALG +request socket from a pipe or any file, respectively. What changes is +just that the kernel now makes an internal, stable copy of the data +before doing the crypto operation. So performance is slightly reduced, +but the UAPI isn't broken. And, very importantly, it's much safer. + +Tested with libkcapi/test.sh. All its test cases still pass. I also +verified that this would have prevented the copy.fail exploit as well. +I also used a custom test program to verify that sendfile() still works. + +Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations") +Fixes: 400c40cf78da ("crypto: algif - add AEAD support") +Reported-by: Taeyang Lee <0wn@theori.io> +Link: https://copy.fail/ +Reported-by: Feng Ning +Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local +Reviewed-by: Demi Marie Obenour +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/crypto/userspace-if.rst | 31 +------------- + crypto/af_alg.c | 71 +++++++++++----------------------- + crypto/algif_aead.c | 8 +-- + 3 files changed, 32 insertions(+), 78 deletions(-) + +--- a/Documentation/crypto/userspace-if.rst ++++ b/Documentation/crypto/userspace-if.rst +@@ -327,33 +327,10 @@ CRYPTO_USER_API_RNG_CAVP option: + Zero-Copy Interface + ------------------- + +-In addition to the send/write/read/recv system call family, the AF_ALG +-interface can be accessed with the zero-copy interface of +-splice/vmsplice. As the name indicates, the kernel tries to avoid a copy +-operation into kernel space. +- +-The zero-copy operation requires data to be aligned at the page +-boundary. Non-aligned data can be used as well, but may require more +-operations of the kernel which would defeat the speed gains obtained +-from the zero-copy interface. +- +-The system-inherent limit for the size of one zero-copy operation is 16 +-pages. If more data is to be sent to AF_ALG, user space must slice the +-input into segments with a maximum size of 16 pages. +- +-Zero-copy can be used with the following code example (a complete +-working example is provided with libkcapi): +- +-:: +- +- int pipes[2]; +- +- pipe(pipes); +- /* input data in iov */ +- vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); +- /* opfd is the file descriptor returned from accept() system call */ +- splice(pipes[0], NULL, opfd, NULL, ret, 0); +- read(opfd, out, outlen); ++AF_ALG used to have zero-copy support, but it was removed due to it being a ++frequent source of vulnerabilities. For backwards compatibility the splice() ++and sendfile() system calls are still supported, but the kernel will make an ++internal copy of the data before passing it to the crypto code. + + + Setsockopt Interface +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -973,7 +973,7 @@ int af_alg_sendmsg(struct socket *sock, + ssize_t plen; + + /* use the existing memory in an allocated page */ +- if (ctx->merge && !(msg->msg_flags & MSG_SPLICE_PAGES)) { ++ if (ctx->merge) { + sgl = list_entry(ctx->tsgl_list.prev, + struct af_alg_tsgl, list); + sg = sgl->sg + sgl->cur - 1; +@@ -1017,60 +1017,37 @@ int af_alg_sendmsg(struct socket *sock, + if (sgl->cur) + sg_unmark_end(sg + sgl->cur - 1); + +- if (msg->msg_flags & MSG_SPLICE_PAGES) { +- struct sg_table sgtable = { +- .sgl = sg, +- .nents = sgl->cur, +- .orig_nents = sgl->cur, +- }; +- +- plen = extract_iter_to_sg(&msg->msg_iter, len, &sgtable, +- MAX_SGL_ENTS - sgl->cur, 0); +- if (plen < 0) { +- err = plen; ++ do { ++ struct page *pg; ++ unsigned int i = sgl->cur; ++ ++ plen = min_t(size_t, len, PAGE_SIZE); ++ ++ pg = alloc_page(GFP_KERNEL); ++ if (!pg) { ++ err = -ENOMEM; + goto unlock; + } + +- for (; sgl->cur < sgtable.nents; sgl->cur++) +- get_page(sg_page(&sg[sgl->cur])); ++ sg_assign_page(sg + i, pg); ++ ++ err = memcpy_from_msg(page_address(sg_page(sg + i)), ++ msg, plen); ++ if (err) { ++ __free_page(sg_page(sg + i)); ++ sg_assign_page(sg + i, NULL); ++ goto unlock; ++ } ++ ++ sg[i].length = plen; + len -= plen; + ctx->used += plen; + copied += plen; + size -= plen; +- } else { +- do { +- struct page *pg; +- unsigned int i = sgl->cur; +- +- plen = min_t(size_t, len, PAGE_SIZE); +- +- pg = alloc_page(GFP_KERNEL); +- if (!pg) { +- err = -ENOMEM; +- goto unlock; +- } +- +- sg_assign_page(sg + i, pg); +- +- err = memcpy_from_msg( +- page_address(sg_page(sg + i)), +- msg, plen); +- if (err) { +- __free_page(sg_page(sg + i)); +- sg_assign_page(sg + i, NULL); +- goto unlock; +- } +- +- sg[i].length = plen; +- len -= plen; +- ctx->used += plen; +- copied += plen; +- size -= plen; +- sgl->cur++; +- } while (len && sgl->cur < MAX_SGL_ENTS); ++ sgl->cur++; ++ } while (len && sgl->cur < MAX_SGL_ENTS); + +- ctx->merge = plen & (PAGE_SIZE - 1); +- } ++ ctx->merge = plen & (PAGE_SIZE - 1); + + if (!size) + sg_mark_end(sg + sgl->cur - 1); +--- a/crypto/algif_aead.c ++++ b/crypto/algif_aead.c +@@ -9,10 +9,10 @@ + * The following concept of the memory management is used: + * + * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is +- * filled by user space with the data submitted via sendmsg (maybe with +- * MSG_SPLICE_PAGES). Filling up the TX SGL does not cause a crypto operation +- * -- the data will only be tracked by the kernel. Upon receipt of one recvmsg +- * call, the caller must provide a buffer which is tracked with the RX SGL. ++ * filled by user space with the data submitted via sendmsg. Filling up the TX ++ * SGL does not cause a crypto operation -- the data will only be tracked by the ++ * kernel. Upon receipt of one recvmsg call, the caller must provide a buffer ++ * which is tracked with the RX SGL. + * + * During the processing of the recvmsg operation, the cipher request is + * allocated and prepared. As part of the recvmsg operation, the processed diff --git a/queue-7.1/crypto-atmel-sha204a-drop-hwrng-quality-reduction-for-atsha204a.patch b/queue-7.1/crypto-atmel-sha204a-drop-hwrng-quality-reduction-for-atsha204a.patch new file mode 100644 index 0000000000..a8384162c6 --- /dev/null +++ b/queue-7.1/crypto-atmel-sha204a-drop-hwrng-quality-reduction-for-atsha204a.patch @@ -0,0 +1,97 @@ +From ea5e57cc97185329dcc5ebdcaae7e1500bf0ad0b Mon Sep 17 00:00:00 2001 +From: Thorsten Blum +Date: Tue, 28 Apr 2026 12:14:32 +0200 +Subject: crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A + +From: Thorsten Blum + +commit ea5e57cc97185329dcc5ebdcaae7e1500bf0ad0b upstream. + +Commit 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to +lowest possible") reduced the hwrng quality to 1 based on a review by +Bill Cox [1]. However, despite its title, the review only tested the +ATSHA204, not the ATSHA204A. + +In the same thread, Atmel engineer Landon Cox wrote "this behavior has +been eliminated entirely"[2] in the ATSHA204A and "this problem does not +affect the ATECC108 or the ATECC108A (or the ATSHA204A)"[3]. + +According to the official ATSHA204A datasheet [4], the device contains a +high-quality hardware RNG that combines its output with an internal seed +value stored in EEPROM or SRAM to generate random numbers. The device +also implements all security functions using SHA-256, and the driver +uses the chip's Random command in seed-update mode. + +Keep 'quality = 1' for ATSHA204, but drop the explicit hwrng quality +reduction for ATSHA204A and fall back to the hwrng core default. + +[1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html +[2] https://www.metzdowd.com/pipermail/cryptography/2014-December/023852.html +[3] https://www.metzdowd.com/pipermail/cryptography/2014-December/023886.html +[4] https://ww1.microchip.com/downloads/en/DeviceDoc/ATSHA204A-Data-Sheet-40002025A.pdf + +Fixes: 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to lowest possible") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Reviewed-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/atmel-sha204a.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/crypto/atmel-sha204a.c ++++ b/drivers/crypto/atmel-sha204a.c +@@ -19,6 +19,12 @@ + #include + #include "atmel-i2c.h" + ++/* ++ * According to review by Bill Cox [1], the ATSHA204 has very low entropy. ++ * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html ++ */ ++static const unsigned short atsha204_quality = 1; ++ + static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data, + void *areq, int status) + { +@@ -158,6 +164,7 @@ static const struct attribute_group atme + static int atmel_sha204a_probe(struct i2c_client *client) + { + struct atmel_i2c_client_priv *i2c_priv; ++ const unsigned short *quality; + int ret; + + ret = atmel_i2c_probe(client); +@@ -171,11 +178,9 @@ static int atmel_sha204a_probe(struct i2 + i2c_priv->hwrng.name = dev_name(&client->dev); + i2c_priv->hwrng.read = atmel_sha204a_rng_read; + +- /* +- * According to review by Bill Cox [1], this HWRNG has very low entropy. +- * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html +- */ +- i2c_priv->hwrng.quality = 1; ++ quality = i2c_get_match_data(client); ++ if (quality) ++ i2c_priv->hwrng.quality = *quality; + + ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); + if (ret) +@@ -203,14 +208,14 @@ static void atmel_sha204a_remove(struct + } + + static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = { +- { .compatible = "atmel,atsha204", }, ++ { .compatible = "atmel,atsha204", .data = &atsha204_quality }, + { .compatible = "atmel,atsha204a", }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); + + static const struct i2c_device_id atmel_sha204a_id[] = { +- { "atsha204" }, ++ { "atsha204", (kernel_ulong_t)&atsha204_quality }, + { "atsha204a" }, + { /* sentinel */ } + }; diff --git a/queue-7.1/crypto-atmel-sha204a-fail-on-hwrng-registration-error-in-probe-path.patch b/queue-7.1/crypto-atmel-sha204a-fail-on-hwrng-registration-error-in-probe-path.patch new file mode 100644 index 0000000000..a528733002 --- /dev/null +++ b/queue-7.1/crypto-atmel-sha204a-fail-on-hwrng-registration-error-in-probe-path.patch @@ -0,0 +1,47 @@ +From 49e05bb00f2e8168695f7af4d694c39e1423e8a2 Mon Sep 17 00:00:00 2001 +From: Thorsten Blum +Date: Sun, 17 May 2026 18:27:40 +0200 +Subject: crypto: atmel-sha204a - fail on hwrng registration error in probe path + +From: Thorsten Blum + +commit 49e05bb00f2e8168695f7af4d694c39e1423e8a2 upstream. + +Commit 13909a0c8897 ("crypto: atmel-sha204a - provide the otp content") +overwrote the hwrng registration return value when creating the sysfs +group, which allowed atmel_sha204a_probe() to succeed even if +devm_hwrng_register() failed. + +Return immediately when devm_hwrng_register() fails, and report both +hwrng and sysfs registration errors with dev_err(). Adjust the sysfs +error log message for consistency. + +Fixes: 13909a0c8897 ("crypto: atmel-sha204a - provide the otp content") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/atmel-sha204a.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/crypto/atmel-sha204a.c ++++ b/drivers/crypto/atmel-sha204a.c +@@ -183,12 +183,14 @@ static int atmel_sha204a_probe(struct i2 + i2c_priv->hwrng.quality = *quality; + + ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng); +- if (ret) +- dev_warn(&client->dev, "failed to register RNG (%d)\n", ret); ++ if (ret) { ++ dev_err(&client->dev, "failed to register RNG (%d)\n", ret); ++ return ret; ++ } + + ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups); + if (ret) { +- dev_err(&client->dev, "failed to register sysfs entry\n"); ++ dev_err(&client->dev, "failed to create sysfs group (%d)\n", ret); + return ret; + } + diff --git a/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps-again.patch b/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps-again.patch new file mode 100644 index 0000000000..9fc30c0afc --- /dev/null +++ b/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps-again.patch @@ -0,0 +1,79 @@ +From 8005dc808bcce7d6cc2ae015a3cde1683bee602d Mon Sep 17 00:00:00 2001 +From: Thorsten Blum +Date: Mon, 27 Apr 2026 18:39:39 +0200 +Subject: crypto: caam - use print_hex_dump_devel to guard key hex dumps again + +From: Thorsten Blum + +commit 8005dc808bcce7d6cc2ae015a3cde1683bee602d upstream. + +Use print_hex_dump_devel() for dumping sensitive key material in +*_setkey() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG +is enabled. + +Fixes: 8d818c105501 ("crypto: caam/qi2 - add DPAA2-CAAM driver") +Fixes: 226853ac3ebe ("crypto: caam/qi2 - add skcipher algorithms") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/caam/caamalg_qi2.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -301,7 +301,7 @@ static int aead_setkey(struct crypto_aea + dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n", + keys.authkeylen + keys.enckeylen, keys.enckeylen, + keys.authkeylen); +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + ctx->adata.keylen = keys.authkeylen; +@@ -315,7 +315,7 @@ static int aead_setkey(struct crypto_aea + memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); + dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad + + keys.enckeylen, ctx->dir); +- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); + +@@ -732,7 +732,7 @@ static int gcm_setkey(struct crypto_aead + ret = aes_check_keylen(keylen); + if (ret) + return ret; +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -828,7 +828,7 @@ static int rfc4106_setkey(struct crypto_ + if (ret) + return ret; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -927,7 +927,7 @@ static int rfc4543_setkey(struct crypto_ + if (ret) + return ret; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -955,7 +955,7 @@ static int skcipher_setkey(struct crypto + u32 *desc; + const bool is_rfc3686 = alg->caam.rfc3686; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + ctx->cdata.keylen = keylen; diff --git a/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps.patch b/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps.patch new file mode 100644 index 0000000000..17cced7483 --- /dev/null +++ b/queue-7.1/crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps.patch @@ -0,0 +1,177 @@ +From 3f57657b6ea23f933371f2c2846322f441773cee Mon Sep 17 00:00:00 2001 +From: Thorsten Blum +Date: Mon, 27 Apr 2026 18:39:37 +0200 +Subject: crypto: caam - use print_hex_dump_devel to guard key hex dumps + +From: Thorsten Blum + +commit 3f57657b6ea23f933371f2c2846322f441773cee upstream. + +Use print_hex_dump_devel() for dumping sensitive key material in +*_setkey() and gen_split_key() to avoid leaking secrets at runtime when +CONFIG_DYNAMIC_DEBUG is enabled. + +Fixes: 6e005503199b ("crypto: caam - print debug messages at debug level") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/caam/caamalg.c | 12 ++++++------ + drivers/crypto/caam/caamalg_qi.c | 12 ++++++------ + drivers/crypto/caam/caamhash.c | 4 ++-- + drivers/crypto/caam/key_gen.c | 4 ++-- + 4 files changed, 16 insertions(+), 16 deletions(-) + +--- a/drivers/crypto/caam/caamalg.c ++++ b/drivers/crypto/caam/caamalg.c +@@ -603,7 +603,7 @@ static int aead_setkey(struct crypto_aea + dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", + keys.authkeylen + keys.enckeylen, keys.enckeylen, + keys.authkeylen); +- print_hex_dump_debug("key in @"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + /* +@@ -639,7 +639,7 @@ static int aead_setkey(struct crypto_aea + dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + + keys.enckeylen, ctx->dir); + +- print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); + +@@ -680,7 +680,7 @@ static int gcm_setkey(struct crypto_aead + if (err) + return err; + +- print_hex_dump_debug("key in @"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -701,7 +701,7 @@ static int rfc4106_setkey(struct crypto_ + if (err) + return err; + +- print_hex_dump_debug("key in @"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -727,7 +727,7 @@ static int rfc4543_setkey(struct crypto_ + if (err) + return err; + +- print_hex_dump_debug("key in @"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -754,7 +754,7 @@ static int skcipher_setkey(struct crypto + u32 *desc; + const bool is_rfc3686 = alg->caam.rfc3686; + +- print_hex_dump_debug("key in @"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + /* Here keylen is actual key length */ +--- a/drivers/crypto/caam/caamalg_qi.c ++++ b/drivers/crypto/caam/caamalg_qi.c +@@ -212,7 +212,7 @@ static int aead_setkey(struct crypto_aea + dev_dbg(jrdev, "keylen %d enckeylen %d authkeylen %d\n", + keys.authkeylen + keys.enckeylen, keys.enckeylen, + keys.authkeylen); +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + /* +@@ -248,7 +248,7 @@ static int aead_setkey(struct crypto_aea + ctx->adata.keylen_pad + keys.enckeylen, + ctx->dir); + +- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->adata.keylen_pad + keys.enckeylen, 1); + +@@ -371,7 +371,7 @@ static int gcm_setkey(struct crypto_aead + if (ret) + return ret; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -475,7 +475,7 @@ static int rfc4106_setkey(struct crypto_ + if (ret) + return ret; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -581,7 +581,7 @@ static int rfc4543_setkey(struct crypto_ + if (ret) + return ret; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + memcpy(ctx->key, key, keylen); +@@ -631,7 +631,7 @@ static int skcipher_setkey(struct crypto + const bool is_rfc3686 = alg->caam.rfc3686; + int ret = 0; + +- print_hex_dump_debug("key in @" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key in @" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + ctx->cdata.keylen = keylen; +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -505,7 +505,7 @@ static int axcbc_setkey(struct crypto_ah + DMA_TO_DEVICE); + ctx->adata.keylen = keylen; + +- print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", ++ print_hex_dump_devel("axcbc ctx.key@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, keylen, 1); + + return axcbc_set_sh_desc(ahash); +@@ -525,7 +525,7 @@ static int acmac_setkey(struct crypto_ah + ctx->adata.key_virt = key; + ctx->adata.keylen = keylen; + +- print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ", ++ print_hex_dump_devel("acmac ctx.key@" __stringify(__LINE__)" : ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + + return acmac_set_sh_desc(ahash); +--- a/drivers/crypto/caam/key_gen.c ++++ b/drivers/crypto/caam/key_gen.c +@@ -58,7 +58,7 @@ int gen_split_key(struct device *jrdev, + + dev_dbg(jrdev, "split keylen %d split keylen padded %d\n", + adata->keylen, adata->keylen_pad); +- print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); + + if (local_max > max_keylen) +@@ -113,7 +113,7 @@ int gen_split_key(struct device *jrdev, + wait_for_completion(&result.completion); + ret = result.err; + +- print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_out, + adata->keylen_pad, 1); + } diff --git a/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_commit.patch b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_commit.patch new file mode 100644 index 0000000000..aa3473e7e8 --- /dev/null +++ b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_commit.patch @@ -0,0 +1,65 @@ +From 5a1364da2f04217a36e2fdfa2db4ee025b383a20 Mon Sep 17 00:00:00 2001 +From: "Tycho Andersen (AMD)" +Date: Mon, 4 May 2026 10:51:45 -0600 +Subject: crypto: ccp - Do not initialize SNP for ioctl(SNP_COMMIT) + +From: Tycho Andersen (AMD) + +commit 5a1364da2f04217a36e2fdfa2db4ee025b383a20 upstream. + +Sashiko notes: + +> if SEV initialization fails and KVM is actively running normal VMs, could a +> userspace process trigger this code path via /dev/sev ioctls (e.g., +> SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN +> execution for an active VM trigger a general protection fault and crash the +> host? + +The SNP_COMMIT command does not require the firmware to be in any +particular state. Skip initializing it if it was previously uninitialized. + +The SEV-SNP firmware specification doc 56860 does not mention SNP_COMMIT in +Table 5 as a command that is allowed in the UNINIT state, but it is in fact +allowed and a future documentation update will reflect that. + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Reported-by: Sashiko +Assisted-by: Gemini:gemini-3.1-pro-preview +Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org +CC: +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2437,24 +2437,13 @@ cleanup: + + static int sev_ioctl_do_snp_commit(struct sev_issue_cmd *argp) + { +- struct sev_device *sev = psp_master->sev_data; + struct sev_data_snp_commit buf; +- bool shutdown_required = false; +- int ret, error; +- +- if (!sev->snp_initialized) { +- ret = snp_move_to_init_state(argp, &shutdown_required); +- if (ret) +- return ret; +- } ++ int ret; + + buf.len = sizeof(buf); + + ret = __sev_do_cmd_locked(SEV_CMD_SNP_COMMIT, &buf, &argp->error); + +- if (shutdown_required) +- __sev_snp_shutdown_locked(&error, false); +- + return ret; + } + diff --git a/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_config.patch b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_config.patch new file mode 100644 index 0000000000..e65c4e1e55 --- /dev/null +++ b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_config.patch @@ -0,0 +1,103 @@ +From 08f0e65e784c4b20e6e620dd4f68d8636073a3d2 Mon Sep 17 00:00:00 2001 +From: "Tycho Andersen (AMD)" +Date: Mon, 4 May 2026 10:51:47 -0600 +Subject: crypto: ccp - Do not initialize SNP for ioctl(SNP_CONFIG) + +From: Tycho Andersen (AMD) + +commit 08f0e65e784c4b20e6e620dd4f68d8636073a3d2 upstream. + +Sashiko notes: + +> if SEV initialization fails and KVM is actively running normal VMs, could a +> userspace process trigger this code path via /dev/sev ioctls (e.g., +> SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN +> execution for an active VM trigger a general protection fault and crash the +> host? + +Refuse to re-try initialization if SNP is not already initialized for +SNP_CONFIG. + +This is technically an ABI break: before if SNP initialization failed it +could be transparently retriggered by this ioctl, and if no VMs were +running, everything worked fine. Hopefully this is enough of a corner case +that nobody will notice, but someone does, there are a few options: + +* do something like symbol_get() for kvm and refuse to initialize if KVM is + loaded +* check each cpu's HSAVE_PA for non-zero data before re-initializing +* once initialization has failed, continue to refuse to initialize until + the ccp module is unloaded + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Reported-by: Sashiko +Assisted-by: Gemini:gemini-3.1-pro-preview +Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org +CC: +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 33 ++++----------------------------- + 1 file changed, 4 insertions(+), 29 deletions(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -1727,21 +1727,6 @@ static int sev_move_to_init_state(struct + return 0; + } + +-static int snp_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) +-{ +- int error, rc; +- +- rc = __sev_snp_init_locked(&error, 0); +- if (rc) { +- argp->error = SEV_RET_INVALID_PLATFORM_STATE; +- return rc; +- } +- +- *shutdown_required = true; +- +- return 0; +-} +- + static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable) + { + int state, rc; +@@ -2451,8 +2436,6 @@ static int sev_ioctl_do_snp_set_config(s + { + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_snp_config config; +- bool shutdown_required = false; +- int ret, error; + + if (!argp->data) + return -EINVAL; +@@ -2460,21 +2443,13 @@ static int sev_ioctl_do_snp_set_config(s + if (!writable) + return -EPERM; + ++ if (!sev->snp_initialized) ++ return -ENODEV; ++ + if (copy_from_user(&config, (void __user *)argp->data, sizeof(config))) + return -EFAULT; + +- if (!sev->snp_initialized) { +- ret = snp_move_to_init_state(argp, &shutdown_required); +- if (ret) +- return ret; +- } +- +- ret = __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); +- +- if (shutdown_required) +- __sev_snp_shutdown_locked(&error, false); +- +- return ret; ++ return __sev_do_cmd_locked(SEV_CMD_SNP_CONFIG, &config, &argp->error); + } + + static int sev_ioctl_do_snp_vlek_load(struct sev_issue_cmd *argp, bool writable) diff --git a/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_vlek_load.patch b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_vlek_load.patch new file mode 100644 index 0000000000..39720ba278 --- /dev/null +++ b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-ioctl-snp_vlek_load.patch @@ -0,0 +1,84 @@ +From f91e9dbb5845d1e5abf1028e6df57dcf61583e1b Mon Sep 17 00:00:00 2001 +From: "Tycho Andersen (AMD)" +Date: Mon, 4 May 2026 10:51:46 -0600 +Subject: crypto: ccp - Do not initialize SNP for ioctl(SNP_VLEK_LOAD) + +From: Tycho Andersen (AMD) + +commit f91e9dbb5845d1e5abf1028e6df57dcf61583e1b upstream. + +Sashiko notes: + +> if SEV initialization fails and KVM is actively running normal VMs, could a +> userspace process trigger this code path via /dev/sev ioctls (e.g., +> SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN +> execution for an active VM trigger a general protection fault and crash the +> host? + +The SEV firmware docs for SNP_VLEK_LOAD note: + +> On SNP_SHUTDOWN, the VLEK is deleted. + +That is, the initialization/shutdown wrapper here is pointless, because the +firmware immediately throws away the key anyway. Instead, refuse to do +anything if SNP has not been previously initialized. + +This is an ABI break: before, this was a no-op and almost certainly a +mistake by userspace, and now it returns -ENODEV. ABI compatibility could be +maintained here by simply returning 0 in the check instead. + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Reported-by: Sashiko +Assisted-by: Gemini:gemini-3.1-pro-preview +Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org +CC: +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 17 ++++------------- + 1 file changed, 4 insertions(+), 13 deletions(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -2481,9 +2481,8 @@ static int sev_ioctl_do_snp_vlek_load(st + { + struct sev_device *sev = psp_master->sev_data; + struct sev_user_data_snp_vlek_load input; +- bool shutdown_required = false; +- int ret, error; + void *blob; ++ int ret; + + if (!argp->data) + return -EINVAL; +@@ -2491,6 +2490,9 @@ static int sev_ioctl_do_snp_vlek_load(st + if (!writable) + return -EPERM; + ++ if (!sev->snp_initialized) ++ return -ENODEV; ++ + if (copy_from_user(&input, u64_to_user_ptr(argp->data), sizeof(input))) + return -EFAULT; + +@@ -2504,18 +2506,7 @@ static int sev_ioctl_do_snp_vlek_load(st + + input.vlek_wrapped_address = __psp_pa(blob); + +- if (!sev->snp_initialized) { +- ret = snp_move_to_init_state(argp, &shutdown_required); +- if (ret) +- goto cleanup; +- } +- + ret = __sev_do_cmd_locked(SEV_CMD_SNP_VLEK_LOAD, &input, &argp->error); +- +- if (shutdown_required) +- __sev_snp_shutdown_locked(&error, false); +- +-cleanup: + kfree(blob); + + return ret; diff --git a/queue-7.1/crypto-ccp-do-not-initialize-snp-for-sev-ioctls.patch b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-sev-ioctls.patch new file mode 100644 index 0000000000..f703d7fc21 --- /dev/null +++ b/queue-7.1/crypto-ccp-do-not-initialize-snp-for-sev-ioctls.patch @@ -0,0 +1,67 @@ +From fb1758e74b8061aacfbce7bbb7a7cc650537e167 Mon Sep 17 00:00:00 2001 +From: "Tycho Andersen (AMD)" +Date: Mon, 4 May 2026 10:51:44 -0600 +Subject: crypto: ccp - Do not initialize SNP for SEV ioctls + +From: Tycho Andersen (AMD) + +commit fb1758e74b8061aacfbce7bbb7a7cc650537e167 upstream. + +Sashiko notes: + +> if SEV initialization fails and KVM is actively running normal VMs, could a +> userspace process trigger this code path via /dev/sev ioctls (e.g., +> SEV_PDH_GEN) and zero out MSR_VM_HSAVE_PA globally? Would the next VMRUN +> execution for an active VM trigger a general protection fault and crash the +> host? + +sev_move_to_init_state() is called for ioctls requiring only SEV firmware: +SEV_PEK_GEN, SEV_PDH_GEN, SEV_PEK_CSR, SEV_PEK_CERT_IMPORT, and +SEV_PDH_CERT_EXPORT. After the firmware command, it does SEV_SHUTDOWN on +the SEV firmware. Since these commands do not require SNP to be +initialized, skip it by calling __sev_platform_init_locked() which only +initializes the SEV firmware. This way SNP is not Initialized at all, and +HSAVE_PA is not cleared. + +The previous code saved any SEV initialization firmware error to +init_args.error and then threw it away and hardcoded the return value of +INVALID_PLATFORM_STATE regardless of the real firmware error. This patch +changes it to surface the underlying error, which is hopefully both more +useful and doesn't cause any problems. + +Note that it is still safe to call __sev_firmware_shutdown() directly: it +calls __sev_snp_shutdown_locked(), which skips SNP shutdown if SNP was not +initialized. + +Fixes: ceac7fb89e8d ("crypto: ccp - Ensure implicit SEV/SNP init and shutdown in ioctls") +Reported-by: Sashiko +Assisted-by: Gemini:gemini-3.1-pro-preview +Link: https://sashiko.dev/#/patchset/20260324161301.1353976-1-tycho%40kernel.org +CC: +Signed-off-by: Tycho Andersen (AMD) +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/ccp/sev-dev.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/drivers/crypto/ccp/sev-dev.c ++++ b/drivers/crypto/ccp/sev-dev.c +@@ -1716,14 +1716,11 @@ static int sev_get_platform_state(int *s + + static int sev_move_to_init_state(struct sev_issue_cmd *argp, bool *shutdown_required) + { +- struct sev_platform_init_args init_args = {0}; + int rc; + +- rc = _sev_platform_init_locked(&init_args); +- if (rc) { +- argp->error = SEV_RET_INVALID_PLATFORM_STATE; ++ rc = __sev_platform_init_locked(&argp->error); ++ if (rc) + return rc; +- } + + *shutdown_required = true; + diff --git a/queue-7.1/crypto-chacha20poly1305-validate-poly1305-template-argument.patch b/queue-7.1/crypto-chacha20poly1305-validate-poly1305-template-argument.patch new file mode 100644 index 0000000000..5069a044fe --- /dev/null +++ b/queue-7.1/crypto-chacha20poly1305-validate-poly1305-template-argument.patch @@ -0,0 +1,64 @@ +From 265b861bece38318b8e0fc8fac0643d4ef906d31 Mon Sep 17 00:00:00 2001 +From: Xiaonan Zhao +Date: Tue, 26 May 2026 18:11:43 +0800 +Subject: crypto: chacha20poly1305 - validate poly1305 template argument + +From: Xiaonan Zhao + +commit 265b861bece38318b8e0fc8fac0643d4ef906d31 upstream. + +chachapoly_create() still accepts the compatibility poly1305 parameter +in the template name, but it assumes the second template argument is +always present and immediately passes it to strcmp(). + +When the argument is missing, crypto_attr_alg_name() returns an error +pointer. Check for that before comparing the name so malformed template +instantiations fail with an error instead of dereferencing the error +pointer in strcmp(). + +This matches the surrounding Crypto API template pattern where +crypto_attr_alg_name() results are validated before string-specific use. + +Fixes: a298765e28ad ("crypto: chacha20poly1305 - Use lib/crypto poly1305") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Co-developed-by: Luxing Yin +Signed-off-by: Luxing Yin +Signed-off-by: Xiaonan Zhao +Signed-off-by: Ren Wei +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/chacha20poly1305.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/crypto/chacha20poly1305.c ++++ b/crypto/chacha20poly1305.c +@@ -375,6 +375,7 @@ static int chachapoly_create(struct cryp + struct aead_instance *inst; + struct chachapoly_instance_ctx *ctx; + struct skcipher_alg_common *chacha; ++ const char *poly_name; + int err; + + if (ivsize > CHACHAPOLY_IV_SIZE) +@@ -396,9 +397,15 @@ static int chachapoly_create(struct cryp + goto err_free_inst; + chacha = crypto_spawn_skcipher_alg_common(&ctx->chacha); + ++ poly_name = crypto_attr_alg_name(tb[2]); ++ if (IS_ERR(poly_name)) { ++ err = PTR_ERR(poly_name); ++ goto err_free_inst; ++ } ++ + err = -EINVAL; +- if (strcmp(crypto_attr_alg_name(tb[2]), "poly1305") && +- strcmp(crypto_attr_alg_name(tb[2]), "poly1305-generic")) ++ if (strcmp(poly_name, "poly1305") && ++ strcmp(poly_name, "poly1305-generic")) + goto err_free_inst; + /* Need 16-byte IV size, including Initial Block Counter value */ + if (chacha->ivsize != CHACHA_IV_SIZE) diff --git a/queue-7.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch b/queue-7.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch new file mode 100644 index 0000000000..54ea757490 --- /dev/null +++ b/queue-7.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,235 @@ +From 7811ec9e973d2c9e465083699f0c8240b98cb8c4 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Fri, 29 May 2026 15:04:30 -0700 +Subject: crypto: crypto4xx - Remove insecure and unused rng_alg + +From: Eric Biggers + +commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream. + +Remove crypto4xx_rng, as it is insecure and unused: + +- It has only a 64-bit security strength, which is highly inadequate. + This can be seen by the fact that crypto4xx_hw_init() seeds it with + only 64 bits of entropy, and the fact that the original commit + mentions that it implements ANSI X9.17 Annex C. + + Another issue was that this driver didn't implement the crypto_rng API + correctly, as crypto4xx_prng_generate() didn't return 0 on success. + +- No user of this code is known. It's usable only theoretically via the + "rng" algorithm type of AF_ALG. But userspace actually just uses the + actual Linux RNG (/dev/random etc) instead. And rng_algs don't + contribute entropy to the actual Linux RNG either. (This may have + been confused with hwrng, which does contribute entropy.) + +Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Acked-by: Christian Lamparter +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/Kconfig | 1 + drivers/crypto/amcc/crypto4xx_core.c | 88 -------------------------------- + drivers/crypto/amcc/crypto4xx_core.h | 4 - + drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ---- + 4 files changed, 104 deletions(-) + +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -301,7 +301,6 @@ config CRYPTO_DEV_PPC4XX + select CRYPTO_CCM + select CRYPTO_CTR + select CRYPTO_GCM +- select CRYPTO_RNG + select CRYPTO_SKCIPHER + help + This option allows you to have support for AMCC crypto acceleration. +--- a/drivers/crypto/amcc/crypto4xx_core.c ++++ b/drivers/crypto/amcc/crypto4xx_core.c +@@ -31,11 +31,9 @@ + #include + #include + #include +-#include + #include + #include + #include +-#include + #include + #include "crypto4xx_reg_def.h" + #include "crypto4xx_core.h" +@@ -985,10 +983,6 @@ static int crypto4xx_register_alg(struct + rc = crypto_register_aead(&alg->alg.u.aead); + break; + +- case CRYPTO_ALG_TYPE_RNG: +- rc = crypto_register_rng(&alg->alg.u.rng); +- break; +- + default: + rc = crypto_register_skcipher(&alg->alg.u.cipher); + break; +@@ -1014,10 +1008,6 @@ static void crypto4xx_unregister_alg(str + crypto_unregister_aead(&alg->alg.u.aead); + break; + +- case CRYPTO_ALG_TYPE_RNG: +- crypto_unregister_rng(&alg->alg.u.rng); +- break; +- + default: + crypto_unregister_skcipher(&alg->alg.u.cipher); + } +@@ -1076,69 +1066,6 @@ static irqreturn_t crypto4xx_ce_interrup + PPC4XX_TMO_ERR_INT); + } + +-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev, +- u8 *data, unsigned int max) +-{ +- unsigned int i, curr = 0; +- u32 val[2]; +- +- do { +- /* trigger PRN generation */ +- writel(PPC4XX_PRNG_CTRL_AUTO_EN, +- dev->ce_base + CRYPTO4XX_PRNG_CTRL); +- +- for (i = 0; i < 1024; i++) { +- /* usually 19 iterations are enough */ +- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) & +- CRYPTO4XX_PRNG_STAT_BUSY)) +- continue; +- +- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0); +- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1); +- break; +- } +- if (i == 1024) +- return -ETIMEDOUT; +- +- if ((max - curr) >= 8) { +- memcpy(data, &val, 8); +- data += 8; +- curr += 8; +- } else { +- /* copy only remaining bytes */ +- memcpy(data, &val, max - curr); +- break; +- } +- } while (curr < max); +- +- return curr; +-} +- +-static int crypto4xx_prng_generate(struct crypto_rng *tfm, +- const u8 *src, unsigned int slen, +- u8 *dstn, unsigned int dlen) +-{ +- struct rng_alg *alg = crypto_rng_alg(tfm); +- struct crypto4xx_alg *amcc_alg; +- struct crypto4xx_device *dev; +- int ret; +- +- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng); +- dev = amcc_alg->dev; +- +- mutex_lock(&dev->core_dev->rng_lock); +- ret = ppc4xx_prng_data_read(dev, dstn, dlen); +- mutex_unlock(&dev->core_dev->rng_lock); +- return ret; +-} +- +- +-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed, +- unsigned int slen) +-{ +- return 0; +-} +- + /* + * Supported Crypto Algorithms + */ +@@ -1268,18 +1195,6 @@ static struct crypto4xx_alg_common crypt + .cra_module = THIS_MODULE, + }, + } }, +- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = { +- .base = { +- .cra_name = "stdrng", +- .cra_driver_name = "crypto4xx_rng", +- .cra_priority = 300, +- .cra_ctxsize = 0, +- .cra_module = THIS_MODULE, +- }, +- .generate = crypto4xx_prng_generate, +- .seed = crypto4xx_prng_seed, +- .seedsize = 0, +- } }, + }; + + /* +@@ -1353,9 +1268,6 @@ static int crypto4xx_probe(struct platfo + core_dev->dev->core_dev = core_dev; + core_dev->dev->is_revb = is_revb; + core_dev->device = dev; +- rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock); +- if (rc) +- return rc; + spin_lock_init(&core_dev->lock); + INIT_LIST_HEAD(&core_dev->dev->alg_list); + ratelimit_default_init(&core_dev->dev->aead_ratelimit); +--- a/drivers/crypto/amcc/crypto4xx_core.h ++++ b/drivers/crypto/amcc/crypto4xx_core.h +@@ -14,10 +14,8 @@ + #define __CRYPTO4XX_CORE_H__ + + #include +-#include + #include + #include +-#include + #include + #include "crypto4xx_reg_def.h" + #include "crypto4xx_sa.h" +@@ -111,7 +109,6 @@ struct crypto4xx_core_device { + u32 irq; + struct tasklet_struct tasklet; + spinlock_t lock; +- struct mutex rng_lock; + }; + + struct crypto4xx_ctx { +@@ -135,7 +132,6 @@ struct crypto4xx_alg_common { + union { + struct skcipher_alg cipher; + struct aead_alg aead; +- struct rng_alg rng; + } u; + }; + +--- a/drivers/crypto/amcc/crypto4xx_reg_def.h ++++ b/drivers/crypto/amcc/crypto4xx_reg_def.h +@@ -90,20 +90,9 @@ + #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8 + #define CRYPTO4XX_ENDIAN_CFG 0x000600d8 + +-#define CRYPTO4XX_PRNG_STAT 0x00070000 +-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1 + #define CRYPTO4XX_PRNG_CTRL 0x00070004 + #define CRYPTO4XX_PRNG_SEED_L 0x00070008 + #define CRYPTO4XX_PRNG_SEED_H 0x0007000c +- +-#define CRYPTO4XX_PRNG_RES_0 0x00070020 +-#define CRYPTO4XX_PRNG_RES_1 0x00070024 +-#define CRYPTO4XX_PRNG_RES_2 0x00070028 +-#define CRYPTO4XX_PRNG_RES_3 0x0007002C +- +-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030 +-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034 +- + /* + * Initialize CRYPTO ENGINE registers, and memory bases. + */ diff --git a/queue-7.1/crypto-drbg-fix-drbg_max_addtl-on-64-bit-kernels.patch b/queue-7.1/crypto-drbg-fix-drbg_max_addtl-on-64-bit-kernels.patch new file mode 100644 index 0000000000..f0875ac87b --- /dev/null +++ b/queue-7.1/crypto-drbg-fix-drbg_max_addtl-on-64-bit-kernels.patch @@ -0,0 +1,60 @@ +From 6f49f00c981bbb9ef602966f19bfdbef46b681d2 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 19 Apr 2026 23:33:48 -0700 +Subject: crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels + +From: Eric Biggers + +commit 6f49f00c981bbb9ef602966f19bfdbef46b681d2 upstream. + +On 64-bit kernels, drbg_max_addtl() returns 2**35 bytes. That's too +large, for two reasons: + +1. SP800-90A says the maximum limit is 2**35 *bits*, not 2**35 bytes. + So the implemented limit has confused bits and bytes. + +2. When drbg_kcapi_hash() calls crypto_shash_update() on the additional + information string, the length is implicitly cast to 'unsigned int'. + That truncates the additional information string to U32_MAX bytes. + +Fix the maximum additional information string length to always be +U32_MAX - 1, causing an error to be returned for any longer lengths. + +Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + include/crypto/drbg.h | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +--- a/include/crypto/drbg.h ++++ b/include/crypto/drbg.h +@@ -148,19 +148,15 @@ static inline size_t drbg_max_request_by + return (1 << 16); + } + ++/* ++ * SP800-90A allows implementations to support additional info / personalization ++ * strings of up to 2**35 bits. Implementations can have a smaller maximum. We ++ * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a ++ * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. ++ */ + static inline size_t drbg_max_addtl(struct drbg_state *drbg) + { +- /* SP800-90A requires 2**35 bytes additional info str / pers str */ +-#if (__BITS_PER_LONG == 32) +- /* +- * SP800-90A allows smaller maximum numbers to be returned -- we +- * return SIZE_MAX - 1 to allow the verification of the enforcement +- * of this value in drbg_healthcheck_sanity. +- */ +- return (SIZE_MAX - 1); +-#else +- return (1UL<<35); +-#endif ++ return U32_MAX - 1; + } + + static inline size_t drbg_max_requests(struct drbg_state *drbg) diff --git a/queue-7.1/crypto-drbg-fix-ineffective-sanity-check.patch b/queue-7.1/crypto-drbg-fix-ineffective-sanity-check.patch new file mode 100644 index 0000000000..7effad99e0 --- /dev/null +++ b/queue-7.1/crypto-drbg-fix-ineffective-sanity-check.patch @@ -0,0 +1,51 @@ +From 040ad83b0e8aa065fd2fc641cacba8491a8b186d Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 19 Apr 2026 23:33:47 -0700 +Subject: crypto: drbg - Fix ineffective sanity check + +From: Eric Biggers + +commit 040ad83b0e8aa065fd2fc641cacba8491a8b186d upstream. + +Fix drbg_healthcheck_sanity() to correctly check the return value of +drbg_generate(). drbg_generate() returns 0 on success, or a negative +errno value on failure. drbg_healthcheck_sanity() incorrectly assumed +that it returned a positive value on success. + +This didn't make the sanity check fail, but it made it ineffective. + +Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/drbg.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/crypto/drbg.c ++++ b/crypto/drbg.c +@@ -1737,7 +1737,6 @@ static int drbg_kcapi_seed(struct crypto + */ + static inline int __init drbg_healthcheck_sanity(void) + { +- int len = 0; + #define OUTBUFLEN 16 + unsigned char buf[OUTBUFLEN]; + struct drbg_state *drbg = NULL; +@@ -1782,11 +1781,11 @@ static inline int __init drbg_healthchec + max_request_bytes = drbg_max_request_bytes(drbg); + drbg_string_fill(&addtl, buf, max_addtllen + 1); + /* overflow addtllen with additional info string */ +- len = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); +- BUG_ON(0 < len); ++ ret = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); ++ BUG_ON(ret == 0); + /* overflow max_bits */ +- len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL); +- BUG_ON(0 < len); ++ ret = drbg_generate(drbg, buf, max_request_bytes + 1, NULL); ++ BUG_ON(ret == 0); + + /* overflow max addtllen with personalization string */ + ret = drbg_seed(drbg, &addtl, false); diff --git a/queue-7.1/crypto-drbg-fix-misaligned-writes-in-ctr_drbg-and-hash_drbg.patch b/queue-7.1/crypto-drbg-fix-misaligned-writes-in-ctr_drbg-and-hash_drbg.patch new file mode 100644 index 0000000000..e6f5887eee --- /dev/null +++ b/queue-7.1/crypto-drbg-fix-misaligned-writes-in-ctr_drbg-and-hash_drbg.patch @@ -0,0 +1,102 @@ +From ddc4dedb9ba3c8eecbc8c050fffd46d1b7e75c21 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 19 Apr 2026 23:33:46 -0700 +Subject: crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG + +From: Eric Biggers + +commit ddc4dedb9ba3c8eecbc8c050fffd46d1b7e75c21 upstream. + +drbg_cpu_to_be32() is being used to do a plain write to a byte array, +which doesn't have any alignment guarantee. This can cause a misaligned +write. Replace it with the correct function, put_unaligned_be32(). + +Fixes: 72f3e00dd67e ("crypto: drbg - replace int2byte with cpu_to_be") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/df_sp80090a.c | 7 ++++--- + crypto/drbg.c | 3 ++- + include/crypto/internal/drbg.h | 18 ------------------ + 3 files changed, 6 insertions(+), 22 deletions(-) + +--- a/crypto/df_sp80090a.c ++++ b/crypto/df_sp80090a.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -141,10 +142,10 @@ int crypto_drbg_ctr_df(struct aes_enckey + /* 10.4.2 step 2 -- calculate the entire length of all input data */ + list_for_each_entry(seed, seedlist, list) + inputlen += seed->len; +- drbg_cpu_to_be32(inputlen, &L_N[0]); ++ put_unaligned_be32(inputlen, &L_N[0]); + + /* 10.4.2 step 3 */ +- drbg_cpu_to_be32(bytes_to_return, &L_N[4]); ++ put_unaligned_be32(bytes_to_return, &L_N[4]); + + /* 10.4.2 step 5: length is L_N, input_string, one byte, padding */ + padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes); +@@ -175,7 +176,7 @@ int crypto_drbg_ctr_df(struct aes_enckey + * holds zeros after allocation -- even the increment of i + * is irrelevant as the increment remains within length of i + */ +- drbg_cpu_to_be32(i, iv); ++ put_unaligned_be32(i, iv); + /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ + drbg_ctr_bcc(aeskey, temp + templen, K, &bcc_list, + blocklen_bytes, keylen); +--- a/crypto/drbg.c ++++ b/crypto/drbg.c +@@ -103,6 +103,7 @@ + #include + #include + #include ++#include + + /*************************************************************** + * Backend cipher definitions available to DRBG +@@ -601,7 +602,7 @@ static int drbg_hash_df(struct drbg_stat + + /* 10.4.1 step 3 */ + input[0] = 1; +- drbg_cpu_to_be32((outlen * 8), &input[1]); ++ put_unaligned_be32(outlen * 8, &input[1]); + + /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ + drbg_string_fill(&data, input, 5); +--- a/include/crypto/internal/drbg.h ++++ b/include/crypto/internal/drbg.h +@@ -10,24 +10,6 @@ + #define _INTERNAL_DRBG_H + + /* +- * Convert an integer into a byte representation of this integer. +- * The byte representation is big-endian +- * +- * @val value to be converted +- * @buf buffer holding the converted integer -- caller must ensure that +- * buffer size is at least 32 bit +- */ +-static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf) +-{ +- struct s { +- __be32 conv; +- }; +- struct s *conversion = (struct s *)buf; +- +- conversion->conv = cpu_to_be32(val); +-} +- +-/* + * Concatenation Helper and string operation helper + * + * SP800-90A requires the concatenation of different data. To avoid copying diff --git a/queue-7.1/crypto-drbg-fix-returning-success-on-failure-in-ctr_drbg.patch b/queue-7.1/crypto-drbg-fix-returning-success-on-failure-in-ctr_drbg.patch new file mode 100644 index 0000000000..7d688a4e1c --- /dev/null +++ b/queue-7.1/crypto-drbg-fix-returning-success-on-failure-in-ctr_drbg.patch @@ -0,0 +1,32 @@ +From 39a31ad9e2a5ed7e9c9c6f711dca96c8c8f5f26b Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 19 Apr 2026 23:33:45 -0700 +Subject: crypto: drbg - Fix returning success on failure in CTR_DRBG + +From: Eric Biggers + +commit 39a31ad9e2a5ed7e9c9c6f711dca96c8c8f5f26b upstream. + +drbg_ctr_generate() sometimes returns success when it fails, leaving the +output buffer uninitialized. Fix it. + +Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/drbg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/crypto/drbg.c ++++ b/crypto/drbg.c +@@ -377,7 +377,7 @@ static int drbg_ctr_generate(struct drbg + if (addtl && !list_empty(addtl)) { + ret = drbg_ctr_update(drbg, addtl, 2); + if (ret) +- return 0; ++ return ret; + } + + /* 10.2.1.5.2 step 4.1 */ diff --git a/queue-7.1/crypto-drbg-fix-the-fips_enabled-priority-boost.patch b/queue-7.1/crypto-drbg-fix-the-fips_enabled-priority-boost.patch new file mode 100644 index 0000000000..6320a31ff9 --- /dev/null +++ b/queue-7.1/crypto-drbg-fix-the-fips_enabled-priority-boost.patch @@ -0,0 +1,39 @@ +From a8a1f93080efc83a9ff8452954429ae379e9e614 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 19 Apr 2026 23:33:49 -0700 +Subject: crypto: drbg - Fix the fips_enabled priority boost + +From: Eric Biggers + +commit a8a1f93080efc83a9ff8452954429ae379e9e614 upstream. + +When fips_enabled=1, it seems to have been intended for one of the +algorithms defined in crypto/drbg.c to be the highest priority "stdrng" +algorithm, so that it is what is used by "stdrng" users. + +However, the code only boosts the priority to 400, which is less than +the priority 500 used in drivers/crypto/caam/caamprng.c. Thus, the CAAM +RNG could be used instead. + +Fix this by boosting the priority by 2000 instead of 200. + +Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/drbg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/crypto/drbg.c ++++ b/crypto/drbg.c +@@ -1832,7 +1832,7 @@ static inline void __init drbg_fill_arra + * it is selected. + */ + if (fips_enabled) +- alg->base.cra_priority += 200; ++ alg->base.cra_priority += 2000; + + alg->base.cra_ctxsize = sizeof(struct drbg_state); + alg->base.cra_module = THIS_MODULE; diff --git a/queue-7.1/crypto-ecc-fix-carry-overflow-in-vli-multiplication.patch b/queue-7.1/crypto-ecc-fix-carry-overflow-in-vli-multiplication.patch new file mode 100644 index 0000000000..ee36010fb2 --- /dev/null +++ b/queue-7.1/crypto-ecc-fix-carry-overflow-in-vli-multiplication.patch @@ -0,0 +1,98 @@ +From 27b536a2ec8e2f85a0380c2d13c9ecbc7aaab406 Mon Sep 17 00:00:00 2001 +From: Anastasia Tishchenko +Date: Wed, 13 May 2026 13:57:40 +0300 +Subject: crypto: ecc - Fix carry overflow in vli multiplication + +From: Anastasia Tishchenko + +commit 27b536a2ec8e2f85a0380c2d13c9ecbc7aaab406 upstream. + +The carry flag calculation fails when r01.m_high is saturated +(0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows. + +The condition (r01.m_high < product.m_high) doesn't handle the case +where r01.m_high == product.m_high and an additional carry exists +from lower-bit overflow. + +When commit 3c4b23901a0c ("crypto: ecdh - Add ECDH software support") +introduced crypto/ecc.c, it split the muladd() function in the +micro-ecc library into separate mul_64_64() and add_128_128() helpers. +It seems the check got lost in translation. + +Add proper handling for this boundary by accounting for the carry +from the lower addition. + +Fixes: 3c4b23901a0c ("crypto: ecdh - Add ECDH software support") +Signed-off-by: Anastasia Tishchenko +Cc: stable@vger.kernel.org # v4.8+ +Reviewed-by: Lukas Wunner +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/ecc.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +--- a/crypto/ecc.c ++++ b/crypto/ecc.c +@@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64 + return result; + } + +-static uint128_t add_128_128(uint128_t a, uint128_t b) ++/* Calculate addition with overflow checking. Returns true on wrap-around, ++ * false otherwise. ++ */ ++static bool check_add_128_128_overflow(uint128_t *result, uint128_t a, ++ uint128_t b) + { +- uint128_t result; ++ bool carry; + +- result.m_low = a.m_low + b.m_low; +- result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); ++ result->m_low = a.m_low + b.m_low; ++ carry = (result->m_low < a.m_low); + +- return result; ++ result->m_high = a.m_high + b.m_high + carry; ++ ++ /* Using constant-time bitwise arithmetic to prevent timing ++ * side-channels. ++ */ ++ carry = (result->m_high < a.m_high) | ++ ((result->m_high == a.m_high) & carry); ++ ++ return carry; + } + + static void vli_mult(u64 *result, const u64 *left, const u64 *right, +@@ -425,9 +437,7 @@ static void vli_mult(u64 *result, const + uint128_t product; + + product = mul_64_64(left[i], right[k - i]); +- +- r01 = add_128_128(r01, product); +- r2 += (r01.m_high < product.m_high); ++ r2 += check_add_128_128_overflow(&r01, r01, product); + } + + result[k] = r01.m_low; +@@ -450,7 +460,7 @@ static void vli_umult(u64 *result, const + uint128_t product; + + product = mul_64_64(left[k], right); +- r01 = add_128_128(r01, product); ++ check_add_128_128_overflow(&r01, r01, product); + /* no carry */ + result[k] = r01.m_low; + r01.m_low = r01.m_high; +@@ -487,8 +497,7 @@ static void vli_square(u64 *result, cons + product.m_low <<= 1; + } + +- r01 = add_128_128(r01, product); +- r2 += (r01.m_high < product.m_high); ++ r2 += check_add_128_128_overflow(&r01, r01, product); + } + + result[k] = r01.m_low; diff --git a/queue-7.1/crypto-hisi-trng-remove-crypto_rng-interface.patch b/queue-7.1/crypto-hisi-trng-remove-crypto_rng-interface.patch new file mode 100644 index 0000000000..65fdaf20f0 --- /dev/null +++ b/queue-7.1/crypto-hisi-trng-remove-crypto_rng-interface.patch @@ -0,0 +1,404 @@ +From 216a7795ec210bdabd5dad42323eee70bbfc8d90 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sat, 30 May 2026 13:26:23 -0700 +Subject: crypto: hisi-trng - Remove crypto_rng interface + +From: Eric Biggers + +commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream. + +drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through +two completely separate interfaces, crypto_rng and hwrng. However, the +implementation of this is buggy because it permits generation operations +from these interfaces to run concurrently with each other, accessing the +same registers. That is, hisi_trng_generate() synchronizes with itself +but not with hisi_trng_read(). This results in potential repetition of +output from the RNG, output of non-random values, etc. + +Fortunately, there's actually no point in hardware RNG drivers +implementing the crypto_rng interface. It's not actually used by +anything besides the "rng" algorithm type of AF_ALG, which in turn is +not actually used in practice. Other crypto_rng hardware drivers are +likewise being phased out, leaving just the hwrng support. + +Thus, remove it to simplify the code and avoid conflict (and confusion) +with the hwrng interface which is the one that actually matters. + +Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/hisilicon/Kconfig | 1 + drivers/crypto/hisilicon/trng/trng.c | 296 ----------------------------------- + 2 files changed, 2 insertions(+), 295 deletions(-) + +--- a/drivers/crypto/hisilicon/Kconfig ++++ b/drivers/crypto/hisilicon/Kconfig +@@ -80,6 +80,5 @@ config CRYPTO_DEV_HISI_TRNG + tristate "Support for HISI TRNG Driver" + depends on ARM64 && ACPI + select HW_RANDOM +- select CRYPTO_RNG + help + Support for HiSilicon TRNG Driver. +--- a/drivers/crypto/hisilicon/trng/trng.c ++++ b/drivers/crypto/hisilicon/trng/trng.c +@@ -1,234 +1,27 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright (c) 2019 HiSilicon Limited. */ + +-#include + #include +-#include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include + #include + + #define HISI_TRNG_REG 0x00F0 + #define HISI_TRNG_BYTES 4 + #define HISI_TRNG_QUALITY 512 +-#define HISI_TRNG_VERSION 0x01B8 +-#define HISI_TRNG_VER_V1 GENMASK(31, 0) + #define SLEEP_US 10 + #define TIMEOUT_US 10000 +-#define SW_DRBG_NUM_SHIFT 2 +-#define SW_DRBG_KEY_BASE 0x082C +-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT)) +-#define SW_DRBG_SEED_REGS_NUM 12 +-#define SW_DRBG_SEED_SIZE 48 +-#define SW_DRBG_BLOCKS 0x0830 +-#define SW_DRBG_INIT 0x0834 +-#define SW_DRBG_GEN 0x083c +-#define SW_DRBG_STATUS 0x0840 +-#define SW_DRBG_BLOCKS_NUM 4095 +-#define SW_DRBG_DATA_BASE 0x0850 +-#define SW_DRBG_DATA_NUM 4 +-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT)) +-#define SW_DRBG_BYTES 16 +-#define SW_DRBG_ENABLE_SHIFT 12 +-#define SEED_SHIFT_24 24 +-#define SEED_SHIFT_16 16 +-#define SEED_SHIFT_8 8 +-#define SW_MAX_RANDOM_BYTES 65520 +- +-struct hisi_trng_list { +- struct mutex lock; +- struct list_head list; +- bool is_init; +-}; + + struct hisi_trng { + void __iomem *base; +- struct hisi_trng_list *trng_list; +- struct list_head list; + struct hwrng rng; +- u32 ver; +- u32 ctx_num; +- /* The bytes of the random number generated since the last seeding. */ +- u32 random_bytes; +- struct mutex lock; +-}; +- +-struct hisi_trng_ctx { +- struct hisi_trng *trng; + }; + +-static atomic_t trng_active_devs; +-static struct hisi_trng_list trng_devices; +-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait); +- +-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed) +-{ +- u32 val, seed_reg, i; +- int ret; +- +- writel(0x0, trng->base + SW_DRBG_BLOCKS); +- +- for (i = 0; i < SW_DRBG_SEED_SIZE; +- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) { +- val = seed[i] << SEED_SHIFT_24; +- val |= seed[i + 1UL] << SEED_SHIFT_16; +- val |= seed[i + 2UL] << SEED_SHIFT_8; +- val |= seed[i + 3UL]; +- +- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM; +- writel(val, trng->base + SW_DRBG_SEED(seed_reg)); +- } +- +- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT), +- trng->base + SW_DRBG_BLOCKS); +- writel(0x1, trng->base + SW_DRBG_INIT); +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(0), SLEEP_US, TIMEOUT_US); +- if (ret) { +- pr_err("failed to init trng(%d)\n", ret); +- return -EIO; +- } +- +- trng->random_bytes = 0; +- +- return 0; +-} +- +-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed, +- unsigned int slen) +-{ +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; +- int ret; +- +- if (slen < SW_DRBG_SEED_SIZE) { +- pr_err("slen(%u) is not matched with trng(%d)\n", slen, +- SW_DRBG_SEED_SIZE); +- return -EINVAL; +- } +- +- mutex_lock(&trng->lock); +- ret = hisi_trng_set_seed(trng, seed); +- mutex_unlock(&trng->lock); +- +- return ret; +-} +- +-static int hisi_trng_reseed(struct hisi_trng *trng) +-{ +- u8 seed[SW_DRBG_SEED_SIZE]; +- int size; +- +- if (!trng->random_bytes) +- return 0; +- +- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false); +- if (size != SW_DRBG_SEED_SIZE) +- return -EIO; +- +- return hisi_trng_set_seed(trng, seed); +-} +- +-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen) +-{ +- u32 data[SW_DRBG_DATA_NUM]; +- u32 currsize = 0; +- u32 val = 0; +- int ret; +- u32 i; +- +- ret = hisi_trng_reseed(trng); +- if (ret) +- return ret; +- +- do { +- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS, +- val, val & BIT(1), SLEEP_US, TIMEOUT_US); +- if (ret) { +- pr_err("failed to generate random number(%d)!\n", ret); +- break; +- } +- +- for (i = 0; i < SW_DRBG_DATA_NUM; i++) +- data[i] = readl(trng->base + SW_DRBG_DATA(i)); +- +- if (dlen - currsize >= SW_DRBG_BYTES) { +- memcpy(dstn + currsize, data, SW_DRBG_BYTES); +- currsize += SW_DRBG_BYTES; +- } else { +- memcpy(dstn + currsize, data, dlen - currsize); +- currsize = dlen; +- } +- +- trng->random_bytes += SW_DRBG_BYTES; +- writel(0x1, trng->base + SW_DRBG_GEN); +- } while (currsize < dlen); +- +- return ret; +-} +- +-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) +-{ +- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm); +- struct hisi_trng *trng = ctx->trng; +- unsigned int currsize = 0; +- unsigned int block_size; +- int ret; +- +- if (!dstn || !dlen) { +- pr_err("output is error, dlen %u!\n", dlen); +- return -EINVAL; +- } +- +- do { +- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES); +- mutex_lock(&trng->lock); +- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size); +- mutex_unlock(&trng->lock); +- if (ret) +- return ret; +- currsize += block_size; +- } while (currsize < dlen); +- +- return 0; +-} +- +-static int hisi_trng_init(struct crypto_tfm *tfm) +-{ +- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); +- struct hisi_trng *trng; +- u32 ctx_num = ~0; +- +- mutex_lock(&trng_devices.lock); +- list_for_each_entry(trng, &trng_devices.list, list) { +- if (trng->ctx_num < ctx_num) { +- ctx_num = trng->ctx_num; +- ctx->trng = trng; +- } +- } +- ctx->trng->ctx_num++; +- mutex_unlock(&trng_devices.lock); +- +- return 0; +-} +- +-static void hisi_trng_exit(struct crypto_tfm *tfm) +-{ +- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm); +- +- mutex_lock(&trng_devices.lock); +- ctx->trng->ctx_num--; +- mutex_unlock(&trng_devices.lock); +-} +- + static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) + { + struct hisi_trng *trng; +@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng * + return currsize; + } + +-static struct rng_alg hisi_trng_alg = { +- .generate = hisi_trng_generate, +- .seed = hisi_trng_seed, +- .seedsize = SW_DRBG_SEED_SIZE, +- .base = { +- .cra_name = "stdrng", +- .cra_driver_name = "hisi_stdrng", +- .cra_priority = 300, +- .cra_ctxsize = sizeof(struct hisi_trng_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = hisi_trng_init, +- .cra_exit = hisi_trng_exit, +- }, +-}; +- +-static void hisi_trng_add_to_list(struct hisi_trng *trng) +-{ +- mutex_lock(&trng_devices.lock); +- list_add_tail(&trng->list, &trng_devices.list); +- mutex_unlock(&trng_devices.lock); +-} +- +-static int hisi_trng_del_from_list(struct hisi_trng *trng) +-{ +- int ret = -EBUSY; +- +- mutex_lock(&trng_devices.lock); +- if (!trng->ctx_num) { +- list_del(&trng->list); +- ret = 0; +- } +- mutex_unlock(&trng_devices.lock); +- +- return ret; +-} +- + static int hisi_trng_probe(struct platform_device *pdev) + { + struct hisi_trng *trng; +@@ -305,68 +62,20 @@ static int hisi_trng_probe(struct platfo + if (!trng) + return -ENOMEM; + +- platform_set_drvdata(pdev, trng); +- + trng->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + +- trng->ctx_num = 0; +- trng->random_bytes = SW_MAX_RANDOM_BYTES; +- mutex_init(&trng->lock); +- trng->ver = readl(trng->base + HISI_TRNG_VERSION); +- if (!trng_devices.is_init) { +- INIT_LIST_HEAD(&trng_devices.list); +- mutex_init(&trng_devices.lock); +- trng_devices.is_init = true; +- } +- +- hisi_trng_add_to_list(trng); +- if (trng->ver != HISI_TRNG_VER_V1 && +- atomic_inc_return(&trng_active_devs) == 1) { +- ret = crypto_register_rng(&hisi_trng_alg); +- if (ret) { +- dev_err(&pdev->dev, +- "failed to register crypto(%d)\n", ret); +- atomic_dec_return(&trng_active_devs); +- goto err_remove_from_list; +- } +- } +- + trng->rng.name = pdev->name; + trng->rng.read = hisi_trng_read; + trng->rng.quality = HISI_TRNG_QUALITY; ++ + ret = devm_hwrng_register(&pdev->dev, &trng->rng); +- if (ret) { ++ if (ret) + dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret); +- goto err_crypto_unregister; +- } +- +- return ret; +- +-err_crypto_unregister: +- if (trng->ver != HISI_TRNG_VER_V1 && +- atomic_dec_return(&trng_active_devs) == 0) +- crypto_unregister_rng(&hisi_trng_alg); +- +-err_remove_from_list: +- hisi_trng_del_from_list(trng); + return ret; + } + +-static void hisi_trng_remove(struct platform_device *pdev) +-{ +- struct hisi_trng *trng = platform_get_drvdata(pdev); +- +- /* Wait until the task is finished */ +- while (hisi_trng_del_from_list(trng)) +- ; +- +- if (trng->ver != HISI_TRNG_VER_V1 && +- atomic_dec_return(&trng_active_devs) == 0) +- crypto_unregister_rng(&hisi_trng_alg); +-} +- + static const struct acpi_device_id hisi_trng_acpi_match[] = { + { "HISI02B3", 0 }, + { } +@@ -375,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi + + static struct platform_driver hisi_trng_driver = { + .probe = hisi_trng_probe, +- .remove = hisi_trng_remove, + .driver = { + .name = "hisi-trng-v2", + .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match), diff --git a/queue-7.1/crypto-loongson-remove-broken-and-unused-loongson-rng.patch b/queue-7.1/crypto-loongson-remove-broken-and-unused-loongson-rng.patch new file mode 100644 index 0000000000..38c487a6eb --- /dev/null +++ b/queue-7.1/crypto-loongson-remove-broken-and-unused-loongson-rng.patch @@ -0,0 +1,323 @@ +From af3d1bb9a09daf928fc3f173689fb7904d6a6d4f Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Fri, 29 May 2026 16:32:08 -0700 +Subject: crypto: loongson - Remove broken and unused loongson-rng + +From: Eric Biggers + +commit af3d1bb9a09daf928fc3f173689fb7904d6a6d4f upstream. + +The loongson-rng rng_alg has several vulnerabilities, including not +providing forward security, and a use-after-free bug due to the use of +wait_for_completion_interruptible(). + +Meanwhile, the rng_alg framework doesn't really have any purpose in the +first place other than to access the software algorithms crypto/drbg.c +and crypto/jitterentropy.c. Hardware-specific rng_algs have no +in-kernel user, and unlike hwrng there's no feed into the actual Linux +RNG. As such, there's really no point to this code. There are of +course other rng_alg drivers that are similarly unused, but they're +similarly in the process of being phased out, e.g. +https://lore.kernel.org/r/20260529193648.18172-1-ebiggers@kernel.org and +https://lore.kernel.org/r/20260529220430.34135-1-ebiggers@kernel.org + +Given that, there's no point in fixing forward these vulnerabilities, +and it makes much more sense to simply roll back the addition of this +driver. If this platform provides TRNG (not PRNG) functionality, it +could make sense to add a hwrng driver, but it would be quite different. + +Link: https://lore.kernel.org/linux-crypto/20260525145939.GC2018@quark/ +Fixes: 766b2d724c8d ("crypto: loongson - add Loongson RNG driver support") +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 1 + arch/loongarch/configs/loongson32_defconfig | 1 + arch/loongarch/configs/loongson64_defconfig | 1 + drivers/crypto/Kconfig | 1 + drivers/crypto/Makefile | 1 + drivers/crypto/loongson/Kconfig | 6 + drivers/crypto/loongson/Makefile | 1 + drivers/crypto/loongson/loongson-rng.c | 209 ---------------------------- + 8 files changed, 221 deletions(-) + delete mode 100644 drivers/crypto/loongson/Kconfig + delete mode 100644 drivers/crypto/loongson/Makefile + delete mode 100644 drivers/crypto/loongson/loongson-rng.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15087,7 +15087,6 @@ M: Qunqin Zhao + L: linux-crypto@vger.kernel.org + S: Maintained + F: drivers/char/tpm/tpm_loongson.c +-F: drivers/crypto/loongson/ + F: drivers/mfd/loongson-se.c + F: include/linux/mfd/loongson-se.h + +--- a/arch/loongarch/configs/loongson32_defconfig ++++ b/arch/loongarch/configs/loongson32_defconfig +@@ -1091,7 +1091,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m + CONFIG_CRYPTO_USER_API_RNG=m + CONFIG_CRYPTO_USER_API_AEAD=m + CONFIG_CRYPTO_DEV_VIRTIO=m +-CONFIG_CRYPTO_DEV_LOONGSON_RNG=m + CONFIG_DMA_CMA=y + CONFIG_CMA_SIZE_MBYTES=0 + CONFIG_PRINTK_TIME=y +--- a/arch/loongarch/configs/loongson64_defconfig ++++ b/arch/loongarch/configs/loongson64_defconfig +@@ -1124,7 +1124,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m + CONFIG_CRYPTO_USER_API_RNG=m + CONFIG_CRYPTO_USER_API_AEAD=m + CONFIG_CRYPTO_DEV_VIRTIO=m +-CONFIG_CRYPTO_DEV_LOONGSON_RNG=m + CONFIG_DMA_CMA=y + CONFIG_DMA_NUMA_CMA=y + CONFIG_CMA_SIZE_MBYTES=0 +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -845,7 +845,6 @@ config CRYPTO_DEV_CCREE + If unsure say Y. + + source "drivers/crypto/hisilicon/Kconfig" +-source "drivers/crypto/loongson/Kconfig" + + source "drivers/crypto/amlogic/Kconfig" + +--- a/drivers/crypto/Makefile ++++ b/drivers/crypto/Makefile +@@ -43,7 +43,6 @@ obj-y += inside-secure/ + obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/ + obj-y += xilinx/ + obj-y += hisilicon/ +-obj-y += loongson/ + obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ + obj-y += intel/ + obj-y += starfive/ +--- a/drivers/crypto/loongson/Kconfig ++++ /dev/null +@@ -1,6 +0,0 @@ +-config CRYPTO_DEV_LOONGSON_RNG +- tristate "Support for Loongson RNG Driver" +- depends on MFD_LOONGSON_SE +- select CRYPTO_RNG +- help +- Support for Loongson RNG Driver. +--- a/drivers/crypto/loongson/Makefile ++++ /dev/null +@@ -1 +0,0 @@ +-obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o +--- a/drivers/crypto/loongson/loongson-rng.c ++++ /dev/null +@@ -1,209 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* Copyright (c) 2019 HiSilicon Limited. */ +-/* Copyright (c) 2025 Loongson Technology Corporation Limited. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define SE_SEED_SIZE 32 +- +-struct loongson_rng_list { +- struct mutex lock; +- struct list_head list; +- int registered; +-}; +- +-struct loongson_rng { +- u32 used; +- struct loongson_se_engine *engine; +- struct list_head list; +- struct mutex lock; +-}; +- +-struct loongson_rng_ctx { +- struct loongson_rng *rng; +-}; +- +-struct loongson_rng_cmd { +- u32 cmd_id; +- union { +- u32 len; +- u32 ret; +- } u; +- u32 seed_off; +- u32 out_off; +- u32 pad[4]; +-}; +- +-static struct loongson_rng_list rng_devices = { +- .lock = __MUTEX_INITIALIZER(rng_devices.lock), +- .list = LIST_HEAD_INIT(rng_devices.list), +-}; +- +-static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src, +- unsigned int slen, u8 *dstn, unsigned int dlen) +-{ +- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); +- struct loongson_rng *rng = ctx->rng; +- struct loongson_rng_cmd *cmd = rng->engine->command; +- int err, len; +- +- mutex_lock(&rng->lock); +- cmd->seed_off = 0; +- do { +- len = min(dlen, rng->engine->buffer_size); +- cmd = rng->engine->command; +- cmd->u.len = len; +- err = loongson_se_send_engine_cmd(rng->engine); +- if (err) +- break; +- +- cmd = rng->engine->command_ret; +- if (cmd->u.ret) { +- err = -EIO; +- break; +- } +- +- memcpy(dstn, rng->engine->data_buffer, len); +- dlen -= len; +- dstn += len; +- } while (dlen > 0); +- mutex_unlock(&rng->lock); +- +- return err; +-} +- +-static int loongson_rng_init(struct crypto_tfm *tfm) +-{ +- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); +- struct loongson_rng *rng; +- u32 min_used = U32_MAX; +- +- mutex_lock(&rng_devices.lock); +- list_for_each_entry(rng, &rng_devices.list, list) { +- if (rng->used < min_used) { +- ctx->rng = rng; +- min_used = rng->used; +- } +- } +- ctx->rng->used++; +- mutex_unlock(&rng_devices.lock); +- +- return 0; +-} +- +-static void loongson_rng_exit(struct crypto_tfm *tfm) +-{ +- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); +- +- mutex_lock(&rng_devices.lock); +- ctx->rng->used--; +- mutex_unlock(&rng_devices.lock); +-} +- +-static int loongson_rng_seed(struct crypto_rng *tfm, const u8 *seed, +- unsigned int slen) +-{ +- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); +- struct loongson_rng *rng = ctx->rng; +- struct loongson_rng_cmd *cmd; +- int err; +- +- if (slen < SE_SEED_SIZE) +- return -EINVAL; +- +- slen = min(slen, rng->engine->buffer_size); +- +- mutex_lock(&rng->lock); +- cmd = rng->engine->command; +- cmd->u.len = slen; +- cmd->seed_off = rng->engine->buffer_off; +- memcpy(rng->engine->data_buffer, seed, slen); +- err = loongson_se_send_engine_cmd(rng->engine); +- if (err) +- goto out; +- +- cmd = rng->engine->command_ret; +- if (cmd->u.ret) +- err = -EIO; +-out: +- mutex_unlock(&rng->lock); +- +- return err; +-} +- +-static struct rng_alg loongson_rng_alg = { +- .generate = loongson_rng_generate, +- .seed = loongson_rng_seed, +- .seedsize = SE_SEED_SIZE, +- .base = { +- .cra_name = "stdrng", +- .cra_driver_name = "loongson_stdrng", +- .cra_priority = 300, +- .cra_ctxsize = sizeof(struct loongson_rng_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = loongson_rng_init, +- .cra_exit = loongson_rng_exit, +- }, +-}; +- +-static int loongson_rng_probe(struct platform_device *pdev) +-{ +- struct loongson_rng_cmd *cmd; +- struct loongson_rng *rng; +- int ret = 0; +- +- rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); +- if (!rng) +- return -ENOMEM; +- +- rng->engine = loongson_se_init_engine(pdev->dev.parent, SE_ENGINE_RNG); +- if (!rng->engine) +- return -ENODEV; +- cmd = rng->engine->command; +- cmd->cmd_id = SE_CMD_RNG; +- cmd->out_off = rng->engine->buffer_off; +- mutex_init(&rng->lock); +- +- mutex_lock(&rng_devices.lock); +- +- if (!rng_devices.registered) { +- ret = crypto_register_rng(&loongson_rng_alg); +- if (ret) { +- dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret); +- goto out; +- } +- rng_devices.registered = 1; +- } +- +- list_add_tail(&rng->list, &rng_devices.list); +-out: +- mutex_unlock(&rng_devices.lock); +- +- return ret; +-} +- +-static struct platform_driver loongson_rng_driver = { +- .probe = loongson_rng_probe, +- .driver = { +- .name = "loongson-rng", +- }, +-}; +-module_platform_driver(loongson_rng_driver); +- +-MODULE_ALIAS("platform:loongson-rng"); +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Yinggang Gu "); +-MODULE_AUTHOR("Qunqin Zhao "); +-MODULE_DESCRIPTION("Loongson Random Number Generator driver"); diff --git a/queue-7.1/crypto-loongson-select-crypto_rng.patch b/queue-7.1/crypto-loongson-select-crypto_rng.patch new file mode 100644 index 0000000000..38367f7f0d --- /dev/null +++ b/queue-7.1/crypto-loongson-select-crypto_rng.patch @@ -0,0 +1,32 @@ +From 4c600ab0d8cfc9d75b92f3426dbcb2ad85eac91d Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Thu, 21 May 2026 21:25:25 -0500 +Subject: crypto: loongson - Select CRYPTO_RNG + +From: Eric Biggers + +commit 4c600ab0d8cfc9d75b92f3426dbcb2ad85eac91d upstream. + +This driver registers a rng_alg, so it requires CRYPTO_RNG. + +Fixes: 766b2d724c8d ("crypto: loongson - add Loongson RNG driver support") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202605201622.qWOiiZTV-lkp@intel.com/ +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Reviewed-by: Huacai Chen +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/loongson/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/crypto/loongson/Kconfig ++++ b/drivers/crypto/loongson/Kconfig +@@ -1,5 +1,6 @@ + config CRYPTO_DEV_LOONGSON_RNG + tristate "Support for Loongson RNG Driver" + depends on MFD_LOONGSON_SE ++ select CRYPTO_RNG + help + Support for Loongson RNG Driver. diff --git a/queue-7.1/crypto-pcrypt-restore-callback-for-non-parallel-fallback.patch b/queue-7.1/crypto-pcrypt-restore-callback-for-non-parallel-fallback.patch new file mode 100644 index 0000000000..b390475070 --- /dev/null +++ b/queue-7.1/crypto-pcrypt-restore-callback-for-non-parallel-fallback.patch @@ -0,0 +1,57 @@ +From ed459fe319376e876de433d12b6c6772e612ca36 Mon Sep 17 00:00:00 2001 +From: Ruijie Li +Date: Mon, 25 May 2026 19:45:21 +0800 +Subject: crypto: pcrypt - restore callback for non-parallel fallback + +From: Ruijie Li + +commit ed459fe319376e876de433d12b6c6772e612ca36 upstream. + +pcrypt installs pcrypt_aead_done() on the child AEAD request before +trying to submit it through padata. If padata_do_parallel() returns +-EBUSY, pcrypt falls back to calling the child AEAD directly. + +That fallback must not keep the padata completion callback. Otherwise +an asynchronous completion runs pcrypt_aead_done() even though the +request was never enrolled in padata. + +Restore the original request callback and callback data before calling +the child AEAD directly. This keeps the fallback path aligned with a +direct AEAD request while leaving the parallel path unchanged. + +Fixes: 662f2f13e66d ("crypto: pcrypt - Call crypto layer directly when padata_do_parallel() return -EBUSY") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Zhengchuan Liang +Reported-by: Xin Liu +Assisted-by: Codex:gpt-5.4 +Signed-off-by: Ruijie Li +Signed-off-by: Ren Wei +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + crypto/pcrypt.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/crypto/pcrypt.c ++++ b/crypto/pcrypt.c +@@ -122,6 +122,8 @@ static int pcrypt_aead_encrypt(struct ae + return -EINPROGRESS; + if (err == -EBUSY) { + /* try non-parallel mode */ ++ aead_request_set_callback(creq, flags, req->base.complete, ++ req->base.data); + return crypto_aead_encrypt(creq); + } + +@@ -173,6 +175,8 @@ static int pcrypt_aead_decrypt(struct ae + return -EINPROGRESS; + if (err == -EBUSY) { + /* try non-parallel mode */ ++ aead_request_set_callback(creq, flags, req->base.complete, ++ req->base.data); + return crypto_aead_decrypt(creq); + } + diff --git a/queue-7.1/crypto-tegra-fix-refcount-leak-in-tegra_se_host1x_submit.patch b/queue-7.1/crypto-tegra-fix-refcount-leak-in-tegra_se_host1x_submit.patch new file mode 100644 index 0000000000..b2f4723ae0 --- /dev/null +++ b/queue-7.1/crypto-tegra-fix-refcount-leak-in-tegra_se_host1x_submit.patch @@ -0,0 +1,41 @@ +From 6ea0ce3a19f9c37a014099e2b0a46b27fa164564 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Thu, 4 Jun 2026 10:27:06 +0000 +Subject: crypto: tegra - fix refcount leak in tegra_se_host1x_submit() + +From: Wentao Liang + +commit 6ea0ce3a19f9c37a014099e2b0a46b27fa164564 upstream. + +The timeout error path in tegra_se_host1x_submit() returns without +calling host1x_job_put(), while all other paths (success, submit +error, pin error) properly release the job reference through the +job_put label. Since host1x_job_alloc() initializes the reference +count and host1x_job_put() is required to drop it, omitting it on +timeout causes a permanent refcount leak. + +Fix this by redirecting the timeout return to the existing job_put +label, ensuring the job reference and any associated syncpt +references are consistently released. + +Cc: stable@vger.kernel.org +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Wentao Liang +Reviewed-by: Akhil R +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/tegra/tegra-se-main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/crypto/tegra/tegra-se-main.c ++++ b/drivers/crypto/tegra/tegra-se-main.c +@@ -180,7 +180,7 @@ int tegra_se_host1x_submit(struct tegra_ + MAX_SCHEDULE_TIMEOUT, NULL); + if (ret) { + dev_err(se->dev, "host1x job timed out\n"); +- return ret; ++ goto job_put; + } + + host1x_job_put(job); diff --git a/queue-7.1/dm-ioctl-report-an-error-if-a-device-has-no-table.patch b/queue-7.1/dm-ioctl-report-an-error-if-a-device-has-no-table.patch new file mode 100644 index 0000000000..ec586e447e --- /dev/null +++ b/queue-7.1/dm-ioctl-report-an-error-if-a-device-has-no-table.patch @@ -0,0 +1,35 @@ +From 457e32348d606a77f9b20e25e989734189834c07 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 11 May 2026 13:04:16 +0200 +Subject: dm-ioctl: report an error if a device has no table + +From: Mikulas Patocka + +commit 457e32348d606a77f9b20e25e989734189834c07 upstream. + +When we send a message to a device that has no table, the return code was +not set. The code would return "2", which is not considered a valid return value. + +Signed-off-by: Mikulas Patocka +Cc: stable@vger.kernel.org +Reviewed-by: Benjamin Marzinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-ioctl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1816,8 +1816,11 @@ static int target_message(struct file *f + goto out_argv; + + table = dm_get_live_table(md, &srcu_idx); +- if (!table) ++ if (!table) { ++ DMERR("The device has no table."); ++ r = -EINVAL; + goto out_table; ++ } + + if (dm_deleting_md(md)) { + r = -ENXIO; diff --git a/queue-7.1/hwrng-jh7110-fix-refcount-leak-in-starfive_trng_read.patch b/queue-7.1/hwrng-jh7110-fix-refcount-leak-in-starfive_trng_read.patch new file mode 100644 index 0000000000..22fc3d3e5c --- /dev/null +++ b/queue-7.1/hwrng-jh7110-fix-refcount-leak-in-starfive_trng_read.patch @@ -0,0 +1,59 @@ +From 8d13f7a8450206e3f820cdb26e33e91d181071b4 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Wed, 3 Jun 2026 11:03:27 +0000 +Subject: hwrng: jh7110 - fix refcount leak in starfive_trng_read() + +From: Wentao Liang + +commit 8d13f7a8450206e3f820cdb26e33e91d181071b4 upstream. + +The starfive_trng_read() function acquires a runtime PM reference +via pm_runtime_get_sync() but fails to release it on two error +paths. If starfive_trng_wait_idle() or starfive_trng_cmd() returns +an error, the function exits without calling +pm_runtime_put_sync_autosuspend(), leaving the runtime PM usage +counter permanently elevated and preventing the device from entering +runtime suspend. + +Refactor the function to use a unified error path that calls +pm_runtime_put_sync_autosuspend() before returning. + +Cc: stable@vger.kernel.org +Fixes: c388f458bc34 ("hwrng: starfive - Add TRNG driver for StarFive SoC") +Signed-off-by: Wentao Liang +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/hw_random/jh7110-trng.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/char/hw_random/jh7110-trng.c ++++ b/drivers/char/hw_random/jh7110-trng.c +@@ -256,19 +256,22 @@ static int starfive_trng_read(struct hwr + + if (wait) { + ret = starfive_trng_wait_idle(trng); +- if (ret) +- return -ETIMEDOUT; ++ if (ret) { ++ ret = -ETIMEDOUT; ++ goto out_put; ++ } + } + + ret = starfive_trng_cmd(trng, STARFIVE_CTRL_GENE_RANDNUM, wait); + if (ret) +- return ret; ++ goto out_put; + + memcpy_fromio(buf, trng->base + STARFIVE_RAND0, max); ++ ret = max; + ++out_put: + pm_runtime_put_sync_autosuspend(trng->dev); +- +- return max; ++ return ret; + } + + static int starfive_trng_probe(struct platform_device *pdev) diff --git a/queue-7.1/isofs-bound-rock-ridge-symlink-components-to-the-sl-record.patch b/queue-7.1/isofs-bound-rock-ridge-symlink-components-to-the-sl-record.patch new file mode 100644 index 0000000000..0c573fec31 --- /dev/null +++ b/queue-7.1/isofs-bound-rock-ridge-symlink-components-to-the-sl-record.patch @@ -0,0 +1,74 @@ +From 5fa1d6a5ec2356d2107dead614437c66fa7138b1 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Sun, 7 Jun 2026 01:18:27 +0000 +Subject: isofs: bound Rock Ridge symlink components to the SL record + +From: Bryam Vargas + +commit 5fa1d6a5ec2356d2107dead614437c66fa7138b1 upstream. + +get_symlink_chunk() and the SL handling in +parse_rock_ridge_inode_internal() walk the variable-length components of +a Rock Ridge "SL" (symbolic link) record. Each component is a two-byte +header (flags, len) followed by len bytes of text, so it occupies +slp->len + 2 bytes. Both loops read slp->len and advance to the next +component, and get_symlink_chunk() additionally does +memcpy(rpnt, slp->text, slp->len), but neither checks that the component +lies within the SL record before dereferencing it. + +A crafted SL record whose component declares a len that runs past the +record (rr->len) therefore triggers an out-of-bounds read of up to 255 +bytes. When the record sits at the tail of its backing buffer - for +example a small kmalloc()ed continuation block reached through a CE +record - the read crosses the allocation; get_symlink_chunk() then +copies the out-of-bounds bytes into the symlink body returned to user +space by readlink(), disclosing adjacent kernel memory. + +ISO 9660 images are routinely mounted from untrusted removable media - +desktop environments auto-mount them (e.g. via udisks2) without +CAP_SYS_ADMIN - so the record contents are attacker-controlled. + +Reject any component that does not fit in the remaining record bytes +before using it. In get_symlink_chunk() return NULL, like the existing +output-buffer (plimit) checks, so a malformed record makes readlink() +fail with -EIO rather than silently returning a truncated target; in +parse_rock_ridge_inode_internal() stop the inode-size walk. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Suggested-by: Michael Bommarito +Signed-off-by: Bryam Vargas +Link: https://patch.msgid.link/20260607011823.217748-1-hexlabsecurity@proton.me +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/isofs/rock.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/fs/isofs/rock.c ++++ b/fs/isofs/rock.c +@@ -466,6 +466,9 @@ repeat: + inode->i_size = symlink_len; + while (slen > 1) { + rootflag = 0; ++ /* keep the component within the SL record */ ++ if (slp->len + 2 > slen) ++ goto eio; + switch (slp->flags & ~1) { + case 0: + inode->i_size += +@@ -621,6 +624,14 @@ static char *get_symlink_chunk(char *rpn + slp = &rr->u.SL.link; + while (slen > 1) { + rootflag = 0; ++ /* ++ * A component is slp->len + 2 bytes (a two-byte header plus ++ * len bytes of text). If it does not fit in the bytes left in ++ * the SL record the record is malformed: fail like the plimit ++ * checks below so readlink() returns -EIO, not a truncated path. ++ */ ++ if (slp->len + 2 > slen) ++ return NULL; + switch (slp->flags & ~1) { + case 0: + if (slp->len > plimit - rpnt) diff --git a/queue-7.1/nvme-multipath-set-bio_remapped-on-bios-remapped-to-per-path-namespace-disks.patch b/queue-7.1/nvme-multipath-set-bio_remapped-on-bios-remapped-to-per-path-namespace-disks.patch new file mode 100644 index 0000000000..0c4a62b520 --- /dev/null +++ b/queue-7.1/nvme-multipath-set-bio_remapped-on-bios-remapped-to-per-path-namespace-disks.patch @@ -0,0 +1,88 @@ +From 88bac2c1a72b8f4f71e9845699aa872df04e5850 Mon Sep 17 00:00:00 2001 +From: "Achkinazi, Igor" +Date: Thu, 28 May 2026 15:24:27 +0000 +Subject: nvme-multipath: set BIO_REMAPPED on bios remapped to per-path namespace disks + +From: Achkinazi, Igor + +commit 88bac2c1a72b8f4f71e9845699aa872df04e5850 upstream. + +When nvme_ns_head_submit_bio() remaps a bio from the multipath head to a +per-path namespace, bio_set_dev() clears BIO_REMAPPED. The remapped bio +is then resubmitted through submit_bio_noacct() which calls +bio_check_eod() because BIO_REMAPPED is not set. + +This races with nvme_ns_remove() which zeroes the per-path capacity +before synchronize_srcu(): + + CPU 0 (IO submission) + --------------------- + srcu_read_lock() + nvme_find_path() -> ns + [NVME_NS_READY is set] + + CPU 1 (namespace removal) + ------------------------- + clear_bit(NVME_NS_READY) + set_capacity(ns->disk, 0) + synchronize_srcu() <- blocks + + CPU 0 (IO submission) + --------------------- + bio_set_dev(bio, ns->disk->part0) + [clears BIO_REMAPPED] + submit_bio_noacct(bio) + -> bio_check_eod() sees capacity=0 + -> bio fails with IO error + +The SRCU read lock prevents synchronize_srcu() from completing, but does +not prevent set_capacity(0) from executing. The bio fails the EOD check +before it reaches the NVMe driver, so nvme_failover_req() never gets a +chance to redirect it to another path of multipath. IO errors are +reported to the application despite another path being available. + +On older kernels (before commit 0b64682e78f7 "block: skip unnecessary +checks for split bio"), the same race was also reachable through split +remainders resubmitted via submit_bio_noacct(). + +Fix this by setting BIO_REMAPPED after bio_set_dev() in +nvme_ns_head_submit_bio(). This skips bio_check_eod() on the per-path +device; the EOD check already passed on the multipath head. + +NVMe per-path namespace devices are always whole disks (bd_partno=0), so +the blk_partition_remap() skip also gated by BIO_REMAPPED is a no-op. +The flag does not persist across failover and cannot go stale if the +namespace geometry changes between attempts: nvme_failover_req() calls +bio_set_dev() to redirect the bio back to the multipath head, which +clears BIO_REMAPPED. When nvme_requeue_work() resubmits through +submit_bio_noacct(), bio_check_eod() runs normally against the current +capacity. + +Same approach as commit 3a905c37c351 ("block: skip bio_check_eod for +partition-remapped bios"). + +Fixes: a7c7f7b2b641 ("nvme: use bio_set_dev to assign ->bi_bdev") +Cc: stable@vger.kernel.org +Reviewed-by: Christoph Hellwig +Signed-off-by: Igor Achkinazi +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/multipath.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -511,6 +511,12 @@ static void nvme_ns_head_submit_bio(stru + ns = nvme_find_path(head); + if (likely(ns)) { + bio_set_dev(bio, ns->disk->part0); ++ /* ++ * Use BIO_REMAPPED to skip bio_check_eod() when this bio ++ * enters submit_bio_noacct() for the per-path device. The EOD ++ * check already passed on the multipath head. ++ */ ++ bio_set_flag(bio, BIO_REMAPPED); + bio->bi_opf |= REQ_NVME_MPATH; + trace_block_bio_remap(bio, disk_devt(ns->head->disk), + bio->bi_iter.bi_sector); diff --git a/queue-7.1/nvme-target-rdma-fix-ndev-refcount-leak-on-queue-connect.patch b/queue-7.1/nvme-target-rdma-fix-ndev-refcount-leak-on-queue-connect.patch new file mode 100644 index 0000000000..a007707a2a --- /dev/null +++ b/queue-7.1/nvme-target-rdma-fix-ndev-refcount-leak-on-queue-connect.patch @@ -0,0 +1,43 @@ +From badc53620fe813b3a9f727ef9526f98567c2c898 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Wed, 27 May 2026 08:45:44 +0000 +Subject: nvme: target: rdma: fix ndev refcount leak on queue connect + +From: Wentao Liang + +commit badc53620fe813b3a9f727ef9526f98567c2c898 upstream. + +nvmet_rdma_queue_connect() calls nvmet_rdma_find_get_device() which +acquires a reference on the returned ndev via kref_get(). On the path +where the host queue backlog is exceeded and the function returns +NVME_SC_CONNECT_CTRL_BUSY, reference of ndev is not released, leaking +the kref. + +Fix this by adding a goto to the existing put_device label before the +early return. + +Fixes: 31deaeb11ba7 ("nvmet-rdma: avoid circular locking dependency on install_queue()") +Cc: stable@vger.kernel.org +Reviewed-by: Christoph Hellwig +Signed-off-by: Wentao Liang +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/rdma.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/nvme/target/rdma.c ++++ b/drivers/nvme/target/rdma.c +@@ -1598,8 +1598,10 @@ static int nvmet_rdma_queue_connect(stru + pending++; + } + mutex_unlock(&nvmet_rdma_queue_mutex); +- if (pending > NVMET_RDMA_BACKLOG) +- return NVME_SC_CONNECT_CTRL_BUSY; ++ if (pending > NVMET_RDMA_BACKLOG) { ++ ret = NVME_SC_CONNECT_CTRL_BUSY; ++ goto put_device; ++ } + } + + ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn); diff --git a/queue-7.1/nvmet-auth-validate-reply-message-payload-bounds-against-transfer-length.patch b/queue-7.1/nvmet-auth-validate-reply-message-payload-bounds-against-transfer-length.patch new file mode 100644 index 0000000000..5ced5c7a0c --- /dev/null +++ b/queue-7.1/nvmet-auth-validate-reply-message-payload-bounds-against-transfer-length.patch @@ -0,0 +1,73 @@ +From 3a413ece2504c70aa34a20be4dafec04e8c741f9 Mon Sep 17 00:00:00 2001 +From: Tianchu Chen +Date: Fri, 29 May 2026 14:18:39 +0000 +Subject: nvmet-auth: validate reply message payload bounds against transfer length + +From: Tianchu Chen + +commit 3a413ece2504c70aa34a20be4dafec04e8c741f9 upstream. + +nvmet_auth_reply() accesses the variable-length rval[] array using +attacker-controlled hl (hash length) and dhvlen (DH value length) fields +without verifying they fit within the allocated buffer of tl bytes. + +A malicious NVMe-oF initiator can craft a DHCHAP_REPLY message with a +small transfer length but large hl/dhvlen values, causing out-of-bounds +heap reads when the target processes the DH public key (rval + 2*hl) or +performs the host response memcmp. + +With DH authentication configured, the OOB pointer is passed directly to +sg_init_one() and read by crypto_kpp_compute_shared_secret(), reaching +up to 526 bytes past the buffer. This is exploitable pre-authentication. + +Add bounds validation ensuring sizeof(*data) + 2*hl + dhvlen <= tl before +any access to the variable-length fields. + +Discovered by Atuin - Automated Vulnerability Discovery Engine. + +Fixes: db1312dd9548 ("nvmet: implement basic In-Band Authentication") +Cc: stable@vger.kernel.org +Reviewed-by: Hannes Reinecke +Signed-off-by: Tianchu Chen +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/fabrics-cmd-auth.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/drivers/nvme/target/fabrics-cmd-auth.c ++++ b/drivers/nvme/target/fabrics-cmd-auth.c +@@ -132,13 +132,22 @@ static u8 nvmet_auth_negotiate(struct nv + return 0; + } + +-static u8 nvmet_auth_reply(struct nvmet_req *req, void *d) ++static u8 nvmet_auth_reply(struct nvmet_req *req, void *d, u32 tl) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmf_auth_dhchap_reply_data *data = d; +- u16 dhvlen = le16_to_cpu(data->dhvlen); ++ u16 dhvlen; + u8 *response; + ++ if (tl < sizeof(*data)) ++ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; ++ ++ dhvlen = le16_to_cpu(data->dhvlen); ++ ++ /* Validate that hl and dhvlen fit within the transfer length */ ++ if (sizeof(*data) + 2 * (size_t)data->hl + dhvlen > tl) ++ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD; ++ + pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n", + __func__, ctrl->cntlid, req->sq->qid, + data->hl, data->cvalid, dhvlen); +@@ -338,7 +347,7 @@ void nvmet_execute_auth_send(struct nvme + + switch (data->auth_id) { + case NVME_AUTH_DHCHAP_MESSAGE_REPLY: +- dhchap_status = nvmet_auth_reply(req, d); ++ dhchap_status = nvmet_auth_reply(req, d, tl); + if (dhchap_status == 0) + req->sq->dhchap_step = + NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1; diff --git a/queue-7.1/nvmet-fix-pre-auth-out-of-bounds-heap-read-in-discovery-get-log-page.patch b/queue-7.1/nvmet-fix-pre-auth-out-of-bounds-heap-read-in-discovery-get-log-page.patch new file mode 100644 index 0000000000..9b45215d44 --- /dev/null +++ b/queue-7.1/nvmet-fix-pre-auth-out-of-bounds-heap-read-in-discovery-get-log-page.patch @@ -0,0 +1,101 @@ +From 53cd102a7a56079b11b897835bd9b94c14e6322c Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Wed, 27 May 2026 15:00:00 -0500 +Subject: nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page + +From: Bryam Vargas + +commit 53cd102a7a56079b11b897835bd9b94c14e6322c upstream. + +nvmet_execute_disc_get_log_page() validates only the dword alignment +of the host-supplied Log Page Offset (lpo). The 64-bit offset is then +added to a small kzalloc'd buffer that holds the discovery log page +and the result is passed straight to nvmet_copy_to_sgl(), which +memcpy()s data_len bytes out to the host with no source-side bound +check: + + u64 offset = nvmet_get_log_page_offset(req->cmd); /* 64-bit host */ + size_t data_len = nvmet_get_log_page_len(req->cmd); /* 32-bit host */ + ... + if (offset & 0x3) { ... } /* only check */ + ... + alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req); + buffer = kzalloc(alloc_len, GFP_KERNEL); + ... + status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len); + +The Discovery controller is unauthenticated -- nvmet_host_allowed() +returns true unconditionally for the discovery subsystem -- so the call +is reachable pre-authentication by any TCP/RDMA/FC peer that can reach +the nvmet target. With a discovery log page of ~1 KiB, an attacker +requesting up to 4 KiB starting at offset == alloc_len reads the next +slab page out and gets its content returned over the fabric (an +empirical run on a default nvmet-tcp loopback target leaked 81 +canonical kernel pointers in one Get Log Page response). Pointing the +offset at unmapped kernel memory faults the in-kernel memcpy and +crashes (or panics, on panic_on_oops=1) the target host instead. + +The attacker-controlled source-side offset pattern +"nvmet_copy_to_sgl(req, 0, buffer + ATTACKER_OFFSET, ...)" is unique +to nvmet_execute_disc_get_log_page in the entire nvmet codebase: every +other Get Log Page handler in admin-cmd.c either ignores lpo (and +silently starts every response at offset 0) or tracks a local +destination offset with a fixed source pointer. + +Validate the host-supplied offset against the log page size, cap the +copy length to what is actually available, and zero-fill any remainder +of the host transfer buffer. The zero-fill matches the existing +short-response pattern in nvmet_execute_get_log_changed_ns() +(admin-cmd.c) and prevents leaking transport SGL contents when the +host asks for more bytes than the log page contains. + +Fixes: a07b4970f464 ("nvmet: add a generic NVMe target") +Cc: stable@vger.kernel.org +Reviewed-by: Chaitanya Kulkarni +Reviewed-by: Christoph Hellwig +Signed-off-by: Bryam Vargas +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/target/discovery.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/drivers/nvme/target/discovery.c ++++ b/drivers/nvme/target/discovery.c +@@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_p + u64 offset = nvmet_get_log_page_offset(req->cmd); + size_t data_len = nvmet_get_log_page_len(req->cmd); + size_t alloc_len; ++ size_t copy_len; + struct nvmet_subsys_link *p; + struct nvmet_port *r; + u32 numrec = 0; +@@ -242,7 +243,27 @@ static void nvmet_execute_disc_get_log_p + + up_read(&nvmet_config_sem); + +- status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len); ++ /* ++ * Validate the host-supplied log page offset before copying out. ++ * Without this check, the host controls a 64-bit byte offset into ++ * a small kzalloc'd buffer: a value past the log page lets the ++ * subsequent memcpy read adjacent kernel heap, and a value aimed ++ * at unmapped kernel memory faults the in-kernel copy and crashes ++ * the target host. The Discovery controller is unauthenticated, ++ * so the bug is reachable from any reachable fabric peer. ++ */ ++ if (offset > alloc_len) { ++ req->error_loc = ++ offsetof(struct nvme_get_log_page_command, lpo); ++ status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; ++ goto out_free_buffer; ++ } ++ ++ copy_len = min_t(size_t, data_len, alloc_len - offset); ++ status = nvmet_copy_to_sgl(req, 0, buffer + offset, copy_len); ++ if (!status && copy_len < data_len) ++ status = nvmet_zero_sgl(req, copy_len, data_len - copy_len); ++out_free_buffer: + kfree(buffer); + out: + nvmet_req_complete(req, status); diff --git a/queue-7.1/partitions-aix-bound-the-pp_count-scan-to-the-ppe-array.patch b/queue-7.1/partitions-aix-bound-the-pp_count-scan-to-the-ppe-array.patch new file mode 100644 index 0000000000..dc74e164fe --- /dev/null +++ b/queue-7.1/partitions-aix-bound-the-pp_count-scan-to-the-ppe-array.patch @@ -0,0 +1,62 @@ +From 2dc0bfd2fe355fb930de63c2f2eb8ced8570c579 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Sun, 7 Jun 2026 06:41:43 +0000 +Subject: partitions: aix: bound the pp_count scan to the ppe array + +From: Bryam Vargas + +commit 2dc0bfd2fe355fb930de63c2f2eb8ced8570c579 upstream. + +aix_partition() reads the physical volume descriptor into a fixed-size +struct pvd and then scans its physical-partition-extent array: + + int numpps = be16_to_cpu(pvd->pp_count); + ... + for (i = 0; i < numpps; i += 1) { + struct ppe *p = pvd->ppe + i; + ... + lp_ix = be16_to_cpu(p->lp_ix); + +pvd points at a single kmalloc()'d struct pvd whose ppe[] member holds a +fixed ARRAY_SIZE(pvd->ppe) (1016) entries, but the loop runs up to the +on-disk pp_count. pp_count is an unvalidated __be16 read straight from +the descriptor, so a crafted AIX image with pp_count larger than 1016 +drives the loop to read pvd->ppe[i] past the end of the allocation (up +to 65535 entries, ~2 MB out of bounds). + +The partition scan runs without mounting anything, when a block device +with a crafted AIX/IBM partition table appears (an attacker-supplied +image attached with losetup -P, or a device auto-scanned by udev), via +msdos_partition() -> aix_partition(). + +Clamp the scan to the number of entries the ppe[] array can hold. + +Fixes: 6ceea22bbbc8 ("partitions: add aix lvm partition support files") +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Acked-by: Philippe De Muyter +Link: https://patch.msgid.link/20260607064137.302574-1-hexlabsecurity@proton.me +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + block/partitions/aix.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/block/partitions/aix.c ++++ b/block/partitions/aix.c +@@ -226,6 +226,15 @@ int aix_partition(struct parsed_partitio + int next_lp_ix = 1; + int lp_ix; + ++ /* ++ * pvd was read into a fixed-size struct pvd whose ppe[] array ++ * holds ARRAY_SIZE(pvd->ppe) entries. pp_count is an ++ * unvalidated on-disk __be16, so clamp the scan to the array ++ * size to avoid walking past the allocation. ++ */ ++ if (numpps > ARRAY_SIZE(pvd->ppe)) ++ numpps = ARRAY_SIZE(pvd->ppe); ++ + for (i = 0; i < numpps; i += 1) { + struct ppe *p = pvd->ppe + i; + unsigned int lv_ix; diff --git a/queue-7.1/series b/queue-7.1/series index 169da74d74..d5a1f879b2 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -339,3 +339,41 @@ usb-gadget-f_fs-initialize-epfile-in-early-to-fix-endpoint-direction-checks.patc usb-gadget-f_fs-tie-read_buffer-lifetime-to-ffs_epfile.patch block-skip-sync_blockdev-on-surprise-removal-in-bdev_mark_dead.patch wifi-mt76-mt7921-mt7925-fix-null-dereference-in-csa-.patch +udf-validate-free-block-extents-against-the-partition-length.patch +udf-validate-vat-header-length-against-the-vat-inode-size.patch +udf-validate-sparing-table-length-as-an-entry-count-not-a-byte-count.patch +hwrng-jh7110-fix-refcount-leak-in-starfive_trng_read.patch +crypto-atmel-sha204a-drop-hwrng-quality-reduction-for-atsha204a.patch +crypto-atmel-sha204a-fail-on-hwrng-registration-error-in-probe-path.patch +nvme-target-rdma-fix-ndev-refcount-leak-on-queue-connect.patch +block-partitions-fix-of_node-refcount-leak-in-of_partition.patch +dm-ioctl-report-an-error-if-a-device-has-no-table.patch +nvme-multipath-set-bio_remapped-on-bios-remapped-to-per-path-namespace-disks.patch +nvmet-fix-pre-auth-out-of-bounds-heap-read-in-discovery-get-log-page.patch +btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch +nvmet-auth-validate-reply-message-payload-bounds-against-transfer-length.patch +btrfs-check-and-set-extent_delalloc_new-before-clearing-extent_delalloc.patch +btrfs-do-not-trim-a-device-which-is-not-writeable.patch +partitions-aix-bound-the-pp_count-scan-to-the-ppe-array.patch +btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch +isofs-bound-rock-ridge-symlink-components-to-the-sl-record.patch +crypto-af_alg-remove-zero-copy-support-from-skcipher-and-aead.patch +crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps.patch +crypto-caam-use-print_hex_dump_devel-to-guard-key-hex-dumps-again.patch +crypto-chacha20poly1305-validate-poly1305-template-argument.patch +crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch +crypto-ecc-fix-carry-overflow-in-vli-multiplication.patch +crypto-hisi-trng-remove-crypto_rng-interface.patch +crypto-pcrypt-restore-callback-for-non-parallel-fallback.patch +crypto-tegra-fix-refcount-leak-in-tegra_se_host1x_submit.patch +crypto-loongson-select-crypto_rng.patch +crypto-loongson-remove-broken-and-unused-loongson-rng.patch +crypto-ccp-do-not-initialize-snp-for-sev-ioctls.patch +crypto-ccp-do-not-initialize-snp-for-ioctl-snp_commit.patch +crypto-ccp-do-not-initialize-snp-for-ioctl-snp_vlek_load.patch +crypto-ccp-do-not-initialize-snp-for-ioctl-snp_config.patch +crypto-drbg-fix-returning-success-on-failure-in-ctr_drbg.patch +crypto-drbg-fix-misaligned-writes-in-ctr_drbg-and-hash_drbg.patch +crypto-drbg-fix-ineffective-sanity-check.patch +crypto-drbg-fix-drbg_max_addtl-on-64-bit-kernels.patch +crypto-drbg-fix-the-fips_enabled-priority-boost.patch diff --git a/queue-7.1/udf-validate-free-block-extents-against-the-partition-length.patch b/queue-7.1/udf-validate-free-block-extents-against-the-partition-length.patch new file mode 100644 index 0000000000..73fffc5971 --- /dev/null +++ b/queue-7.1/udf-validate-free-block-extents-against-the-partition-length.patch @@ -0,0 +1,65 @@ +From 5f0419457f89dce1a3f1c8e62a3adf2f39ab8168 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 15 May 2026 10:23:27 -0400 +Subject: udf: validate free block extents against the partition length + +From: Michael Bommarito + +commit 5f0419457f89dce1a3f1c8e62a3adf2f39ab8168 upstream. + +udf_free_blocks() checks the logical block number and count against the +partition length, but drops the extent offset from that final bound. A +crafted extent can pass the guard while logicalBlockNum + offset + count +points past the partition, which later indexes past the space bitmap +array. + +A single ftruncate(2) on a file backed by such an extent reliably +panics the kernel. This is a local availability issue. On desktop +systems where UDisks/polkit allows the active user to mount removable +UDF media without CAP_SYS_ADMIN, an unprivileged local user can supply +the crafted filesystem and trigger the panic by truncating a writable +file on it. Systems that require root or CAP_SYS_ADMIN to mount the +image have a higher prerequisite. + +No confidentiality or integrity impact is claimed: the reproduced +primitive is an out-of-bounds read of a bitmap pointer slot followed by +a kernel panic. + +Use the already computed logicalBlockNum + offset + count value for the +partition length check. Also make load_block_bitmap() reject an +out-of-range block group before indexing s_block_bitmap[], so corrupted +callers cannot walk past the flexible array. + +Fixes: 56e69e59751d ("udf: prevent integer overflow in udf_bitmap_free_blocks()") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260515142327.1120767-1-michael.bommarito@gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/balloc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/udf/balloc.c ++++ b/fs/udf/balloc.c +@@ -82,8 +82,9 @@ static int load_block_bitmap(struct supe + int nr_groups = bitmap->s_nr_groups; + + if (block_group >= nr_groups) { +- udf_debug("block_group (%u) > nr_groups (%d)\n", ++ udf_debug("block_group (%u) >= nr_groups (%d)\n", + block_group, nr_groups); ++ return -EFSCORRUPTED; + } + + if (bitmap->s_block_bitmap[block_group]) { +@@ -662,7 +663,7 @@ void udf_free_blocks(struct super_block + + if (check_add_overflow(bloc->logicalBlockNum, offset, &blk) || + check_add_overflow(blk, count, &blk) || +- bloc->logicalBlockNum + count > map->s_partition_len) { ++ blk > map->s_partition_len) { + udf_debug("Invalid request to free blocks: (%d, %u), off %u, " + "len %u, partition len %u\n", + partition, bloc->logicalBlockNum, offset, count, diff --git a/queue-7.1/udf-validate-sparing-table-length-as-an-entry-count-not-a-byte-count.patch b/queue-7.1/udf-validate-sparing-table-length-as-an-entry-count-not-a-byte-count.patch new file mode 100644 index 0000000000..b8ede71088 --- /dev/null +++ b/queue-7.1/udf-validate-sparing-table-length-as-an-entry-count-not-a-byte-count.patch @@ -0,0 +1,57 @@ +From 3ec997bd5508e9b25210b5bbec89031629cdb093 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Fri, 12 Jun 2026 01:40:01 -0500 +Subject: udf: validate sparing table length as an entry count, not a byte count + +From: Bryam Vargas + +commit 3ec997bd5508e9b25210b5bbec89031629cdb093 upstream. + +udf_load_sparable_map() accepts a sparing table when + + sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > sb->s_blocksize + +is false, i.e. it treats reallocationTableLen as a number of BYTES that +must fit in the block. But the table is walked as an array of 8-byte +sparingEntry elements: + + for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) { + struct sparingEntry *entry = &st->mapEntry[i]; + ... entry->origLocation ... + } + +in udf_get_pblock_spar15() and udf_relocate_blocks(). A +reallocationTableLen of N therefore passes the check whenever +sizeof(*st) + N <= blocksize, yet the consumers index +sizeof(*st) + N * sizeof(struct sparingEntry) bytes -- up to ~8x the +block. On a crafted UDF image this is an out-of-bounds read in +udf_get_pblock_spar15(); udf_relocate_blocks() additionally feeds the +same length to udf_update_tag(), whose crc_itu_t() reads far past the +block, and its memmove() through st->mapEntry[] is an out-of-bounds +write. + +Validate reallocationTableLen as the entry count it is, with +struct_size(). + +Fixes: 1df2ae31c724 ("udf: Fortify loading of sparing table") +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Link: https://patch.msgid.link/20260612-b4-disp-91780c4e-v1-1-f15112ff6882@proton.me +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/super.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -1426,7 +1426,8 @@ static int udf_load_sparable_map(struct + if (ident != 0 || + strncmp(st->sparingIdent.ident, UDF_ID_SPARING, + strlen(UDF_ID_SPARING)) || +- sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > ++ struct_size(st, mapEntry, ++ le16_to_cpu(st->reallocationTableLen)) > + sb->s_blocksize) { + brelse(bh); + continue; diff --git a/queue-7.1/udf-validate-vat-header-length-against-the-vat-inode-size.patch b/queue-7.1/udf-validate-vat-header-length-against-the-vat-inode-size.patch new file mode 100644 index 0000000000..abf81fcdc6 --- /dev/null +++ b/queue-7.1/udf-validate-vat-header-length-against-the-vat-inode-size.patch @@ -0,0 +1,60 @@ +From d8202786b3d75125c84ebc4de6d946f92fde0ee8 Mon Sep 17 00:00:00 2001 +From: Bryam Vargas +Date: Fri, 12 Jun 2026 02:53:31 -0500 +Subject: udf: validate VAT header length against the VAT inode size + +From: Bryam Vargas + +commit d8202786b3d75125c84ebc4de6d946f92fde0ee8 upstream. + +udf_load_vat() takes the virtual partition's start offset straight from +the on-disk VAT 2.0 header without checking it against the VAT inode +size: + + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual.s_start_offset) >> 2; + +lengthHeader is a fully attacker-controlled 16-bit value. If it exceeds +the VAT inode size, the s_num_entries subtraction underflows to a huge +count, which defeats the "block > s_num_entries" bound in +udf_get_pblock_virt15(); and on the ICB-inline path that function reads + + ((__le32 *)(iinfo->i_data + s_start_offset))[block] + +so a large s_start_offset indexes past the inode's in-ICB data. Mounting +a crafted UDF image with a virtual (VAT) partition then triggers an +out-of-bounds read. + +Reject a VAT whose header length does not leave room for at least one +entry within the VAT inode. + +Fixes: fa5e08156335 ("udf: Handle VAT packed inside inode properly") +Cc: stable@vger.kernel.org +Signed-off-by: Bryam Vargas +Link: https://patch.msgid.link/20260612-b4-disp-9a2317ee-v1-1-fefef5736154@proton.me +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman +--- + fs/udf/super.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/udf/super.c ++++ b/fs/udf/super.c +@@ -1263,6 +1263,14 @@ static int udf_load_vat(struct super_blo + + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader); ++ if (map->s_type_specific.s_virtual.s_start_offset ++ > sbi->s_vat_inode->i_size) { ++ udf_err(sb, "Corrupted VAT header length %u (VAT inode size %lld)\n", ++ map->s_type_specific.s_virtual.s_start_offset, ++ sbi->s_vat_inode->i_size); ++ brelse(bh); ++ return -EFSCORRUPTED; ++ } + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual.