From: Greg Kroah-Hartman Date: Thu, 30 Jan 2025 09:53:13 +0000 (+0100) Subject: 6.13-stable patches X-Git-Tag: v6.13.1~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=63c7af68a2aa0822f6424c1fb22a0a8079867b05;p=thirdparty%2Fkernel%2Fstable-queue.git 6.13-stable patches added patches: cachestat-fix-page-cache-statistics-permission-checking.patch gfs2-truncate-address-space-when-flipping-gfs2_dif_jdata-flag.patch libfs-replace-simple_offset-end-of-directory-detection.patch libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch libfs-use-d_children-list-to-iterate-simple_offset-directories.patch net-sched-fix-ets-qdisc-oob-indexing.patch revert-hid-multitouch-add-support-for-lenovo-y9000p-touchpad.patch revert-libfs-add-simple_offset_empty.patch revert-libfs-fix-infinite-directory-reads-for-offset-dir.patch scsi-storvsc-ratelimit-warning-logs-to-prevent-vm-denial-of-service.patch smb-client-handle-lack-of-ea-support-in-smb2_query_path_info.patch vfio-platform-check-the-bounds-of-read-write-syscalls.patch --- diff --git a/queue-6.13/cachestat-fix-page-cache-statistics-permission-checking.patch b/queue-6.13/cachestat-fix-page-cache-statistics-permission-checking.patch new file mode 100644 index 00000000000..82103366325 --- /dev/null +++ b/queue-6.13/cachestat-fix-page-cache-statistics-permission-checking.patch @@ -0,0 +1,65 @@ +From 5f537664e705b0bf8b7e329861f20128534f6a83 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Tue, 21 Jan 2025 09:27:22 -0800 +Subject: cachestat: fix page cache statistics permission checking + +From: Linus Torvalds + +commit 5f537664e705b0bf8b7e329861f20128534f6a83 upstream. + +When the 'cachestat()' system call was added in commit cf264e1329fb +("cachestat: implement cachestat syscall"), it was meant to be a much +more convenient (and performant) version of mincore() that didn't need +mapping things into the user virtual address space in order to work. + +But it ended up missing the "check for writability or ownership" fix for +mincore(), done in commit 134fca9063ad ("mm/mincore.c: make mincore() +more conservative"). + +This just adds equivalent logic to 'cachestat()', modified for the file +context (rather than vma). + +Reported-by: Sudheendra Raghav Neela +Fixes: cf264e1329fb ("cachestat: implement cachestat syscall") +Tested-by: Johannes Weiner +Acked-by: Johannes Weiner +Acked-by: Nhat Pham +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +--- + mm/filemap.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -4376,6 +4376,20 @@ resched: + } + + /* ++ * See mincore: reveal pagecache information only for files ++ * that the calling process has write access to, or could (if ++ * tried) open for writing. ++ */ ++static inline bool can_do_cachestat(struct file *f) ++{ ++ if (f->f_mode & FMODE_WRITE) ++ return true; ++ if (inode_owner_or_capable(file_mnt_idmap(f), file_inode(f))) ++ return true; ++ return file_permission(f, MAY_WRITE) == 0; ++} ++ ++/* + * The cachestat(2) system call. + * + * cachestat() returns the page cache statistics of a file in the +@@ -4430,6 +4444,9 @@ SYSCALL_DEFINE4(cachestat, unsigned int, + if (is_file_hugepages(fd_file(f))) + return -EOPNOTSUPP; + ++ if (!can_do_cachestat(fd_file(f))) ++ return -EPERM; ++ + if (flags != 0) + return -EINVAL; + diff --git a/queue-6.13/gfs2-truncate-address-space-when-flipping-gfs2_dif_jdata-flag.patch b/queue-6.13/gfs2-truncate-address-space-when-flipping-gfs2_dif_jdata-flag.patch new file mode 100644 index 00000000000..4e0fcd60ea7 --- /dev/null +++ b/queue-6.13/gfs2-truncate-address-space-when-flipping-gfs2_dif_jdata-flag.patch @@ -0,0 +1,30 @@ +From 7c9d9223802fbed4dee1ae301661bf346964c9d2 Mon Sep 17 00:00:00 2001 +From: Andreas Gruenbacher +Date: Mon, 13 Jan 2025 19:31:28 +0100 +Subject: gfs2: Truncate address space when flipping GFS2_DIF_JDATA flag + +From: Andreas Gruenbacher + +commit 7c9d9223802fbed4dee1ae301661bf346964c9d2 upstream. + +Truncate an inode's address space when flipping the GFS2_DIF_JDATA flag: +depending on that flag, the pages in the address space will either use +buffer heads or iomap_folio_state structs, and we cannot mix the two. + +Reported-by: Kun Hu , Jiaji Qin +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Greg Kroah-Hartman +--- + fs/gfs2/file.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -251,6 +251,7 @@ static int do_gfs2_set_flags(struct inod + error = filemap_fdatawait(inode->i_mapping); + if (error) + goto out; ++ truncate_inode_pages(inode->i_mapping, 0); + if (new_flags & GFS2_DIF_JDATA) + gfs2_ordered_del_inode(ip); + } diff --git a/queue-6.13/libfs-replace-simple_offset-end-of-directory-detection.patch b/queue-6.13/libfs-replace-simple_offset-end-of-directory-detection.patch new file mode 100644 index 00000000000..d5d37e06879 --- /dev/null +++ b/queue-6.13/libfs-replace-simple_offset-end-of-directory-detection.patch @@ -0,0 +1,149 @@ +From 68a3a65003145644efcbb651e91db249ccd96281 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Sat, 28 Dec 2024 12:55:20 -0500 +Subject: libfs: Replace simple_offset end-of-directory detection + +From: Chuck Lever + +commit 68a3a65003145644efcbb651e91db249ccd96281 upstream. + +According to getdents(3), the d_off field in each returned directory +entry points to the next entry in the directory. The d_off field in +the last returned entry in the readdir buffer must contain a valid +offset value, but if it points to an actual directory entry, then +readdir/getdents can loop. + +This patch introduces a specific fixed offset value that is placed +in the d_off field of the last entry in a directory. Some user space +applications assume that the EOD offset value is larger than the +offsets of real directory entries, so the largest valid offset value +is reserved for this purpose. This new value is never allocated by +simple_offset_add(). + +When ->iterate_dir() returns, getdents{64} inserts the ctx->pos +value into the d_off field of the last valid entry in the readdir +buffer. When it hits EOD, offset_readdir() sets ctx->pos to the EOD +offset value so the last entry is updated to point to the EOD marker. + +When trying to read the entry at the EOD offset, offset_readdir() +terminates immediately. + +It is worth noting that using a Maple tree for directory offset +value allocation does not guarantee a 63-bit range of values -- +on platforms where "long" is a 32-bit type, the directory offset +value range is still 0..(2^31 - 1). For broad compatibility with +32-bit user space, the largest tmpfs directory cookie value is now +S32_MAX. + +Fixes: 796432efab1e ("libfs: getdents() should return 0 after reaching EOD") +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/20241228175522.1854234-5-cel@kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/libfs.c | 37 +++++++++++++++++++++---------------- + 1 file changed, 21 insertions(+), 16 deletions(-) + +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -245,9 +245,15 @@ const struct inode_operations simple_dir + }; + EXPORT_SYMBOL(simple_dir_inode_operations); + +-/* 0 is '.', 1 is '..', so always start with offset 2 or more */ ++/* simple_offset_add() never assigns these to a dentry */ + enum { +- DIR_OFFSET_MIN = 2, ++ DIR_OFFSET_EOD = S32_MAX, ++}; ++ ++/* simple_offset_add() allocation range */ ++enum { ++ DIR_OFFSET_MIN = 2, ++ DIR_OFFSET_MAX = DIR_OFFSET_EOD - 1, + }; + + static void offset_set(struct dentry *dentry, long offset) +@@ -291,7 +297,8 @@ int simple_offset_add(struct offset_ctx + return -EBUSY; + + ret = mtree_alloc_cyclic(&octx->mt, &offset, dentry, DIR_OFFSET_MIN, +- LONG_MAX, &octx->next_offset, GFP_KERNEL); ++ DIR_OFFSET_MAX, &octx->next_offset, ++ GFP_KERNEL); + if (unlikely(ret < 0)) + return ret == -EBUSY ? -ENOSPC : ret; + +@@ -447,8 +454,6 @@ static loff_t offset_dir_llseek(struct f + return -EINVAL; + } + +- /* In this case, ->private_data is protected by f_pos_lock */ +- file->private_data = NULL; + return vfs_setpos(file, offset, LONG_MAX); + } + +@@ -458,7 +463,7 @@ static struct dentry *offset_find_next(s + struct dentry *child, *found = NULL; + + rcu_read_lock(); +- child = mas_find(&mas, LONG_MAX); ++ child = mas_find(&mas, DIR_OFFSET_MAX); + if (!child) + goto out; + spin_lock(&child->d_lock); +@@ -479,7 +484,7 @@ static bool offset_dir_emit(struct dir_c + inode->i_ino, fs_umode_to_dtype(inode->i_mode)); + } + +-static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) ++static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx) + { + struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode); + struct dentry *dentry; +@@ -487,7 +492,7 @@ static void *offset_iterate_dir(struct i + while (true) { + dentry = offset_find_next(octx, ctx->pos); + if (!dentry) +- return ERR_PTR(-ENOENT); ++ goto out_eod; + + if (!offset_dir_emit(ctx, dentry)) { + dput(dentry); +@@ -497,7 +502,10 @@ static void *offset_iterate_dir(struct i + ctx->pos = dentry2offset(dentry) + 1; + dput(dentry); + } +- return NULL; ++ return; ++ ++out_eod: ++ ctx->pos = DIR_OFFSET_EOD; + } + + /** +@@ -517,6 +525,8 @@ static void *offset_iterate_dir(struct i + * + * On return, @ctx->pos contains an offset that will read the next entry + * in this directory when offset_readdir() is called again with @ctx. ++ * Caller places this value in the d_off field of the last entry in the ++ * user's buffer. + * + * Return values: + * %0 - Complete +@@ -529,13 +539,8 @@ static int offset_readdir(struct file *f + + if (!dir_emit_dots(file, ctx)) + return 0; +- +- /* In this case, ->private_data is protected by f_pos_lock */ +- if (ctx->pos == DIR_OFFSET_MIN) +- file->private_data = NULL; +- else if (file->private_data == ERR_PTR(-ENOENT)) +- return 0; +- file->private_data = offset_iterate_dir(d_inode(dir), ctx); ++ if (ctx->pos != DIR_OFFSET_EOD) ++ offset_iterate_dir(d_inode(dir), ctx); + return 0; + } + diff --git a/queue-6.13/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch b/queue-6.13/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch new file mode 100644 index 00000000000..5298a3f26c8 --- /dev/null +++ b/queue-6.13/libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch @@ -0,0 +1,46 @@ +From 903dc9c43a155e0893280c7472d4a9a3a83d75a6 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Sat, 28 Dec 2024 12:55:17 -0500 +Subject: libfs: Return ENOSPC when the directory offset range is exhausted + +From: Chuck Lever + +commit 903dc9c43a155e0893280c7472d4a9a3a83d75a6 upstream. + +Testing shows that the EBUSY error return from mtree_alloc_cyclic() +leaks into user space. The ERRORS section of "man creat(2)" says: + +> EBUSY O_EXCL was specified in flags and pathname refers +> to a block device that is in use by the system +> (e.g., it is mounted). + +ENOSPC is closer to what applications expect in this situation. + +Note that the normal range of simple directory offset values is +2..2^63, so hitting this error is going to be rare to impossible. + +Fixes: 6faddda69f62 ("libfs: Add directory operations for stable offsets") +Cc: stable@vger.kernel.org # v6.9+ +Reviewed-by: Jeff Layton +Reviewed-by: Yang Erkun +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/20241228175522.1854234-2-cel@kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/libfs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -292,8 +292,8 @@ int simple_offset_add(struct offset_ctx + + ret = mtree_alloc_cyclic(&octx->mt, &offset, dentry, DIR_OFFSET_MIN, + LONG_MAX, &octx->next_offset, GFP_KERNEL); +- if (ret < 0) +- return ret; ++ if (unlikely(ret < 0)) ++ return ret == -EBUSY ? -ENOSPC : ret; + + offset_set(dentry, offset); + return 0; diff --git a/queue-6.13/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch b/queue-6.13/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch new file mode 100644 index 00000000000..15ff9f29a17 --- /dev/null +++ b/queue-6.13/libfs-use-d_children-list-to-iterate-simple_offset-directories.patch @@ -0,0 +1,171 @@ +From b9b588f22a0c049a14885399e27625635ae6ef91 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Sat, 28 Dec 2024 12:55:21 -0500 +Subject: libfs: Use d_children list to iterate simple_offset directories + +From: Chuck Lever + +commit b9b588f22a0c049a14885399e27625635ae6ef91 upstream. + +The mtree mechanism has been effective at creating directory offsets +that are stable over multiple opendir instances. However, it has not +been able to handle the subtleties of renames that are concurrent +with readdir. + +Instead of using the mtree to emit entries in the order of their +offset values, use it only to map incoming ctx->pos to a starting +entry. Then use the directory's d_children list, which is already +maintained properly by the dcache, to find the next child to emit. + +One of the sneaky things about this is that when the mtree-allocated +offset value wraps (which is very rare), looking up ctx->pos++ is +not going to find the next entry; it will return NULL. Instead, by +following the d_children list, the offset values can appear in any +order but all of the entries in the directory will be visited +eventually. + +Note also that the readdir() is guaranteed to reach the tail of this +list. Entries are added only at the head of d_children, and readdir +walks from its current position in that list towards its tail. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/20241228175522.1854234-6-cel@kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/libfs.c | 84 ++++++++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 58 insertions(+), 26 deletions(-) + +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -247,12 +247,13 @@ EXPORT_SYMBOL(simple_dir_inode_operation + + /* simple_offset_add() never assigns these to a dentry */ + enum { ++ DIR_OFFSET_FIRST = 2, /* Find first real entry */ + DIR_OFFSET_EOD = S32_MAX, + }; + + /* simple_offset_add() allocation range */ + enum { +- DIR_OFFSET_MIN = 2, ++ DIR_OFFSET_MIN = DIR_OFFSET_FIRST + 1, + DIR_OFFSET_MAX = DIR_OFFSET_EOD - 1, + }; + +@@ -457,51 +458,82 @@ static loff_t offset_dir_llseek(struct f + return vfs_setpos(file, offset, LONG_MAX); + } + +-static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset) ++static struct dentry *find_positive_dentry(struct dentry *parent, ++ struct dentry *dentry, ++ bool next) ++{ ++ struct dentry *found = NULL; ++ ++ spin_lock(&parent->d_lock); ++ if (next) ++ dentry = d_next_sibling(dentry); ++ else if (!dentry) ++ dentry = d_first_child(parent); ++ hlist_for_each_entry_from(dentry, d_sib) { ++ if (!simple_positive(dentry)) ++ continue; ++ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); ++ if (simple_positive(dentry)) ++ found = dget_dlock(dentry); ++ spin_unlock(&dentry->d_lock); ++ if (likely(found)) ++ break; ++ } ++ spin_unlock(&parent->d_lock); ++ return found; ++} ++ ++static noinline_for_stack struct dentry * ++offset_dir_lookup(struct dentry *parent, loff_t offset) + { +- MA_STATE(mas, &octx->mt, offset, offset); ++ struct inode *inode = d_inode(parent); ++ struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode); + struct dentry *child, *found = NULL; + +- rcu_read_lock(); +- child = mas_find(&mas, DIR_OFFSET_MAX); +- if (!child) +- goto out; +- spin_lock(&child->d_lock); +- if (simple_positive(child)) +- found = dget_dlock(child); +- spin_unlock(&child->d_lock); +-out: +- rcu_read_unlock(); ++ MA_STATE(mas, &octx->mt, offset, offset); ++ ++ if (offset == DIR_OFFSET_FIRST) ++ found = find_positive_dentry(parent, NULL, false); ++ else { ++ rcu_read_lock(); ++ child = mas_find(&mas, DIR_OFFSET_MAX); ++ found = find_positive_dentry(parent, child, false); ++ rcu_read_unlock(); ++ } + return found; + } + + static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry) + { + struct inode *inode = d_inode(dentry); +- long offset = dentry2offset(dentry); + +- return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset, +- inode->i_ino, fs_umode_to_dtype(inode->i_mode)); ++ return dir_emit(ctx, dentry->d_name.name, dentry->d_name.len, ++ inode->i_ino, fs_umode_to_dtype(inode->i_mode)); + } + +-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx) ++static void offset_iterate_dir(struct file *file, struct dir_context *ctx) + { +- struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode); ++ struct dentry *dir = file->f_path.dentry; + struct dentry *dentry; + ++ dentry = offset_dir_lookup(dir, ctx->pos); ++ if (!dentry) ++ goto out_eod; + while (true) { +- dentry = offset_find_next(octx, ctx->pos); +- if (!dentry) +- goto out_eod; ++ struct dentry *next; + +- if (!offset_dir_emit(ctx, dentry)) { +- dput(dentry); ++ ctx->pos = dentry2offset(dentry); ++ if (!offset_dir_emit(ctx, dentry)) + break; +- } + +- ctx->pos = dentry2offset(dentry) + 1; ++ next = find_positive_dentry(dir, dentry, true); + dput(dentry); ++ ++ if (!next) ++ goto out_eod; ++ dentry = next; + } ++ dput(dentry); + return; + + out_eod: +@@ -540,7 +572,7 @@ static int offset_readdir(struct file *f + if (!dir_emit_dots(file, ctx)) + return 0; + if (ctx->pos != DIR_OFFSET_EOD) +- offset_iterate_dir(d_inode(dir), ctx); ++ offset_iterate_dir(file, ctx); + return 0; + } + diff --git a/queue-6.13/net-sched-fix-ets-qdisc-oob-indexing.patch b/queue-6.13/net-sched-fix-ets-qdisc-oob-indexing.patch new file mode 100644 index 00000000000..33b543d472f --- /dev/null +++ b/queue-6.13/net-sched-fix-ets-qdisc-oob-indexing.patch @@ -0,0 +1,91 @@ +From d62b04fca4340a0d468d7853bd66e511935a18cb Mon Sep 17 00:00:00 2001 +From: Jamal Hadi Salim +Date: Sat, 11 Jan 2025 09:57:39 -0500 +Subject: net: sched: fix ets qdisc OOB Indexing + +From: Jamal Hadi Salim + +commit d62b04fca4340a0d468d7853bd66e511935a18cb upstream. + +Haowei Yan found that ets_class_from_arg() can +index an Out-Of-Bound class in ets_class_from_arg() when passed clid of +0. The overflow may cause local privilege escalation. + + [ 18.852298] ------------[ cut here ]------------ + [ 18.853271] UBSAN: array-index-out-of-bounds in net/sched/sch_ets.c:93:20 + [ 18.853743] index 18446744073709551615 is out of range for type 'ets_class [16]' + [ 18.854254] CPU: 0 UID: 0 PID: 1275 Comm: poc Not tainted 6.12.6-dirty #17 + [ 18.854821] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 + [ 18.856532] Call Trace: + [ 18.857441] + [ 18.858227] dump_stack_lvl+0xc2/0xf0 + [ 18.859607] dump_stack+0x10/0x20 + [ 18.860908] __ubsan_handle_out_of_bounds+0xa7/0xf0 + [ 18.864022] ets_class_change+0x3d6/0x3f0 + [ 18.864322] tc_ctl_tclass+0x251/0x910 + [ 18.864587] ? lock_acquire+0x5e/0x140 + [ 18.865113] ? __mutex_lock+0x9c/0xe70 + [ 18.866009] ? __mutex_lock+0xa34/0xe70 + [ 18.866401] rtnetlink_rcv_msg+0x170/0x6f0 + [ 18.866806] ? __lock_acquire+0x578/0xc10 + [ 18.867184] ? __pfx_rtnetlink_rcv_msg+0x10/0x10 + [ 18.867503] netlink_rcv_skb+0x59/0x110 + [ 18.867776] rtnetlink_rcv+0x15/0x30 + [ 18.868159] netlink_unicast+0x1c3/0x2b0 + [ 18.868440] netlink_sendmsg+0x239/0x4b0 + [ 18.868721] ____sys_sendmsg+0x3e2/0x410 + [ 18.869012] ___sys_sendmsg+0x88/0xe0 + [ 18.869276] ? rseq_ip_fixup+0x198/0x260 + [ 18.869563] ? rseq_update_cpu_node_id+0x10a/0x190 + [ 18.869900] ? trace_hardirqs_off+0x5a/0xd0 + [ 18.870196] ? syscall_exit_to_user_mode+0xcc/0x220 + [ 18.870547] ? do_syscall_64+0x93/0x150 + [ 18.870821] ? __memcg_slab_free_hook+0x69/0x290 + [ 18.871157] __sys_sendmsg+0x69/0xd0 + [ 18.871416] __x64_sys_sendmsg+0x1d/0x30 + [ 18.871699] x64_sys_call+0x9e2/0x2670 + [ 18.871979] do_syscall_64+0x87/0x150 + [ 18.873280] ? do_syscall_64+0x93/0x150 + [ 18.874742] ? lock_release+0x7b/0x160 + [ 18.876157] ? do_user_addr_fault+0x5ce/0x8f0 + [ 18.877833] ? irqentry_exit_to_user_mode+0xc2/0x210 + [ 18.879608] ? irqentry_exit+0x77/0xb0 + [ 18.879808] ? clear_bhb_loop+0x15/0x70 + [ 18.880023] ? clear_bhb_loop+0x15/0x70 + [ 18.880223] ? clear_bhb_loop+0x15/0x70 + [ 18.880426] entry_SYSCALL_64_after_hwframe+0x76/0x7e + [ 18.880683] RIP: 0033:0x44a957 + [ 18.880851] Code: ff ff e8 fc 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 8974 24 10 + [ 18.881766] RSP: 002b:00007ffcdd00fad8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e + [ 18.882149] RAX: ffffffffffffffda RBX: 00007ffcdd010db8 RCX: 000000000044a957 + [ 18.882507] RDX: 0000000000000000 RSI: 00007ffcdd00fb70 RDI: 0000000000000003 + [ 18.885037] RBP: 00007ffcdd010bc0 R08: 000000000703c770 R09: 000000000703c7c0 + [ 18.887203] R10: 0000000000000080 R11: 0000000000000246 R12: 0000000000000001 + [ 18.888026] R13: 00007ffcdd010da8 R14: 00000000004ca7d0 R15: 0000000000000001 + [ 18.888395] + [ 18.888610] ---[ end trace ]--- + +Fixes: dcc68b4d8084 ("net: sch_ets: Add a new Qdisc") +Reported-by: Haowei Yan +Suggested-by: Haowei Yan +Signed-off-by: Jamal Hadi Salim +Reviewed-by: Eric Dumazet +Reviewed-by: Petr Machata +Link: https://patch.msgid.link/20250111145740.74755-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/sched/sch_ets.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/sched/sch_ets.c ++++ b/net/sched/sch_ets.c +@@ -91,6 +91,8 @@ ets_class_from_arg(struct Qdisc *sch, un + { + struct ets_sched *q = qdisc_priv(sch); + ++ if (arg == 0 || arg > q->nbands) ++ return NULL; + return &q->classes[arg - 1]; + } + diff --git a/queue-6.13/revert-hid-multitouch-add-support-for-lenovo-y9000p-touchpad.patch b/queue-6.13/revert-hid-multitouch-add-support-for-lenovo-y9000p-touchpad.patch new file mode 100644 index 00000000000..5b163f89975 --- /dev/null +++ b/queue-6.13/revert-hid-multitouch-add-support-for-lenovo-y9000p-touchpad.patch @@ -0,0 +1,76 @@ +From 3d88ba86ba6f35a0467f25a88c38aa5639190d04 Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Thu, 12 Dec 2024 09:53:10 +0100 +Subject: Revert "HID: multitouch: Add support for lenovo Y9000P Touchpad" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jiri Kosina + +commit 3d88ba86ba6f35a0467f25a88c38aa5639190d04 upstream. + +This reverts commit 251efae73bd46b097deec4f9986d926813aed744. + +Quoting Wang Yuli: + + "The 27C6:01E0 touchpad doesn't require the workaround and applying it + would actually break functionality. + + The initial report came from a BBS forum, but we suspect the + information provided by the forum user may be incorrect which could + happen sometimes. [1] + + Further investigation showed that the Lenovo Y9000P 2024 doesn't even + use a Goodix touchpad. [2] + + For the broader issue of 27c6:01e0 being unusable on some devices, it + just need to address it with a libinput quirk. + + In conclusion, we should revert this commit, which is the best + solution." + +Reported-by: Ulrich Müller +Reported-by: WangYuli +Link: https://lore.kernel.org/all/uikt4wwpw@gentoo.org/ +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-ids.h | 1 - + drivers/hid/hid-multitouch.c | 8 ++------ + 2 files changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -506,7 +506,6 @@ + #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 + + #define I2C_VENDOR_ID_GOODIX 0x27c6 +-#define I2C_DEVICE_ID_GOODIX_01E0 0x01e0 + #define I2C_DEVICE_ID_GOODIX_01E8 0x01e8 + #define I2C_DEVICE_ID_GOODIX_01E9 0x01e9 + #define I2C_DEVICE_ID_GOODIX_01F0 0x01f0 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -1460,8 +1460,7 @@ static const __u8 *mt_report_fixup(struc + { + if (hdev->vendor == I2C_VENDOR_ID_GOODIX && + (hdev->product == I2C_DEVICE_ID_GOODIX_01E8 || +- hdev->product == I2C_DEVICE_ID_GOODIX_01E9 || +- hdev->product == I2C_DEVICE_ID_GOODIX_01E0)) { ++ hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) { + if (rdesc[607] == 0x15) { + rdesc[607] = 0x25; + dev_info( +@@ -2085,10 +2084,7 @@ static const struct hid_device_id mt_dev + I2C_DEVICE_ID_GOODIX_01E8) }, + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, + HID_DEVICE(BUS_I2C, HID_GROUP_ANY, I2C_VENDOR_ID_GOODIX, +- I2C_DEVICE_ID_GOODIX_01E9) }, +- { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, +- HID_DEVICE(BUS_I2C, HID_GROUP_ANY, I2C_VENDOR_ID_GOODIX, +- I2C_DEVICE_ID_GOODIX_01E0) }, ++ I2C_DEVICE_ID_GOODIX_01E8) }, + + /* GoodTouch panels */ + { .driver_data = MT_CLS_NSMU, diff --git a/queue-6.13/revert-libfs-add-simple_offset_empty.patch b/queue-6.13/revert-libfs-add-simple_offset_empty.patch new file mode 100644 index 00000000000..5ceef5595a2 --- /dev/null +++ b/queue-6.13/revert-libfs-add-simple_offset_empty.patch @@ -0,0 +1,99 @@ +From d7bde4f27ceef3dc6d72010a20d4da23db835a32 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Sat, 28 Dec 2024 12:55:18 -0500 +Subject: Revert "libfs: Add simple_offset_empty()" + +From: Chuck Lever + +commit d7bde4f27ceef3dc6d72010a20d4da23db835a32 upstream. + +simple_empty() and simple_offset_empty() perform the same task. +The latter's use as a canary to find bugs has not found any new +issues. A subsequent patch will remove the use of the mtree for +iterating directory contents, so revert back to using a similar +mechanism for determining whether a directory is indeed empty. + +Only one such mechanism is ever needed. + +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/20241228175522.1854234-3-cel@kernel.org +Reviewed-by: Yang Erkun +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/libfs.c | 32 -------------------------------- + include/linux/fs.h | 1 - + mm/shmem.c | 4 ++-- + 3 files changed, 2 insertions(+), 35 deletions(-) + +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -330,38 +330,6 @@ void simple_offset_remove(struct offset_ + } + + /** +- * simple_offset_empty - Check if a dentry can be unlinked +- * @dentry: dentry to be tested +- * +- * Returns 0 if @dentry is a non-empty directory; otherwise returns 1. +- */ +-int simple_offset_empty(struct dentry *dentry) +-{ +- struct inode *inode = d_inode(dentry); +- struct offset_ctx *octx; +- struct dentry *child; +- unsigned long index; +- int ret = 1; +- +- if (!inode || !S_ISDIR(inode->i_mode)) +- return ret; +- +- index = DIR_OFFSET_MIN; +- octx = inode->i_op->get_offset_ctx(inode); +- mt_for_each(&octx->mt, child, index, LONG_MAX) { +- spin_lock(&child->d_lock); +- if (simple_positive(child)) { +- spin_unlock(&child->d_lock); +- ret = 0; +- break; +- } +- spin_unlock(&child->d_lock); +- } +- +- return ret; +-} +- +-/** + * simple_offset_rename - handle directory offsets for rename + * @old_dir: parent directory of source entry + * @old_dentry: dentry of source entry +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -3468,7 +3468,6 @@ struct offset_ctx { + void simple_offset_init(struct offset_ctx *octx); + int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry); + void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry); +-int simple_offset_empty(struct dentry *dentry); + int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); + int simple_offset_rename_exchange(struct inode *old_dir, +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -3821,7 +3821,7 @@ static int shmem_unlink(struct inode *di + + static int shmem_rmdir(struct inode *dir, struct dentry *dentry) + { +- if (!simple_offset_empty(dentry)) ++ if (!simple_empty(dentry)) + return -ENOTEMPTY; + + drop_nlink(d_inode(dentry)); +@@ -3878,7 +3878,7 @@ static int shmem_rename2(struct mnt_idma + return simple_offset_rename_exchange(old_dir, old_dentry, + new_dir, new_dentry); + +- if (!simple_offset_empty(new_dentry)) ++ if (!simple_empty(new_dentry)) + return -ENOTEMPTY; + + if (flags & RENAME_WHITEOUT) { diff --git a/queue-6.13/revert-libfs-fix-infinite-directory-reads-for-offset-dir.patch b/queue-6.13/revert-libfs-fix-infinite-directory-reads-for-offset-dir.patch new file mode 100644 index 00000000000..41a76749e46 --- /dev/null +++ b/queue-6.13/revert-libfs-fix-infinite-directory-reads-for-offset-dir.patch @@ -0,0 +1,149 @@ +From b662d858131da9a8a14e68661656989b14dbf113 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Sat, 28 Dec 2024 12:55:19 -0500 +Subject: Revert "libfs: fix infinite directory reads for offset dir" + +From: Chuck Lever + +commit b662d858131da9a8a14e68661656989b14dbf113 upstream. + +The current directory offset allocator (based on mtree_alloc_cyclic) +stores the next offset value to return in octx->next_offset. This +mechanism typically returns values that increase monotonically over +time. Eventually, though, the newly allocated offset value wraps +back to a low number (say, 2) which is smaller than other already- +allocated offset values. + +Yu Kuai reports that, after commit 64a7ce76fb90 +("libfs: fix infinite directory reads for offset dir"), if a +directory's offset allocator wraps, existing entries are no longer +visible via readdir/getdents because offset_readdir() stops listing +entries once an entry's offset is larger than octx->next_offset. +These entries vanish persistently -- they can be looked up, but will +never again appear in readdir(3) output. + +The reason for this is that the commit treats directory offsets as +monotonically increasing integer values rather than opaque cookies, +and introduces this comparison: + + if (dentry2offset(dentry) >= last_index) { + +On 64-bit platforms, the directory offset value upper bound is +2^63 - 1. Directory offsets will monotonically increase for millions +of years without wrapping. + +On 32-bit platforms, however, LONG_MAX is 2^31 - 1. The allocator +can wrap after only a few weeks (at worst). + +Revert commit 64a7ce76fb90 ("libfs: fix infinite directory reads for +offset dir") to prepare for a fix that can work properly on 32-bit +systems and might apply to recent LTS kernels where shmem employs +the simple_offset mechanism. + +Reported-by: Yu Kuai +Signed-off-by: Chuck Lever +Link: https://lore.kernel.org/r/20241228175522.1854234-4-cel@kernel.org +Reviewed-by: Yang Erkun +Signed-off-by: Christian Brauner +Signed-off-by: Greg Kroah-Hartman +--- + fs/libfs.c | 35 +++++++++++------------------------ + 1 file changed, 11 insertions(+), 24 deletions(-) + +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -422,14 +422,6 @@ void simple_offset_destroy(struct offset + mtree_destroy(&octx->mt); + } + +-static int offset_dir_open(struct inode *inode, struct file *file) +-{ +- struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode); +- +- file->private_data = (void *)ctx->next_offset; +- return 0; +-} +- + /** + * offset_dir_llseek - Advance the read position of a directory descriptor + * @file: an open directory whose position is to be updated +@@ -443,9 +435,6 @@ static int offset_dir_open(struct inode + */ + static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence) + { +- struct inode *inode = file->f_inode; +- struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode); +- + switch (whence) { + case SEEK_CUR: + offset += file->f_pos; +@@ -459,8 +448,7 @@ static loff_t offset_dir_llseek(struct f + } + + /* In this case, ->private_data is protected by f_pos_lock */ +- if (!offset) +- file->private_data = (void *)ctx->next_offset; ++ file->private_data = NULL; + return vfs_setpos(file, offset, LONG_MAX); + } + +@@ -491,7 +479,7 @@ static bool offset_dir_emit(struct dir_c + inode->i_ino, fs_umode_to_dtype(inode->i_mode)); + } + +-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx, long last_index) ++static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) + { + struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode); + struct dentry *dentry; +@@ -499,21 +487,17 @@ static void offset_iterate_dir(struct in + while (true) { + dentry = offset_find_next(octx, ctx->pos); + if (!dentry) +- return; +- +- if (dentry2offset(dentry) >= last_index) { +- dput(dentry); +- return; +- } ++ return ERR_PTR(-ENOENT); + + if (!offset_dir_emit(ctx, dentry)) { + dput(dentry); +- return; ++ break; + } + + ctx->pos = dentry2offset(dentry) + 1; + dput(dentry); + } ++ return NULL; + } + + /** +@@ -540,19 +524,22 @@ static void offset_iterate_dir(struct in + static int offset_readdir(struct file *file, struct dir_context *ctx) + { + struct dentry *dir = file->f_path.dentry; +- long last_index = (long)file->private_data; + + lockdep_assert_held(&d_inode(dir)->i_rwsem); + + if (!dir_emit_dots(file, ctx)) + return 0; + +- offset_iterate_dir(d_inode(dir), ctx, last_index); ++ /* In this case, ->private_data is protected by f_pos_lock */ ++ if (ctx->pos == DIR_OFFSET_MIN) ++ file->private_data = NULL; ++ else if (file->private_data == ERR_PTR(-ENOENT)) ++ return 0; ++ file->private_data = offset_iterate_dir(d_inode(dir), ctx); + return 0; + } + + const struct file_operations simple_offset_dir_operations = { +- .open = offset_dir_open, + .llseek = offset_dir_llseek, + .iterate_shared = offset_readdir, + .read = generic_read_dir, diff --git a/queue-6.13/scsi-storvsc-ratelimit-warning-logs-to-prevent-vm-denial-of-service.patch b/queue-6.13/scsi-storvsc-ratelimit-warning-logs-to-prevent-vm-denial-of-service.patch new file mode 100644 index 00000000000..1aef74b037d --- /dev/null +++ b/queue-6.13/scsi-storvsc-ratelimit-warning-logs-to-prevent-vm-denial-of-service.patch @@ -0,0 +1,48 @@ +From d2138eab8cde61e0e6f62d0713e45202e8457d6d Mon Sep 17 00:00:00 2001 +From: Easwar Hariharan +Date: Tue, 7 Jan 2025 17:28:40 +0000 +Subject: scsi: storvsc: Ratelimit warning logs to prevent VM denial of service + +From: Easwar Hariharan + +commit d2138eab8cde61e0e6f62d0713e45202e8457d6d upstream. + +If there's a persistent error in the hypervisor, the SCSI warning for +failed I/O can flood the kernel log and max out CPU utilization, +preventing troubleshooting from the VM side. Ratelimit the warning so +it doesn't DoS the VM. + +Closes: https://github.com/microsoft/WSL/issues/9173 +Signed-off-by: Easwar Hariharan +Link: https://lore.kernel.org/r/20250107-eahariha-ratelimit-storvsc-v1-1-7fc193d1f2b0@linux.microsoft.com +Reviewed-by: Michael Kelley +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/storvsc_drv.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -171,6 +171,12 @@ do { \ + dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \ + } while (0) + ++#define storvsc_log_ratelimited(dev, level, fmt, ...) \ ++do { \ ++ if (do_logging(level)) \ ++ dev_warn_ratelimited(&(dev)->device, fmt, ##__VA_ARGS__); \ ++} while (0) ++ + struct vmscsi_request { + u16 length; + u8 srb_status; +@@ -1177,7 +1183,7 @@ static void storvsc_on_io_completion(str + int loglevel = (stor_pkt->vm_srb.cdb[0] == TEST_UNIT_READY) ? + STORVSC_LOGGING_WARN : STORVSC_LOGGING_ERROR; + +- storvsc_log(device, loglevel, ++ storvsc_log_ratelimited(device, loglevel, + "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n", + scsi_cmd_to_rq(request->cmd)->tag, + stor_pkt->vm_srb.cdb[0], diff --git a/queue-6.13/series b/queue-6.13/series index e69de29bb2d..a3a5682f719 100644 --- a/queue-6.13/series +++ b/queue-6.13/series @@ -0,0 +1,12 @@ +gfs2-truncate-address-space-when-flipping-gfs2_dif_jdata-flag.patch +libfs-return-enospc-when-the-directory-offset-range-is-exhausted.patch +revert-libfs-add-simple_offset_empty.patch +revert-libfs-fix-infinite-directory-reads-for-offset-dir.patch +libfs-replace-simple_offset-end-of-directory-detection.patch +libfs-use-d_children-list-to-iterate-simple_offset-directories.patch +smb-client-handle-lack-of-ea-support-in-smb2_query_path_info.patch +net-sched-fix-ets-qdisc-oob-indexing.patch +revert-hid-multitouch-add-support-for-lenovo-y9000p-touchpad.patch +cachestat-fix-page-cache-statistics-permission-checking.patch +vfio-platform-check-the-bounds-of-read-write-syscalls.patch +scsi-storvsc-ratelimit-warning-logs-to-prevent-vm-denial-of-service.patch diff --git a/queue-6.13/smb-client-handle-lack-of-ea-support-in-smb2_query_path_info.patch b/queue-6.13/smb-client-handle-lack-of-ea-support-in-smb2_query_path_info.patch new file mode 100644 index 00000000000..d48e75f9800 --- /dev/null +++ b/queue-6.13/smb-client-handle-lack-of-ea-support-in-smb2_query_path_info.patch @@ -0,0 +1,198 @@ +From 3681c74d342db75b0d641ba60de27bf73e16e66b Mon Sep 17 00:00:00 2001 +From: Paulo Alcantara +Date: Tue, 21 Jan 2025 15:25:36 -0300 +Subject: smb: client: handle lack of EA support in smb2_query_path_info() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Paulo Alcantara + +commit 3681c74d342db75b0d641ba60de27bf73e16e66b upstream. + +If the server doesn't support both EAs and reparse point in a file, +the SMB2_QUERY_INFO request will fail with either +STATUS_NO_EAS_ON_FILE or STATUS_EAS_NOT_SUPPORT in the compound chain, +so ignore it as long as reparse point isn't +IO_REPARSE_TAG_LX_(CHR|BLK), which would require the EAs to know about +major/minor numbers. + +Reported-by: Pali Rohár +Signed-off-by: Paulo Alcantara (Red Hat) +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2inode.c | 92 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 69 insertions(+), 23 deletions(-) + +--- a/fs/smb/client/smb2inode.c ++++ b/fs/smb/client/smb2inode.c +@@ -176,27 +176,27 @@ static int smb2_compound_op(const unsign + struct kvec *out_iov, int *out_buftype, struct dentry *dentry) + { + +- struct reparse_data_buffer *rbuf; ++ struct smb2_query_info_rsp *qi_rsp = NULL; + struct smb2_compound_vars *vars = NULL; +- struct kvec *rsp_iov, *iov; +- struct smb_rqst *rqst; +- int rc; +- __le16 *utf16_path = NULL; + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; +- struct cifs_fid fid; ++ struct cifs_open_info_data *idata; + struct cifs_ses *ses = tcon->ses; ++ struct reparse_data_buffer *rbuf; + struct TCP_Server_Info *server; +- int num_rqst = 0, i; + int resp_buftype[MAX_COMPOUND]; +- struct smb2_query_info_rsp *qi_rsp = NULL; +- struct cifs_open_info_data *idata; ++ int retries = 0, cur_sleep = 1; ++ __u8 delete_pending[8] = {1,}; ++ struct kvec *rsp_iov, *iov; + struct inode *inode = NULL; +- int flags = 0; +- __u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0}; ++ __le16 *utf16_path = NULL; ++ struct smb_rqst *rqst; + unsigned int size[2]; +- void *data[2]; ++ struct cifs_fid fid; ++ int num_rqst = 0, i; + unsigned int len; +- int retries = 0, cur_sleep = 1; ++ int tmp_rc, rc; ++ int flags = 0; ++ void *data[2]; + + replay_again: + /* reinitialize for possible replay */ +@@ -637,7 +637,14 @@ finished: + tcon->need_reconnect = true; + } + ++ tmp_rc = rc; + for (i = 0; i < num_cmds; i++) { ++ char *buf = rsp_iov[i + i].iov_base; ++ ++ if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER) ++ rc = server->ops->map_error(buf, false); ++ else ++ rc = tmp_rc; + switch (cmds[i]) { + case SMB2_OP_QUERY_INFO: + idata = in_iov[i].iov_base; +@@ -803,6 +810,7 @@ finished: + } + } + SMB2_close_free(&rqst[num_rqst]); ++ rc = tmp_rc; + + num_cmds += 2; + if (out_iov && out_buftype) { +@@ -858,22 +866,52 @@ static int parse_create_response(struct + return rc; + } + ++/* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */ ++static bool ea_unsupported(int *cmds, int num_cmds, ++ struct kvec *out_iov, int *out_buftype) ++{ ++ int i; ++ ++ if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA) ++ return false; ++ ++ for (i = 1; i < num_cmds - 1; i++) { ++ struct smb2_hdr *hdr = out_iov[i].iov_base; ++ ++ if (out_buftype[i] == CIFS_NO_BUFFER || !hdr || ++ hdr->Status != STATUS_SUCCESS) ++ return false; ++ } ++ return true; ++} ++ ++static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) { ++ free_rsp_buf(buftype[i], iovs[i].iov_base); ++ memset(&iovs[i], 0, sizeof(*iovs)); ++ buftype[i] = CIFS_NO_BUFFER; ++ } ++} ++ + int smb2_query_path_info(const unsigned int xid, + struct cifs_tcon *tcon, + struct cifs_sb_info *cifs_sb, + const char *full_path, + struct cifs_open_info_data *data) + { ++ struct kvec in_iov[3], out_iov[5] = {}; ++ struct cached_fid *cfid = NULL; + struct cifs_open_parms oparms; +- __u32 create_options = 0; + struct cifsFileInfo *cfile; +- struct cached_fid *cfid = NULL; ++ __u32 create_options = 0; ++ int out_buftype[5] = {}; + struct smb2_hdr *hdr; +- struct kvec in_iov[3], out_iov[3] = {}; +- int out_buftype[3] = {}; ++ int num_cmds = 0; + int cmds[3]; + bool islink; +- int i, num_cmds = 0; + int rc, rc2; + + data->adjust_tz = false; +@@ -943,14 +981,14 @@ int smb2_query_path_info(const unsigned + if (rc || !data->reparse_point) + goto out; + +- if (!tcon->posix_extensions) +- cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; + /* + * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create + * response. + */ + if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK) + cmds[num_cmds++] = SMB2_OP_GET_REPARSE; ++ if (!tcon->posix_extensions) ++ cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; + + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, + FILE_READ_ATTRIBUTES | +@@ -958,9 +996,18 @@ int smb2_query_path_info(const unsigned + FILE_OPEN, create_options | + OPEN_REPARSE_POINT, ACL_NO_MODE); + cifs_get_readable_path(tcon, full_path, &cfile); ++ free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov)); + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, + &oparms, in_iov, cmds, num_cmds, +- cfile, NULL, NULL, NULL); ++ cfile, out_iov, out_buftype, NULL); ++ if (rc && ea_unsupported(cmds, num_cmds, ++ out_iov, out_buftype)) { ++ if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK && ++ data->reparse.tag != IO_REPARSE_TAG_LX_CHR) ++ rc = 0; ++ else ++ rc = -EOPNOTSUPP; ++ } + break; + case -EREMOTE: + break; +@@ -978,8 +1025,7 @@ int smb2_query_path_info(const unsigned + } + + out: +- for (i = 0; i < ARRAY_SIZE(out_buftype); i++) +- free_rsp_buf(out_buftype[i], out_iov[i].iov_base); ++ free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov)); + return rc; + } + diff --git a/queue-6.13/vfio-platform-check-the-bounds-of-read-write-syscalls.patch b/queue-6.13/vfio-platform-check-the-bounds-of-read-write-syscalls.patch new file mode 100644 index 00000000000..58f98fe9cd1 --- /dev/null +++ b/queue-6.13/vfio-platform-check-the-bounds-of-read-write-syscalls.patch @@ -0,0 +1,54 @@ +From ce9ff21ea89d191e477a02ad7eabf4f996b80a69 Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Wed, 22 Jan 2025 10:38:30 -0700 +Subject: vfio/platform: check the bounds of read/write syscalls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Williamson + +commit ce9ff21ea89d191e477a02ad7eabf4f996b80a69 upstream. + +count and offset are passed from user space and not checked, only +offset is capped to 40 bits, which can be used to read/write out of +bounds of the device. + +Fixes: 6e3f26456009 (“vfio/platform: read and write support for the device fd”) +Cc: stable@vger.kernel.org +Reported-by: Mostafa Saleh +Reviewed-by: Eric Auger +Reviewed-by: Mostafa Saleh +Tested-by: Mostafa Saleh +Signed-off-by: Alex Williamson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vfio/platform/vfio_platform_common.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/vfio/platform/vfio_platform_common.c ++++ b/drivers/vfio/platform/vfio_platform_common.c +@@ -388,6 +388,11 @@ static ssize_t vfio_platform_read_mmio(s + { + unsigned int done = 0; + ++ if (off >= reg->size) ++ return -EINVAL; ++ ++ count = min_t(size_t, count, reg->size - off); ++ + if (!reg->ioaddr) { + reg->ioaddr = + ioremap(reg->addr, reg->size); +@@ -467,6 +472,11 @@ static ssize_t vfio_platform_write_mmio( + { + unsigned int done = 0; + ++ if (off >= reg->size) ++ return -EINVAL; ++ ++ count = min_t(size_t, count, reg->size - off); ++ + if (!reg->ioaddr) { + reg->ioaddr = + ioremap(reg->addr, reg->size);