From 74eb8a81ec93208ea7c8cfeee3270afddd66c636 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 7 Feb 2026 16:38:17 +0100 Subject: [PATCH] 6.12-stable patches added patches: hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch tools-power-turbostat-fix-gcc9-build-regression.patch ublk-fix-deadlock-when-reading-partition-table.patch --- ...ut-of-bounds-read-in-hfsplus_uni2asc.patch | 176 ++++++++++++++++++ queue-6.12/series | 3 + ...-turbostat-fix-gcc9-build-regression.patch | 79 ++++++++ ...eadlock-when-reading-partition-table.patch | 107 +++++++++++ 4 files changed, 365 insertions(+) create mode 100644 queue-6.12/hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch create mode 100644 queue-6.12/tools-power-turbostat-fix-gcc9-build-regression.patch create mode 100644 queue-6.12/ublk-fix-deadlock-when-reading-partition-table.patch diff --git a/queue-6.12/hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch b/queue-6.12/hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch new file mode 100644 index 0000000000..9180de5145 --- /dev/null +++ b/queue-6.12/hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch @@ -0,0 +1,176 @@ +From bea3e1d4467bcf292c8e54f080353d556d355e26 Mon Sep 17 00:00:00 2001 +From: Kang Chen +Date: Tue, 9 Sep 2025 11:13:16 +0800 +Subject: hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc() + +From: Kang Chen + +commit bea3e1d4467bcf292c8e54f080353d556d355e26 upstream. + +BUG: KASAN: slab-out-of-bounds in hfsplus_uni2asc+0xa71/0xb90 fs/hfsplus/unicode.c:186 +Read of size 2 at addr ffff8880289ef218 by task syz.6.248/14290 + +CPU: 0 UID: 0 PID: 14290 Comm: syz.6.248 Not tainted 6.16.4 #1 PREEMPT(full) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 +Call Trace: + + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0x116/0x1b0 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xca/0x5f0 mm/kasan/report.c:482 + kasan_report+0xca/0x100 mm/kasan/report.c:595 + hfsplus_uni2asc+0xa71/0xb90 fs/hfsplus/unicode.c:186 + hfsplus_listxattr+0x5b6/0xbd0 fs/hfsplus/xattr.c:738 + vfs_listxattr+0xbe/0x140 fs/xattr.c:493 + listxattr+0xee/0x190 fs/xattr.c:924 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x143/0x360 fs/xattr.c:988 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xcb/0x4c0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7fe0e9fae16d +Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007fe0eae67f98 EFLAGS: 00000246 ORIG_RAX: 00000000000000c3 +RAX: ffffffffffffffda RBX: 00007fe0ea205fa0 RCX: 00007fe0e9fae16d +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000200000000000 +RBP: 00007fe0ea0480f0 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 00007fe0ea206038 R14: 00007fe0ea205fa0 R15: 00007fe0eae48000 + + +Allocated by task 14290: + kasan_save_stack+0x24/0x50 mm/kasan/common.c:47 + kasan_save_track+0x14/0x30 mm/kasan/common.c:68 + poison_kmalloc_redzone mm/kasan/common.c:377 [inline] + __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:394 + kasan_kmalloc include/linux/kasan.h:260 [inline] + __do_kmalloc_node mm/slub.c:4333 [inline] + __kmalloc_noprof+0x219/0x540 mm/slub.c:4345 + kmalloc_noprof include/linux/slab.h:909 [inline] + hfsplus_find_init+0x95/0x1f0 fs/hfsplus/bfind.c:21 + hfsplus_listxattr+0x331/0xbd0 fs/hfsplus/xattr.c:697 + vfs_listxattr+0xbe/0x140 fs/xattr.c:493 + listxattr+0xee/0x190 fs/xattr.c:924 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x143/0x360 fs/xattr.c:988 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xcb/0x4c0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +When hfsplus_uni2asc is called from hfsplus_listxattr, +it actually passes in a struct hfsplus_attr_unistr*. +The size of the corresponding structure is different from that of hfsplus_unistr, +so the previous fix (94458781aee6) is insufficient. +The pointer on the unicode buffer is still going beyond the allocated memory. + +This patch introduces two warpper functions hfsplus_uni2asc_xattr_str and +hfsplus_uni2asc_str to process two unicode buffers, +struct hfsplus_attr_unistr* and struct hfsplus_unistr* respectively. +When ustrlen value is bigger than the allocated memory size, +the ustrlen value is limited to an safe size. + +Fixes: 94458781aee6 ("hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc()") +Signed-off-by: Kang Chen +Reviewed-by: Viacheslav Dubeyko +Signed-off-by: Viacheslav Dubeyko +Link: https://lore.kernel.org/r/20250909031316.1647094-1-k.chen@smail.nju.edu.cn +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Jianqiang kang +Signed-off-by: Greg Kroah-Hartman +--- + fs/hfsplus/dir.c | 2 +- + fs/hfsplus/hfsplus_fs.h | 8 ++++++-- + fs/hfsplus/unicode.c | 24 +++++++++++++++++++----- + fs/hfsplus/xattr.c | 6 +++--- + 4 files changed, 29 insertions(+), 11 deletions(-) + +--- a/fs/hfsplus/dir.c ++++ b/fs/hfsplus/dir.c +@@ -204,7 +204,7 @@ static int hfsplus_readdir(struct file * + fd.entrylength); + type = be16_to_cpu(entry.type); + len = NLS_MAX_CHARSET_SIZE * HFSPLUS_MAX_STRLEN; +- err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); ++ err = hfsplus_uni2asc_str(sb, &fd.key->cat.name, strbuf, &len); + if (err) + goto out; + if (type == HFSPLUS_FOLDER) { +--- a/fs/hfsplus/hfsplus_fs.h ++++ b/fs/hfsplus/hfsplus_fs.h +@@ -519,8 +519,12 @@ int hfsplus_strcasecmp(const struct hfsp + const struct hfsplus_unistr *s2); + int hfsplus_strcmp(const struct hfsplus_unistr *s1, + const struct hfsplus_unistr *s2); +-int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, +- char *astr, int *len_p); ++int hfsplus_uni2asc_str(struct super_block *sb, ++ const struct hfsplus_unistr *ustr, char *astr, ++ int *len_p); ++int hfsplus_uni2asc_xattr_str(struct super_block *sb, ++ const struct hfsplus_attr_unistr *ustr, ++ char *astr, int *len_p); + int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, + int max_unistr_len, const char *astr, int len); + int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str); +--- a/fs/hfsplus/unicode.c ++++ b/fs/hfsplus/unicode.c +@@ -143,9 +143,8 @@ static u16 *hfsplus_compose_lookup(u16 * + return NULL; + } + +-int hfsplus_uni2asc(struct super_block *sb, +- const struct hfsplus_unistr *ustr, +- char *astr, int *len_p) ++static int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, ++ int max_len, char *astr, int *len_p) + { + const hfsplus_unichr *ip; + struct nls_table *nls = HFSPLUS_SB(sb)->nls; +@@ -158,8 +157,8 @@ int hfsplus_uni2asc(struct super_block * + ip = ustr->unicode; + + ustrlen = be16_to_cpu(ustr->length); +- if (ustrlen > HFSPLUS_MAX_STRLEN) { +- ustrlen = HFSPLUS_MAX_STRLEN; ++ if (ustrlen > max_len) { ++ ustrlen = max_len; + pr_err("invalid length %u has been corrected to %d\n", + be16_to_cpu(ustr->length), ustrlen); + } +@@ -280,6 +279,21 @@ out: + return res; + } + ++inline int hfsplus_uni2asc_str(struct super_block *sb, ++ const struct hfsplus_unistr *ustr, char *astr, ++ int *len_p) ++{ ++ return hfsplus_uni2asc(sb, ustr, HFSPLUS_MAX_STRLEN, astr, len_p); ++} ++ ++inline int hfsplus_uni2asc_xattr_str(struct super_block *sb, ++ const struct hfsplus_attr_unistr *ustr, ++ char *astr, int *len_p) ++{ ++ return hfsplus_uni2asc(sb, (const struct hfsplus_unistr *)ustr, ++ HFSPLUS_ATTR_MAX_STRLEN, astr, len_p); ++} ++ + /* + * Convert one or more ASCII characters into a single unicode character. + * Returns the number of ASCII characters corresponding to the unicode char. +--- a/fs/hfsplus/xattr.c ++++ b/fs/hfsplus/xattr.c +@@ -735,9 +735,9 @@ ssize_t hfsplus_listxattr(struct dentry + goto end_listxattr; + + xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN; +- if (hfsplus_uni2asc(inode->i_sb, +- (const struct hfsplus_unistr *)&fd.key->attr.key_name, +- strbuf, &xattr_name_len)) { ++ if (hfsplus_uni2asc_xattr_str(inode->i_sb, ++ &fd.key->attr.key_name, strbuf, ++ &xattr_name_len)) { + pr_err("unicode conversion failed\n"); + res = -EIO; + goto end_listxattr; diff --git a/queue-6.12/series b/queue-6.12/series index 9cdad4e854..c6d06c0ead 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -19,3 +19,6 @@ mm-shmem-prevent-infinite-loop-on-truncate-race.patch revert-drm-amd-check-if-aspm-is-enabled-from-pcie-subsystem.patch kvm-don-t-clobber-irqfd-routing-type-when-deassigning-irqfd.patch pci-err-ensure-error-recoverability-at-all-times.patch +tools-power-turbostat-fix-gcc9-build-regression.patch +ublk-fix-deadlock-when-reading-partition-table.patch +hfsplus-fix-slab-out-of-bounds-read-in-hfsplus_uni2asc.patch diff --git a/queue-6.12/tools-power-turbostat-fix-gcc9-build-regression.patch b/queue-6.12/tools-power-turbostat-fix-gcc9-build-regression.patch new file mode 100644 index 0000000000..f9c3fc3b14 --- /dev/null +++ b/queue-6.12/tools-power-turbostat-fix-gcc9-build-regression.patch @@ -0,0 +1,79 @@ +From d4a058762f3d931aa1159b64ba94a09a04024f8c Mon Sep 17 00:00:00 2001 +From: Todd Brandt +Date: Wed, 31 Jul 2024 12:24:09 -0400 +Subject: tools/power turbostat: fix GCC9 build regression + +From: Todd Brandt + +commit d4a058762f3d931aa1159b64ba94a09a04024f8c upstream. + +Fix build regression seen when using old gcc-9 compiler. + +Signed-off-by: Todd Brandt +Reviewed-by: Chen Yu +Signed-off-by: Len Brown +Signed-off-by: Nikolay Kuratov +Signed-off-by: Greg Kroah-Hartman +--- + tools/power/x86/turbostat/turbostat.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -2798,6 +2798,8 @@ int format_counters(struct thread_data * + } + + for (i = 0, ppmt = sys.pmt_tp; ppmt; i++, ppmt = ppmt->next) { ++ const unsigned long value_raw = t->pmt_counter[i]; ++ const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; + switch (ppmt->type) { + case PMT_TYPE_RAW: + if (pmt_counter_get_width(ppmt) <= 32) +@@ -2809,9 +2811,6 @@ int format_counters(struct thread_data * + break; + + case PMT_TYPE_XTAL_TIME: +- const unsigned long value_raw = t->pmt_counter[i]; +- const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; +- + outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted); + break; + } +@@ -2879,6 +2878,8 @@ int format_counters(struct thread_data * + } + + for (i = 0, ppmt = sys.pmt_cp; ppmt; i++, ppmt = ppmt->next) { ++ const unsigned long value_raw = c->pmt_counter[i]; ++ const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; + switch (ppmt->type) { + case PMT_TYPE_RAW: + if (pmt_counter_get_width(ppmt) <= 32) +@@ -2890,9 +2891,6 @@ int format_counters(struct thread_data * + break; + + case PMT_TYPE_XTAL_TIME: +- const unsigned long value_raw = c->pmt_counter[i]; +- const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; +- + outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted); + break; + } +@@ -3078,6 +3076,8 @@ int format_counters(struct thread_data * + } + + for (i = 0, ppmt = sys.pmt_pp; ppmt; i++, ppmt = ppmt->next) { ++ const unsigned long value_raw = p->pmt_counter[i]; ++ const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; + switch (ppmt->type) { + case PMT_TYPE_RAW: + if (pmt_counter_get_width(ppmt) <= 32) +@@ -3089,9 +3089,6 @@ int format_counters(struct thread_data * + break; + + case PMT_TYPE_XTAL_TIME: +- const unsigned long value_raw = p->pmt_counter[i]; +- const double value_converted = 100.0 * value_raw / crystal_hz / interval_float; +- + outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), value_converted); + break; + } diff --git a/queue-6.12/ublk-fix-deadlock-when-reading-partition-table.patch b/queue-6.12/ublk-fix-deadlock-when-reading-partition-table.patch new file mode 100644 index 0000000000..87c00fdcdd --- /dev/null +++ b/queue-6.12/ublk-fix-deadlock-when-reading-partition-table.patch @@ -0,0 +1,107 @@ +From c258f5c4502c9667bccf5d76fa731ab9c96687c1 Mon Sep 17 00:00:00 2001 +From: Ming Lei +Date: Fri, 12 Dec 2025 22:34:15 +0800 +Subject: ublk: fix deadlock when reading partition table + +From: Ming Lei + +commit c258f5c4502c9667bccf5d76fa731ab9c96687c1 upstream. + +When one process(such as udev) opens ublk block device (e.g., to read +the partition table via bdev_open()), a deadlock[1] can occur: + +1. bdev_open() grabs disk->open_mutex +2. The process issues read I/O to ublk backend to read partition table +3. In __ublk_complete_rq(), blk_update_request() or blk_mq_end_request() + runs bio->bi_end_io() callbacks +4. If this triggers fput() on file descriptor of ublk block device, the + work may be deferred to current task's task work (see fput() implementation) +5. This eventually calls blkdev_release() from the same context +6. blkdev_release() tries to grab disk->open_mutex again +7. Deadlock: same task waiting for a mutex it already holds + +The fix is to run blk_update_request() and blk_mq_end_request() with bottom +halves disabled. This forces blkdev_release() to run in kernel work-queue +context instead of current task work context, and allows ublk server to make +forward progress, and avoids the deadlock. + +Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") +Link: https://github.com/ublk-org/ublksrv/issues/170 [1] +Signed-off-by: Ming Lei +Reviewed-by: Caleb Sander Mateos +[axboe: rewrite comment in ublk] +Signed-off-by: Jens Axboe +[ The fix omits the change in __ublk_do_auto_buf_reg() since this function + doesn't exist in Linux 6.12. ] +Signed-off-by: Alva Lan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/ublk_drv.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -1020,6 +1020,13 @@ static inline bool ubq_daemon_is_dying(s + return ubq->ubq_daemon->flags & PF_EXITING; + } + ++static void ublk_end_request(struct request *req, blk_status_t error) ++{ ++ local_bh_disable(); ++ blk_mq_end_request(req, error); ++ local_bh_enable(); ++} ++ + /* todo: handle partial completion */ + static inline void __ublk_complete_rq(struct request *req) + { +@@ -1027,6 +1034,7 @@ static inline void __ublk_complete_rq(st + struct ublk_io *io = &ubq->ios[req->tag]; + unsigned int unmapped_bytes; + blk_status_t res = BLK_STS_OK; ++ bool requeue; + + /* called from ublk_abort_queue() code path */ + if (io->flags & UBLK_IO_FLAG_ABORTED) { +@@ -1064,14 +1072,30 @@ static inline void __ublk_complete_rq(st + if (unlikely(unmapped_bytes < io->res)) + io->res = unmapped_bytes; + +- if (blk_update_request(req, BLK_STS_OK, io->res)) ++ /* ++ * Run bio->bi_end_io() with softirqs disabled. If the final fput ++ * happens off this path, then that will prevent ublk's blkdev_release() ++ * from being called on current's task work, see fput() implementation. ++ * ++ * Otherwise, ublk server may not provide forward progress in case of ++ * reading the partition table from bdev_open() with disk->open_mutex ++ * held, and causes dead lock as we could already be holding ++ * disk->open_mutex here. ++ * ++ * Preferably we would not be doing IO with a mutex held that is also ++ * used for release, but this work-around will suffice for now. ++ */ ++ local_bh_disable(); ++ requeue = blk_update_request(req, BLK_STS_OK, io->res); ++ local_bh_enable(); ++ if (requeue) + blk_mq_requeue_request(req, true); + else + __blk_mq_end_request(req, BLK_STS_OK); + + return; + exit: +- blk_mq_end_request(req, res); ++ ublk_end_request(req, res); + } + + static void ublk_complete_rq(struct kref *ref) +@@ -1149,7 +1173,7 @@ static inline void __ublk_abort_rq(struc + if (ublk_nosrv_dev_should_queue_io(ubq->dev)) + blk_mq_requeue_request(rq, false); + else +- blk_mq_end_request(rq, BLK_STS_IOERR); ++ ublk_end_request(rq, BLK_STS_IOERR); + } + + static inline void __ublk_rq_task_work(struct request *req, -- 2.47.3