5.10.261-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 638/699 netfilter: ebtables: zero chainstack array
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit cbfe53599eebffd188938ab6774cc41794f6f9d5 ]
sashiko reports:
looking at ebtables table
translation, could a sparse cpu_possible_mask lead to an uninitialized pointer free?
If cpu_possible_mask is sparse (for example, CPU 0 and CPU 2 are possible, but CPU 1 is not), the allocation loop skips CPU 1. If vmalloc_node() fails at CPU 2, the cleanup loop will blindly decrement and call vfree() on newinfo->chainstack[1].
Not a real-world bug, such allocation isn't expected to fail in the first place.
--- net/bridge/netfilter/ebtables.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/bridge/netfilter/ebtables.c +1 -2
@@ -884,8 +884,7 @@ static int translate_table(struct net *n* if an error occurs */ newinfo->chainstack = -vmalloc_array (nr_cpu_ids, -sizeof (*(newinfo->chainstack))); +vcalloc (nr_cpu_ids,sizeof (*(newinfo->chainstack)));if (!newinfo->chainstack)return -ENOMEM ;for_each_possible_cpu (i) {
Greg Kroah-Hartman
maintainerPATCH 639/699 Bluetooth: L2CAP: Fix not tracking outstanding TX ident
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 6c3ea155e5ee3e56606233acde8309afda66d483 ]
This attempts to proper track outstanding request by using struct ida and allocating from it in l2cap_get_ident using ida_alloc_range which would reuse ids as they are free, then upon completion release the id using ida_free.
This fixes the qualification test case L2CAP/COS/CED/BI-29-C which attempts to check if the host stack is able to work after 256 attempts to connect which requires Ident field to use the full range of possible values in order to pass the test.
Stable-dep-of: 2641a9e0a1dd ("Bluetooth: L2CAP: cancel pending_rx_work before taking conn->lock")
--- include/net/bluetooth/l2cap.h | 3 -- net/bluetooth/l2cap_core.c | 53 ++++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 16 deletions(-)
include/net/bluetooth/l2cap.h +1 -2
@@ -690,8 +690,7 @@ struct l2cap_conn {struct sk_buff *rx_skb;__u32 rx_len; -__u8 tx_ident; -struct mutex ident_lock; +struct ida tx_ida;struct sk_buff_head pending_rx;struct work_struct pending_rx_work;
net/bluetooth/l2cap_core.c +39 -14
102 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 640/699 Bluetooth: L2CAP: Fix deadlock in l2cap_conn_del()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
[ Upstream commit 00fdebbbc557a2fc21321ff2eaa22fd70c078608 ]
l2cap_conn_del() calls cancel_delayed_work_sync() for both info_timer and id_addr_timer while holding conn->lock. However, the work functions l2cap_info_timeout() and l2cap_conn_update_id_addr() both acquire conn->lock, creating a potential AB-BA deadlock if the work is already executing when l2cap_conn_del() takes the lock.
Move the work cancellations before acquiring conn->lock and use disable_delayed_work_sync() to additionally prevent the works from being rearmed after cancellation, consistent with the pattern used in hci_conn_del().
Stable-dep-of: 2641a9e0a1dd ("Bluetooth: L2CAP: cancel pending_rx_work before taking conn->lock")
--- net/bluetooth/l2cap_core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
net/bluetooth/l2cap_core.c +3 -6
@@ -1898,6 +1898,9 @@ static void l2cap_conn_del(struct hci_coBT_DBG ("hcon %p conn %p, err %d" , hcon, conn, err); +cancel_delayed_work_sync (&conn->info_timer); +cancel_work_sync (&conn->id_addr_update_work); +kfree_skb (conn->rx_skb);skb_queue_purge (&conn->pending_rx);
@@ -1911,9 +1914,6 @@ static void l2cap_conn_del(struct hci_coida_destroy (&conn->tx_ida); -if (work_pending (&conn->id_addr_update_work)) -cancel_work_sync (&conn->id_addr_update_work); -l2cap_unregister_all_users (conn);/* Force the connection to be immediately dropped */
@@ -1938,9 +1938,6 @@ static void l2cap_conn_del(struct hci_cohci_chan_del (conn->hchan); -if (conn->info_state &L2CAP_INFO_FEAT_MASK_REQ_SENT ) -cancel_delayed_work_sync (&conn->info_timer); - hcon->l2cap_data =NULL ; conn->hchan =NULL ;l2cap_conn_put (conn);
Greg Kroah-Hartman
maintainerPATCH 641/699 Bluetooth: L2CAP: cancel pending_rx_work before taking conn->lock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 2641a9e0a1dd4af2e21995470a21d55dd35e5203 ]
l2cap_conn_del() takes conn->lock and then calls cancel_work_sync() for pending_rx_work. process_pending_rx() takes the same mutex, so teardown can deadlock against the worker it is flushing.
This issue was found by our static analysis tool and then manually reviewed against the current tree.
The grounded PoC kept the l2cap_conn_ready() -> queue_work(..., &conn->pending_rx_work) submit path, the l2cap_conn_del() -> cancel_work_sync(&conn->pending_rx_work) teardown path, and the process_pending_rx() -> mutex_lock(&conn->lock) worker edge. Lockdep reported:
WARNING: possible circular locking dependency detected
process_pending_rx+0x21/0x2a [vuln_msv] l2cap_conn_del.constprop.0+0x3f/0x4e [vuln_msv] *** DEADLOCK ***
Cancel pending_rx_work before taking conn->lock, matching the existing lock-before-drain ordering used for the two delayed works in the same teardown path. The pending_rx queue is still purged after the work has been cancelled and conn->lock has been acquired.
--- net/bluetooth/l2cap_core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
net/bluetooth/l2cap_core.c +2 -8
@@ -1901,17 +1901,11 @@ static void l2cap_conn_del(struct hci_cocancel_delayed_work_sync (&conn->info_timer);cancel_work_sync (&conn->id_addr_update_work); +cancel_work_sync (&conn->pending_rx_work); +kfree_skb (conn->rx_skb);skb_queue_purge (&conn->pending_rx); - -/* We can not call flush_work(&conn->pending_rx_work) here since we -* might block if we are running on a worker from the same workqueue -* pending_rx_work is waiting on. -*/ -if (work_pending (&conn->pending_rx_work)) -cancel_work_sync (&conn->pending_rx_work); -ida_destroy (&conn->tx_ida);l2cap_unregister_all_users (conn);
Greg Kroah-Hartman
maintainerPATCH 642/699 smb: client: Fix next buffer leak in receive_encrypted_standard()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit 1c6267a1d5cf4c73b656f8181b310cbbb3e4767b ]
receive_encrypted_standard() allocates next_buffer before checking whether the number of compound PDUs already reached MAX_COMPOUND. If the limit check fails, the function returns immediately and the newly allocated next_buffer is not assigned to server->smallbuf/server->bigbuf, making it leaked.
Move the MAX_COMPOUND check before allocating next_buffer.
--- fs/cifs/smb2ops.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
fs/cifs/smb2ops.c +6 -4
@@ -4961,6 +4961,12 @@ receive_encrypted_standard(struct TCP_Se one_more: shdr = (struct smb2_hdr *)buf; next_cmd =le32_to_cpu (shdr->NextCommand); + +if (*num_mids >=MAX_COMPOUND ) { +cifs_server_dbg (VFS ,"too many PDUs in compound\n" ); +return -1 ; + } +if (next_cmd) {if (WARN_ON_ONCE (next_cmd > pdu_length))return -1 ;
@@ -4984,10 +4990,6 @@ one_more: mid_entry->resp_buf_size = server->pdu_size; } -if (*num_mids >=MAX_COMPOUND ) { -cifs_server_dbg (VFS ,"too many PDUs in compound\n" ); -return -1 ; - } bufs[*num_mids] = buf; mids[(*num_mids)++] = mid_entry;
Greg Kroah-Hartman
maintainerPATCH 643/699 smb: client: mask server-provided mode to 07777 in modefromsid
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Manthey <[email protected]>
[ Upstream commit e3d9c7160d483fc8f9e225aafad8ecbbc43f3151 ]
When modefromsid is active, parse_dacl() applies the server-provided sub_auth[2] value from the NFS mode SID to cf_mode without masking to 07777. Apply the correct masking, same as in the read path.
--- fs/cifs/cifsacl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/cifs/cifsacl.c +1 -1
@@ -767,7 +767,7 @@ static void parse_dacl(struct cifs_acl **/ fattr->cf_mode &= ~07777 ; fattr->cf_mode |= -le32_to_cpu (ppace[i]->sid.sub_auth[2 ]); +le32_to_cpu (ppace[i]->sid.sub_auth[2 ]) &07777 ;break ; }else if (compare_sids (&(ppace[i]->sid), pownersid) ==0 ) access_flags_to_mode(ppace[i]->access_req,
Greg Kroah-Hartman
maintainerPATCH 644/699 smb: client: use unaligned reads in parse_posix_ctxt()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
[ Upstream commit b86467cd2691192ad4809a5a6e922fc24b8e9839 ]
The server controls create-context DataOffset, so the POSIX context data pointer may be misaligned on strict-alignment architectures. Use get_unaligned_le32() when reading nlink, reparse_tag, and mode.
--- fs/cifs/smb2pdu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/cifs/smb2pdu.c +3 -3
@@ -1973,9 +1973,9 @@ parse_posix_ctxt(struct create_context *memset (posix,0 ,sizeof (*posix)); - posix->nlink =le32_to_cpu (*(__le32 *)(beg +0 )); - posix->reparse_tag =le32_to_cpu (*(__le32 *)(beg +4 )); - posix->mode =le32_to_cpu (*(__le32 *)(beg +8 )); + posix->nlink =get_unaligned_le32 (beg); + posix->reparse_tag =get_unaligned_le32 (beg +4 ); + posix->mode =get_unaligned_le32 (beg +8 ); sid = beg +12 ; sid_len =posix_info_sid_size (sid, end);
Greg Kroah-Hartman
maintainerPATCH 645/699 smb: client: harden POSIX SID length parsing
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
[ Upstream commit 7ad2bcf2441430bb2e918fb3ef9a90d775a6e422 ]
posix_info_sid_size() reads sid[1] to obtain the subauthority count, but its existing boundary check still accepts buffers with only one remaining byte. Require two bytes before reading sid[1] so all client paths that reuse the helper reject truncated POSIX SIDs safely.
--- fs/cifs/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/cifs/smb2pdu.c +1 -1
@@ -4518,7 +4518,7 @@ int posix_info_sid_size(const void *beg,size_t subauth;int total; -if (beg +1 > end) +if (beg +2 > end)return -1 ; subauth = *(u8 *)(beg+1 );
Greg Kroah-Hartman
maintainerPATCH 646/699 writeback: fix race between cgroup_writeback_umount() and inode_switch_wbs()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
[ Upstream commit cba38ec4cbd3a7b8b942a8d52531a05be8a9ff0d ]
When a container exits, the following BUG_ON() is occasionally triggered:
==================================================================
VFS: Busy inodes after unmount of sdb (ext4)
------------[ cut here ]------------ kernel BUG at fs/super.c:695! CPU: 3 PID: 6 Comm: containerd-shim Tainted: G OE K 6.6 #1 pstate: 63400009 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--) pc : generic_shutdown_super+0xf0/0x100 lr : generic_shutdown_super+0xf0/0x100 Call trace: generic_shutdown_super+0xf0/0x100 kill_block_super+0x20/0x48 ext4_kill_sb+0x28/0x60 deactivate_locked_super+0x54/0x130 deactivate_super+0x84/0xa0 cleanup_mnt+0xa4/0x140 __cleanup_mnt+0x18/0x28 task_work_run+0x78/0xe0 do_notify_resume+0x204/0x240 ==================================================================
The root cause is a race between cgroup_writeback_umount() and inode_switch_wbs()/cleanup_offline_cgwb(). There is a window between inode_prepare_wbs_switch() returning true and the subsequent wb_queue_isw() call. Following is the process that triggers the issue:
CPU A (umount) | CPU B (writeback)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inode_switch_wbs/cleanup_offline_cgwb
atomic_inc(&isw_nr_in_flight)
inode_prepare_wbs_switch
-> passes SB_ACTIVE check
__iget(inode)
generic_shutdown_super
sb->s_flags &= ~SB_ACTIVE
cgroup_writeback_umount(sb)
smp_mb()
atomic_read(&isw_nr_in_flight)
rcu_barrier()
-> no pending RCU callbacks
flush_workqueue(isw_wq)
-> nothing queued, returns
evict_inodes(sb)
-> Inode skipped as isw still holds a ref.
sop->put_super(sb)
/* destroys percpu counters */
-> VFS: Busy inodes after unmount!
wb_queue_isw()
queue_work(isw_wq, ...)
/* later in work function */
inode_switch_wbs_work_fn
process_inode_switch_wbs
iput() -> evict
percpu_counter_dec() // UAF!Fix this by extending the RCU read-side critical section in inode_switch_wbs() and cleanup_offline_cgwb() to cover from inode_prepare_wbs_switch() through wb_queue_isw(). Since there is no sleep in this window, rcu_read_lock() can be used. Then add a synchronize_rcu() in cgroup_writeback_umount() before the existing rcu_barrier(), so that all in-flight switchers that have passed the SB_ACTIVE check have completed queue_work() before flush_workqueue() is called.
The existing rcu_barrier() is intentionally retained so this fix can be backported unchanged to stable kernels (5.10.y, 6.6.y, ...) that still queue switches via queue_rcu_work(). It is a no-op on current mainline (since commit e1b849cfa6b6 ("writeback: Avoid contention on wb->list_lock when switching inodes")) and is removed in a follow-up patch.
--- fs/fs-writeback.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
fs/fs-writeback.c +18 -2
@@ -507,12 +507,18 @@ static void inode_switch_wbs(struct inodatomic_inc (&isw_nr_in_flight); -/* find and pin the new wb */ +/* +* Paired with synchronize_rcu() in cgroup_writeback_umount(): +* holding rcu_read_lock across the SB_ACTIVE check, the inode +* grab and call_rcu() ensures synchronize_rcu() cannot return +* until the switch is queued, so the subsequent rcu_barrier() +* and flush_workqueue() will wait for the switch. +*/ rcu_read_lock (); +/* find and pin the new wb */ memcg_css =css_from_id (new_wb_id, &memory_cgrp_subsys);if (memcg_css && !css_tryget (memcg_css)) memcg_css =NULL ; -rcu_read_unlock ();if (!memcg_css) goto out_free;
@@ -542,9 +548,11 @@ static void inode_switch_wbs(struct inod* Let's continue after I_WB_SWITCH is guaranteed to be visible. */ call_rcu (&isw->rcu_head, inode_switch_wbs_rcu_fn); +rcu_read_unlock ();return ; out_free: +rcu_read_unlock ();atomic_dec (&isw_nr_in_flight);if (isw->new_wb)wb_put (isw->new_wb);
@@ -1011,6 +1019,14 @@ void cgroup_writeback_umount(void) {if (atomic_read (&isw_nr_in_flight)) {/* +* Paired with rcu_read_lock() in inode_switch_wbs(). +* synchronize_rcu() waits for any in-flight switcher that +* already passed the SB_ACTIVE check to finish calling +* call_rcu(), so the rcu_barrier() and flush_workqueue() +* below will then drain it. +*/ +synchronize_rcu (); +/* * Use rcu_barrier() to wait for all pending callbacks to * ensure that all in-flight wb switches are in the workqueue. */
Greg Kroah-Hartman
maintainerPATCH 647/699 X.509: Fix validation of ASN.1 certificate header
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lukas Wunner <[email protected]>
[ Upstream commit 3b626ba431c4501512ad07549310685e07fe4706 ]
x509_load_certificate_list() seeks to enforce that a certificate starts with 0x30 0x82 (ASN.1 SEQUENCE tag followed by a length of more than 256 and less than 65535 bytes).
But it only enforces that *either* of those two byte values are present, instead of checking for the *conjunction* of the two values. Fix it.
--- certs/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
certs/common.c +1 -1
@@ -20,7 +20,7 @@ int load_certificate_list(const u8 cert_*/ if (end - p <4 ) goto dodgy_cert; -if (p[0 ] !=0x30 && +if (p[0 ] !=0x30 || p[1 ] !=0x82 ) goto dodgy_cert; plen = (p[2 ] <<8 ) | p[3 ];
Greg Kroah-Hartman
maintainerPATCH 648/699 proc: use generic setattr() for /proc/$PID/net
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
[ Upstream commit 18e66ae67673f2c8df6f02428798b1355691f2a9 ]
All other files in /proc/$PID/ use proc_setattr().
Not using it allows the usage of chmod() on /proc/$PID/net, even on other processes owned by the same user.
The same would probably also be true for other attributes to be changed.
As this technically represents an ABI change it is not marked for stable so any unlikely regressions are caught during a full release cycle.
Message-Id: <[email protected]>
Stable-dep-of: 6255da28d4bb ("proc: protect ptrace_may_access() with exec_update_lock (FD links)")
--- fs/proc/proc_net.c | 1 + 1 file changed, 1 insertion(+)
fs/proc/proc_net.c +1 -0
@@ -310,6 +310,7 @@ static int proc_tgid_net_getattr(const sconst struct inode_operations proc_net_inode_operations = { .lookup = proc_tgid_net_lookup, .getattr = proc_tgid_net_getattr, + .setattr = proc_setattr, };static int proc_tgid_net_readdir (struct file *file,struct dir_context *ctx)
Greg Kroah-Hartman
maintainerPATCH 649/699 proc: rename proc_setattr to proc_nochmod_setattr
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
[ Upstream commit 690005b0b1e6b567c88b7790e6d90d4d6c9e09cc ]
What is currently proc_setattr is a special version added after the more general procfs ->seattr in commit 6d76fa58b050 ("Don't allow chmod() on the /proc/<pid>/ files"). Give it a name that reflects that to free the proc_setattr name and better describe what is doing.
Stable-dep-of: 6255da28d4bb ("proc: protect ptrace_may_access() with exec_update_lock (FD links)")
--- fs/proc/base.c | 22 +++++++++++----------- fs/proc/fd.c | 4 ++-- fs/proc/internal.h | 2 +- fs/proc/namespaces.c | 4 ++-- fs/proc/proc_net.c | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-)
fs/proc/base.c +11 -11
@@ -720,7 +720,7 @@ static int proc_fd_access_allowed(structreturn allowed; } -int proc_setattr (struct dentry *dentry,struct iattr *attr) +int proc_nochmod_setattr (struct dentry *dentry,struct iattr *attr) {int error;struct inode *inode =d_inode (dentry);
@@ -792,7 +792,7 @@ static int proc_pid_permission(struct instatic const struct inode_operations proc_def_inode_operations = { - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };static int proc_single_show (struct seq_file *m,void *v)
@@ -1863,7 +1863,7 @@ out:const struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .get_link = proc_pid_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };
@@ -2311,7 +2311,7 @@ proc_map_files_get_link(struct dentry *dstatic const struct inode_operations proc_map_files_link_inode_operations = { .readlink = proc_pid_readlink, .get_link = proc_map_files_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *
@@ -2390,7 +2390,7 @@ out:static const struct inode_operations proc_map_files_inode_operations = { .lookup = proc_map_files_lookup, .permission = proc_fd_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static int
@@ -2882,7 +2882,7 @@ static struct dentry *proc_##LSM##_attr_ static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ .lookup = proc_##LSM##_attr_dir_lookup, \ .getattr = pid_getattr, \ - .setattr = proc_setattr, \ + .setattr = proc_nochmod_setattr, \ }#ifdef CONFIG_SECURITY_SMACK
@@ -2941,7 +2941,7 @@ static struct dentry *proc_attr_dir_lookstatic const struct inode_operations proc_attr_dir_inode_operations = { .lookup = proc_attr_dir_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };#endif
@@ -3395,7 +3395,7 @@ static struct dentry *proc_tgid_base_loostatic const struct inode_operations proc_tgid_base_inode_operations = { .lookup = proc_tgid_base_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_pid_permission, };
@@ -3594,7 +3594,7 @@ static int proc_tid_comm_permission(stru }static const struct inode_operations proc_tid_comm_inode_operations = { - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_tid_comm_permission, };
@@ -3718,7 +3718,7 @@ static const struct file_operations procstatic const struct inode_operations proc_tid_base_inode_operations = { .lookup = proc_tid_base_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_task_instantiate(struct dentry *dentry,
@@ -3913,7 +3913,7 @@ static int proc_task_getattr(const strucstatic const struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, .getattr = proc_task_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_pid_permission, };
fs/proc/fd.c +2 -2
@@ -297,7 +297,7 @@ int proc_fd_permission(struct inode *inoconst struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, .permission = proc_fd_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,
@@ -335,7 +335,7 @@ static int proc_readfdinfo(struct file *const struct inode_operations proc_fdinfo_inode_operations = { .lookup = proc_lookupfdinfo, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };const struct file_operations proc_fdinfo_operations = {
fs/proc/internal.h +1 -1
@@ -177,7 +177,7 @@ extern int proc_pid_statm(struct seq_fil*/ extern const struct dentry_operations pid_dentry_operations;extern int pid_getattr (const struct path *,struct kstat *,u32 ,unsigned int ); -extern int proc_setattr (struct dentry *,struct iattr *); +int proc_nochmod_setattr (struct dentry *dentry,struct iattr *attr);extern void proc_pid_evict_inode (struct proc_inode *);extern struct inode *proc_pid_make_inode (struct super_block *,struct task_struct *,umode_t );extern void pid_update_inode (struct task_struct *,struct inode *);
fs/proc/namespaces.c +2 -2
@@ -92,7 +92,7 @@ static int proc_ns_readlink(struct dentrstatic const struct inode_operations proc_ns_link_inode_operations = { .readlink = proc_ns_readlink, .get_link = proc_ns_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_ns_instantiate(struct dentry *dentry,
@@ -179,5 +179,5 @@ out_no_task:const struct inode_operations proc_ns_dir_inode_operations = { .lookup = proc_ns_dir_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };
fs/proc/proc_net.c +1 -1
@@ -310,7 +310,7 @@ static int proc_tgid_net_getattr(const sconst struct inode_operations proc_net_inode_operations = { .lookup = proc_tgid_net_lookup, .getattr = proc_tgid_net_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };static int proc_tgid_net_readdir (struct file *file,struct dir_context *ctx)
Greg Kroah-Hartman
maintainerPATCH 650/699 proc: protect ptrace_may_access() with exec_update_lock (FD links)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit 6255da28d4bb5349fe18e84cb043ccd394eba75d ]
proc_pid_get_link() and proc_pid_readlink() currently look up the task from the pid once, then do the ptrace access check on that task, then look up the task from the pid a second time to do the actual access. That's racy in several ways.
To fix it, pass the task to the ->proc_get_link() handler, and instead of proc_fd_access_allowed(), introduce a new helper call_proc_get_link() that looks up and locks the task, does the access check, and calls ->proc_get_link().
--- fs/proc/base.c | 119 ++++++++++++++++++++--------------------------------- fs/proc/fd.c | 25 ++++------- fs/proc/internal.h | 2 3 files changed, 58 insertions(+), 88 deletions(-)
fs/proc/base.c +47 -72
@@ -217,33 +217,24 @@ static int get_task_root(struct task_strreturn result; } -static int proc_cwd_link (struct dentry *dentry,struct path *path) +static int proc_cwd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry));int result = -ENOENT ; -if (task) { -task_lock (task); -if (task->fs) { -get_fs_pwd (task->fs, path); - result =0 ; - } -task_unlock (task); -put_task_struct (task); +task_lock (task); +if (task->fs) { +get_fs_pwd (task->fs, path); + result =0 ; } +task_unlock (task);return result; } -static int proc_root_link (struct dentry *dentry,struct path *path) +static int proc_root_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry)); -int result = -ENOENT ; - -if (task) { - result =get_task_root (task, path); -put_task_struct (task); - } -return result; +return get_task_root (task, path); }/*
@@ -703,23 +694,6 @@ static int proc_pid_syscall(struct seq_f/* Here the fs part begins */ /************************************************************************/ -/* permission checks */ -static int proc_fd_access_allowed (struct inode *inode) -{ -struct task_struct *task; -int allowed =0 ; -/* Allow access to a task's file descriptors if it is us or we -* may use ptrace attach to the process and find out that -* information. -*/ - task =get_proc_task (inode); -if (task) { - allowed =ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS ); -put_task_struct (task); - } -return allowed; -} -int proc_nochmod_setattr (struct dentry *dentry,struct iattr *attr) {int error;
@@ -1774,16 +1748,12 @@ static const struct file_operations proc .release = single_release, }; -static int proc_exe_link (struct dentry *dentry,struct path *exe_path) +static int proc_exe_link (struct dentry *dentry,struct path *exe_path, +struct task_struct *task) { -struct task_struct *task;struct file *exe_file; - task =get_proc_task (d_inode (dentry)); -if (!task) -return -ENOENT ; exe_file =get_task_exe_file (task); -put_task_struct (task);if (exe_file) { *exe_path = exe_file->f_path;path_get (&exe_file->f_path);
@@ -1793,26 +1763,42 @@ static int proc_exe_link(struct dentry *return -ENOENT ; } +static int call_proc_get_link (struct dentry *dentry,struct inode *inode,struct path *path_out) +{ +struct task_struct *task; +int ret; + + task =get_proc_task (inode); +if (!task) +return -ENOENT ; + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { + ret = -EACCES ; + goto out; + } + ret =PROC_I (inode)->op.proc_get_link (dentry, path_out, task); + +out: +up_read (&task->signal->exec_update_lock); +out_put_task: +put_task_struct (task); +return ret; +} +static const char *proc_pid_get_link (struct dentry *dentry,struct inode *inode,struct delayed_call *done) {struct path path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD ); - -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =nd_jump_link (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) + error =nd_jump_link (&path);return ERR_PTR (error); }
@@ -1846,17 +1832,11 @@ static int proc_pid_readlink(struct dentstruct inode *inode =d_inode (dentry);struct path path; -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =do_proc_readlink (&path, buffer, buflen); -path_put (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) { + error =do_proc_readlink (&path, buffer, buflen); +path_put (&path); + }return error; }
@@ -2242,21 +2222,16 @@ static const struct dentry_operations ti .d_delete = pid_delete_dentry, }; -static int map_files_get_link (struct dentry *dentry,struct path *path) +static int map_files_get_link (struct dentry *dentry,struct path *path, +struct task_struct *task) {unsigned long vm_start, vm_end;struct vm_area_struct *vma; -struct task_struct *task;struct mm_struct *mm;int rc; rc = -ENOENT ; - task =get_proc_task (d_inode (dentry)); -if (!task) - goto out; - mm =get_task_mm (task); -put_task_struct (task);if (!mm) goto out;
fs/proc/fd.c +10 -15
@@ -140,24 +140,19 @@ static const struct dentry_operations ti .d_delete = pid_delete_dentry, }; -static int proc_fd_link (struct dentry *dentry,struct path *path) +static int proc_fd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task;int ret = -ENOENT ; +unsigned int fd =proc_fd (d_inode (dentry)); +struct file *fd_file; - task =get_proc_task (d_inode (dentry)); -if (task) { -unsigned int fd =proc_fd (d_inode (dentry)); -struct file *fd_file; - - fd_file =fget_task (task, fd); -if (fd_file) { - *path = fd_file->f_path; -path_get (&fd_file->f_path); - ret =0 ; -fput (fd_file); - } -put_task_struct (task); + fd_file =fget_task (task, fd); +if (fd_file) { + *path = fd_file->f_path; +path_get (&fd_file->f_path); + ret =0 ; +fput (fd_file); }return ret;
fs/proc/internal.h +1 -1
@@ -97,7 +97,7 @@ extern struct kmem_cache *proc_dir_entryvoid pde_free (struct proc_dir_entry *pde);union proc_op { -int (*proc_get_link)(struct dentry *,struct path *); +int (*proc_get_link)(struct dentry *,struct path *,struct task_struct *);int (*proc_show)(struct seq_file *m,struct pid_namespace *ns,struct pid *pid,struct task_struct *task);
Greg Kroah-Hartman
maintainerPATCH 651/699 HID: add haptics page defines
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Angela Czubak <[email protected]>
[ Upstream commit 5e0ae59159e3a07391a35865bb79ff335473fa79 ]
Introduce haptic usages as defined in HID Usage Tables specification. Add HID units for newton and gram.
Stable-dep-of: 8813b0612275 ("HID: multitouch: fix out-of-bounds bit access on mt_io_flags")
--- include/linux/hid.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
include/linux/hid.h +29 -0
@@ -152,6 +152,7 @@ struct hid_item {#define HID_UP_TELEPHONY 0x000b0000#define HID_UP_CONSUMER 0x000c0000#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_HAPTIC 0x000e0000#define HID_UP_PID 0x000f0000#define HID_UP_HPVENDOR 0xff7f0000#define HID_UP_HPVENDOR2 0xff010000
@@ -299,6 +300,28 @@ struct hid_item {#define HID_DG_TOOLSERIALNUMBER 0x000d005b#define HID_DG_LATENCYMODE 0x000d0060 +#define HID_HP_SIMPLECONTROLLER 0x000e0001 +#define HID_HP_WAVEFORMLIST 0x000e0010 +#define HID_HP_DURATIONLIST 0x000e0011 +#define HID_HP_AUTOTRIGGER 0x000e0020 +#define HID_HP_MANUALTRIGGER 0x000e0021 +#define HID_HP_AUTOTRIGGERASSOCIATEDCONTROL 0x000e0022 +#define HID_HP_INTENSITY 0x000e0023 +#define HID_HP_REPEATCOUNT 0x000e0024 +#define HID_HP_RETRIGGERPERIOD 0x000e0025 +#define HID_HP_WAVEFORMVENDORPAGE 0x000e0026 +#define HID_HP_WAVEFORMVENDORID 0x000e0027 +#define HID_HP_WAVEFORMCUTOFFTIME 0x000e0028 +#define HID_HP_WAVEFORMNONE 0x000e1001 +#define HID_HP_WAVEFORMSTOP 0x000e1002 +#define HID_HP_WAVEFORMCLICK 0x000e1003 +#define HID_HP_WAVEFORMBUZZCONTINUOUS 0x000e1004 +#define HID_HP_WAVEFORMRUMBLECONTINUOUS 0x000e1005 +#define HID_HP_WAVEFORMPRESS 0x000e1006 +#define HID_HP_WAVEFORMRELEASE 0x000e1007 +#define HID_HP_VENDORWAVEFORMMIN 0x000e2001 +#define HID_HP_VENDORWAVEFORMMAX 0x000e2fff +#define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076/* * HID report types --- Ouch! HID spec says 1 2 3!
@@ -385,6 +408,12 @@ struct hid_item {#define HID_BOOT_PROTOCOL 0/* +* HID units +*/ +#define HID_UNIT_GRAM 0x0101 +#define HID_UNIT_NEWTON 0xe111 + +/* * This is the global environment of the parser. This information is * persistent for main-items. The global environment can be saved and * restored with PUSH/POP statements.
Greg Kroah-Hartman
maintainerPATCH 652/699 HID: multitouch: fix out-of-bounds bit access on mt_io_flags
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Trung Nguyen <[email protected]>
[ Upstream commit 8813b0612275cc61fe9e6603d0ee019247ade6be ]
mt_io_flags is a single unsigned long, but mt_process_slot(), mt_release_pending_palms() and mt_release_contacts() use it as a per-slot bitmap indexed by the slot number. That slot number is only bounded by td->maxcontacts, which is taken from the device's ContactCountMaximum feature report and can be up to 255, not by BITS_PER_LONG.
As a result, a multitouch device that advertises a large contact count makes set_bit()/clear_bit() operate past the mt_io_flags word and corrupt the adjacent members of struct mt_device. The sticky-fingers release timer is the easiest way to reach this. mt_release_contacts() runs
for (i = 0; i < mt->num_slots; i++) clear_bit(i, &td->mt_io_flags);
with num_slots == maxcontacts. For maxcontacts around 250 the loop clears the bits that overlap td->applications.next, zeroing that list head, and the list_for_each_entry() that immediately follows then dereferences NULL. The kernel panics from timer (softirq) context. On a KASAN build this shows up as a general protection fault in mt_release_contacts() with a null-ptr-deref at offset 0x58, which is offsetof(struct mt_application, num_received).
The state is reachable from an untrusted USB or Bluetooth HID multitouch device; no local privileges are required.
Store the per-slot active state in a separately allocated bitmap sized for maxcontacts, the same pattern already used for pending_palm_slots, and keep only MT_IO_FLAGS_RUNNING in mt_io_flags. The two "mt_io_flags & MT_IO_SLOTS_MASK" arming checks become bitmap_empty(td->active_slots, td->maxcontacts).
Move MT_IO_FLAGS_RUNNING back to bit 0. It was bumped to bit 32 by the same commit to leave the low byte for the slot bits; with the slot bits gone it fits in bit 0 again, which also keeps it within the unsigned long on 32-bit.
--- drivers/hid/hid-multitouch.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
drivers/hid/hid-multitouch.c +20 -12
@@ -31,6 +31,7 @@* [1] https://gitlab.freedesktop.org/libevdev/hid-tools */ +#include <linux/bitmap.h> #include <linux/device.h> #include <linux/hid.h> #include <linux/module.h>
@@ -81,8 +82,7 @@ enum latency_mode { HID_LATENCY_HIGH = 1, }; -#define MT_IO_SLOTS_MASK GENMASK(7, 0)/* reserve first 8 bits for slot tracking */ -#define MT_IO_FLAGS_RUNNING 32 +#define MT_IO_FLAGS_RUNNING 0static const bool mtrue = true;/* default for true */ static const bool mfalse;/* default for false */
@@ -158,10 +158,9 @@ struct mt_device {struct mt_class mtclass;/* our mt device class */ struct timer_list release_timer;/* to release sticky fingers */ struct hid_device *hdev;/* hid_device we're attached to */ -unsigned long mt_io_flags;/* mt flags (MT_IO_FLAGS_RUNNING) -* first 8 bits are reserved for keeping the slot -* states, this is fine because we only support up -* to 250 slots (MT_MAX_MAXCONTACT) +unsigned long mt_io_flags;/* mt flags (MT_IO_FLAGS_RUNNING) */ +unsigned long *active_slots;/* bitmap of slots with an active +* contact, sized for maxcontacts */ __u8 inputmode_value;/* InputMode HID feature value */ __u8 maxcontacts;
@@ -915,7 +914,7 @@ static void mt_release_pending_palms(strfor_each_set_bit (slotnum, app->pending_palm_slots, td->maxcontacts) {clear_bit (slotnum, app->pending_palm_slots); -clear_bit (slotnum, &td->mt_io_flags); +clear_bit (slotnum, td->active_slots);input_mt_slot (input, slotnum);input_mt_report_slot_inactive (input);
@@ -1100,9 +1099,9 @@ static int mt_process_slot(struct mt_devinput_event (input,EV_ABS ,ABS_MT_TOUCH_MAJOR , major);input_event (input,EV_ABS ,ABS_MT_TOUCH_MINOR , minor); -set_bit (slotnum, &td->mt_io_flags); +set_bit (slotnum, td->active_slots); }else { -clear_bit (slotnum, &td->mt_io_flags); +clear_bit (slotnum, td->active_slots); }return 0 ;
@@ -1237,7 +1236,7 @@ static void mt_touch_report(struct hid_d* defect. */ if (app->quirks &MT_QUIRK_STICKY_FINGERS ) { -if (td->mt_io_flags &MT_IO_SLOTS_MASK ) +if (!bitmap_empty (td->active_slots, td->maxcontacts))mod_timer (&td->release_timer, jiffies +msecs_to_jiffies (100 ));else
@@ -1277,6 +1276,15 @@ static int mt_touch_input_configured(strif (td->is_buttonpad)__set_bit (INPUT_PROP_BUTTONPAD , input->propbit); +if (!td->active_slots) { + td->active_slots =devm_kcalloc (&td->hdev->dev, +BITS_TO_LONGS (td->maxcontacts), +sizeof (long ), +GFP_KERNEL ); +if (!td->active_slots) +return -ENOMEM ; + } + app->pending_palm_slots = devm_kcalloc(&hi->input->dev, BITS_TO_LONGS(td->maxcontacts), sizeof(long),
@@ -1655,7 +1663,7 @@ static void mt_release_contacts(struct hfor (i =0 ; i < mt->num_slots; i++) {input_mt_slot (input_dev, i);input_mt_report_slot_inactive (input_dev); -clear_bit (i, &td->mt_io_flags); +clear_bit (i, td->active_slots); }input_mt_sync_frame (input_dev);input_sync (input_dev);
@@ -1678,7 +1686,7 @@ static void mt_expired_timeout(struct ti*/ if (test_and_set_bit_lock (MT_IO_FLAGS_RUNNING , &td->mt_io_flags))return ; -if (td->mt_io_flags &MT_IO_SLOTS_MASK ) +if (!bitmap_empty (td->active_slots, td->maxcontacts))mt_release_contacts (hdev);clear_bit_unlock (MT_IO_FLAGS_RUNNING , &td->mt_io_flags); }
Greg Kroah-Hartman
maintainerPATCH 653/699 cpufreq: intel_pstate: Sync policy->cur during CPU offline
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fushuai Wang <[email protected]>
[ Upstream commit bcbdaa1086c25a8a5d48e04e1b82fdfb0682b681 ]
When a CPU goes offline with HWP disabled, intel_pstate_set_min_pstate() sets the MSR_IA32_PERF_CTL to minimum frequency to prevent SMT siblings from being restricted. However, the policy->cur value was not updated, leaving it at the previous value.
When the CPU comes back online, governor->limits() checks if target_freq equals policy->cur and skips the frequency adjustment if they match. Since policy->cur still holds the previous value, the governor does not call cpufreq_driver->target to update MSR_IA32_PERF_CTL.
Fix this by synchronizing policy->cur with the hardware state when setting minimum pstate during CPU offline.
--- drivers/cpufreq/intel_pstate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/cpufreq/intel_pstate.c +4 -2
@@ -2355,10 +2355,12 @@ static int intel_pstate_cpu_offline(stru* from getting to lower performance levels, so force the minimum * performance on CPU offline to prevent that from happening. */ -if (hwp_active) +if (hwp_active) {intel_pstate_hwp_offline (cpu); -else + }else {intel_pstate_set_min_pstate (cpu); + policy->cur = cpu->pstate.min_pstate * cpu->pstate.scaling; + }intel_pstate_exit_perf_limits (policy);
Greg Kroah-Hartman
maintainerPATCH 654/699 proc: protect ptrace_may_access() with exec_update_lock (part 1)
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
[ Upstream commit 6650527444dadc63d84aa939d14ecba4fadb2f69 ]
Fix the easy cases where procfs currently calls ptrace_may_access() without exec_update_lock protection, where the fix is to simply add the extra lock or use mm_access():
- do_task_stat(): grab exec_update_lock
- proc_pid_wchan(): grab exec_update_lock
- proc_map_files_lookup(): use mm_access() instead of get_task_mm()
- proc_map_files_readdir(): use mm_access() instead of get_task_mm()
- proc_ns_get_link(): grab exec_update_lock
- proc_ns_readlink(): grab exec_update_lock
--- fs/proc/array.c | 6 ++++++ fs/proc/base.c | 41 ++++++++++++++++++++++++----------------- fs/proc/namespaces.c | 12 ++++++++++++ 3 files changed, 42 insertions(+), 17 deletions(-)
fs/proc/array.c +6 -0
@@ -449,6 +449,11 @@ static int do_task_stat(struct seq_fileunsigned long flags;struct signal_struct *sig = task->signal;unsigned int seq =1 ; +int ret; + + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) +return ret; state = *get_task_state (task); vsize = eip = esp =0 ;
@@ -626,6 +631,7 @@ static int do_task_stat(struct seq_fileseq_puts (m," 0" );seq_putc (m,'\n' ); +up_read (&task->signal->exec_update_lock);if (mm)mmput (mm);return 0 ;
fs/proc/base.c +24 -17
103 lines not on this page · raw message
fs/proc/namespaces.c +12 -0
@@ -55,6 +55,10 @@ static const char *proc_ns_get_link(struif (!task)return ERR_PTR (-EACCES ); + error =down_read_killable (&task->signal->exec_update_lock); +if (error) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -64,6 +68,8 @@ static const char *proc_ns_get_link(stru error =nd_jump_link (&ns_path); out: +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return ERR_PTR (error); }
@@ -80,11 +86,17 @@ static int proc_ns_readlink(struct dentrif (!task)return res; + res =down_read_killable (&task->signal->exec_update_lock); +if (res) + goto out_put_task; +if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 ) res =readlink_copy (buffer, buflen, name); } +up_read (&task->signal->exec_update_lock); +out_put_task:put_task_struct (task);return res; }
Greg Kroah-Hartman
maintainerPATCH 655/699 HID: appleir: fix UAF on pending key_up_timer in remove()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manish Khadka <[email protected]>
[ Upstream commit 75fe87e19d8aff81eb2c64d15d244ab8da4de945 ]
appleir_remove() runs hid_hw_stop() before timer_delete_sync(). hid_hw_stop() synchronously unregisters the HID input device via hid_disconnect() -> hidinput_disconnect() -> input_unregister_device(), which drops the last reference and frees the underlying input_dev when no userspace handle holds it open.
key_up_tick() reads appleir->input_dev and calls input_report_key() / input_sync() on it. The timer is armed from appleir_raw_event() with a HZ/8 (~125 ms) timeout on every keydown and key-repeat report. If a key was pressed shortly before the device is disconnected, the timer can fire after hid_hw_stop() has freed input_dev but before the teardown drains it.
A simple reorder is not sufficient. Putting the timer drain first still leaves a window where a USB URB completion (raw_event) running during hid_hw_stop() can call mod_timer() and re-arm the timer, which then fires after hidinput_disconnect() has freed input_dev. The same URB-completion window also lets raw_event() reach key_up(), key_down() and battery_flat() directly, all of which dereference appleir->input_dev.
Introduce a 'removing' flag on struct appleir, gated by the existing spinlock. appleir_remove() sets the flag under the lock and then shuts down the timer with timer_shutdown_sync(), which both drains any in-flight callback and permanently disables further mod_timer() calls. appleir_raw_event() and key_up_tick() bail out early if the flag is set, so no path can arm or run the timer, or dereference appleir->input_dev, after remove() has started tearing down.
The keyrepeat and flatbattery branches of appleir_raw_event() previously called into the input layer without holding the spinlock; take it now so the flag check is well-defined. This incidentally closes a pre-existing read-side race on appleir->current_key in the keyrepeat branch.
This bug is structurally a sibling of commit 4db2af929279 ("HID:
appletb-kbd: fix UAF in inactivity-timer cleanup path") and has been present since the driver was introduced.
--- drivers/hid/hid-appleir.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-)
drivers/hid/hid-appleir.c +35 -10
@@ -109,9 +109,10 @@ struct appleir {struct hid_device *hid;unsigned short keymap[ARRAY_SIZE (appleir_key_table)];struct timer_list key_up_timer;/* timer for key up */ -spinlock_t lock;/* protects .current_key */ +spinlock_t lock;/* protects .current_key, .removing */ int current_key;/* the currently pressed key */ int prev_key_idx;/* key index in a 2 packets message */ +bool removing;/* set during teardown; gates input_dev access */ };static int get_key (int data)
@@ -172,7 +173,7 @@ static void key_up_tick(struct timer_lisunsigned long flags;spin_lock_irqsave (&appleir->lock, flags); -if (appleir->current_key) { +if (!appleir->removing && appleir->current_key) {key_up (hid, appleir, appleir->current_key); appleir->current_key =0 ; }
@@ -195,6 +196,10 @@ static int appleir_raw_event(struct hid_int index;spin_lock_irqsave (&appleir->lock, flags); +if (appleir->removing) { +spin_unlock_irqrestore (&appleir->lock, flags); + goto out; + }/* * If we already have a key down, take it up before marking * this one down
@@ -229,17 +234,25 @@ static int appleir_raw_event(struct hid_ appleir->prev_key_idx =0 ;if (!memcmp (data, keyrepeat,sizeof (keyrepeat))) { -key_down (hid, appleir, appleir->current_key); -/* -* Remote doesn't do key up, either pull them up, in the test -* above, or here set a timer which pulls them up after 1/8 s -*/ -mod_timer (&appleir->key_up_timer, jiffies +HZ /8 ); +spin_lock_irqsave (&appleir->lock, flags); +if (!appleir->removing) { +key_down (hid, appleir, appleir->current_key); +/* +* Remote doesn't do key up, either pull them up, in +* the test above, or here set a timer which pulls them +* up after 1/8 s +*/ +mod_timer (&appleir->key_up_timer, jiffies +HZ /8 ); + } +spin_unlock_irqrestore (&appleir->lock, flags); goto out; }if (!memcmp (data, flatbattery,sizeof (flatbattery))) { -battery_flat (appleir); +spin_lock_irqsave (&appleir->lock, flags); +if (!appleir->removing) +battery_flat (appleir); +spin_unlock_irqrestore (&appleir->lock, flags);/* Fall through */ }
@@ -318,8 +331,20 @@ fail:static void appleir_remove (struct hid_device *hid) {struct appleir *appleir =hid_get_drvdata (hid); +unsigned long flags; + +/* +* Mark the driver as tearing down so that any concurrent raw_event +* (e.g. from a USB URB completion that hid_hw_stop() has not yet +* killed) and the key_up_timer softirq stop touching input_dev +* before hid_hw_stop() frees it via hidinput_disconnect(). +*/ +spin_lock_irqsave (&appleir->lock, flags); + appleir->removing = true; +spin_unlock_irqrestore (&appleir->lock, flags); + +timer_delete_sync (&appleir->key_up_timer);hid_hw_stop (hid); -del_timer_sync (&appleir->key_up_timer); }static const struct hid_device_id appleir_devices[] = {
Greg Kroah-Hartman
maintainerPATCH 656/699 serial: 8250_mid: Remove 8250_pci usage
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilpo Järvinen <[email protected]>
[ Upstream commit a136abd7e7abe0f1247f8ffde6cc7c8ab09f985b ]
8250_mid uses FL_*BASE* from linux/8250_pci.h and nothing else. The code can be simplified by directly defining BARs within the driver instead.
Stable-dep-of: b1b4efea05a5 ("serial: 8250_mid: Disable DMA for selected platforms")
--- drivers/tty/serial/8250/8250_mid.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
drivers/tty/serial/8250/8250_mid.c +7 -11
@@ -12,7 +12,6 @@#include <linux/rational.h> #include <linux/dma/hsu.h> -#include <linux/8250_pci.h> #include "8250.h"
@@ -32,9 +31,9 @@struct mid8250 ;struct mid8250_board { -unsigned int flags;unsigned long freq;unsigned int base_baud; +unsigned int bar;int (*setup)(struct mid8250 *,struct uart_port *p);void (*exit)(struct mid8250 *); };
@@ -169,7 +168,6 @@ static int dnv_setup(struct mid8250 *mid {struct hsu_dma_chip *chip = &mid->dma_chip;struct pci_dev *pdev =to_pci_dev (p->dev); -unsigned int bar =FL_GET_BASE (mid->board->flags);int ret;pci_set_master (pdev);
@@ -183,7 +181,7 @@ static int dnv_setup(struct mid8250 *mid chip->dev = &pdev->dev; chip->irq =pci_irq_vector (pdev,0 ); chip->regs = p->membase; - chip->length =pci_resource_len (pdev, bar); + chip->length =pci_resource_len (pdev, mid->board->bar); chip->offset =DNV_DMA_CHAN_OFFSET ;/* Falling back to PIO mode if DMA probing fails */
@@ -292,7 +290,6 @@ static int mid8250_probe(struct pci_dev {struct uart_8250_port uart;struct mid8250 *mid; -unsigned int bar;int ret; ret =pcim_enable_device (pdev);
@@ -304,7 +301,6 @@ static int mid8250_probe(struct pci_devreturn -ENOMEM ; mid->board = (struct mid8250_board *)id->driver_data; - bar =FL_GET_BASE (mid->board->flags);memset (&uart,0 ,sizeof (struct uart_8250_port ));
@@ -317,8 +313,8 @@ static int mid8250_probe(struct pci_dev uart.port.flags =UPF_SHARE_IRQ |UPF_FIXED_PORT |UPF_FIXED_TYPE ; uart.port.set_termios = mid8250_set_termios; - uart.port.mapbase =pci_resource_start (pdev, bar); - uart.port.membase =pcim_iomap (pdev, bar,0 ); + uart.port.mapbase =pci_resource_start (pdev, mid->board->bar); + uart.port.membase =pcim_iomap (pdev, mid->board->bar,0 );if (!uart.port.membase)return -ENOMEM ;
@@ -356,25 +352,25 @@ static void mid8250_remove(struct pci_de }static const struct mid8250_board pnw_board = { - .flags =FL_BASE0 , .freq =50000000 , .base_baud =115200 , + .bar =0 , .setup = pnw_setup, .exit = pnw_exit, };static const struct mid8250_board tng_board = { - .flags =FL_BASE0 , .freq =38400000 , .base_baud =1843200 , + .bar =0 , .setup = tng_setup, .exit = tng_exit, };static const struct mid8250_board dnv_board = { - .flags =FL_BASE1 , .freq =133333333 , .base_baud =115200 , + .bar =1 , .setup = dnv_setup, .exit = dnv_exit, };
Greg Kroah-Hartman
maintainerPATCH 657/699 serial: 8250_mid: Disable DMA for selected platforms
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit b1b4efea05a56c0995e4702a86d6624b4fdff32f ]
In accordance with Errata (specification updates)
HSUART May Stop Functioning when DMA is Active.
- Denverton document #572409, rev 3.4, DNV60
- Ice Lake Xeon D document #714070, ICXD65
- Snowridge document #731931, SNR44
For a quick fix just disable the respective callbacks during the device probe. Depending on the future development we might remove them completely.
--- drivers/tty/serial/8250/8250_mid.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/tty/serial/8250/8250_mid.c +11 -2
@@ -10,6 +10,7 @@#include <linux/module.h> #include <linux/pci.h> #include <linux/rational.h> +#include <linux/util_macros.h> #include <linux/dma/hsu.h>
@@ -371,8 +372,16 @@ static const struct mid8250_board dnv_bo .freq = 133333333, .base_baud = 115200, .bar = 1, - .setup = dnv_setup, - .exit = dnv_exit, +/* +* Errata: +* HSUART May Stop Functioning when DMA is Active. +* +* - Denverton document #572409, rev 3.4, DNV60 +* - Ice Lake Xeon D document #714070, ICXD65 +* - Snowridge document #731931, SNR44 +*/ + .setup = PTR_IF(false, dnv_setup), + .exit = PTR_IF(false, dnv_exit), };#define MID_DEVICE (id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
Greg Kroah-Hartman
maintainerPATCH 658/699 xfs: reflect sb features in xfs_mount
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <[email protected]>
[ Upstream commit a1d86e8dec8c1325d301c9d5594bb794bc428fc3 ]
Currently on-disk feature checks require decoding the superblock fileds and so can be non-trivial. We have almost 400 hundred individual feature checks in the XFS code, so this is a significant amount of code. To reduce runtime check overhead, pre-process all the version flags into a features field in the xfs_mount at mount time so we can convert all the feature checks to a simple flag check.
There is also a need to convert the dynamic feature flags to update the m_features field. This is required for attr, attr2 and quota features. New xfs_mount based wrappers are added for this.
Stable-dep-of: 03866d130ed3 ("xfs: fix unreachable BIGTIME check in dquot flush validation")
--- fs/xfs/libxfs/xfs_format.h | 2 - fs/xfs/libxfs/xfs_sb.c | 64 ++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_sb.h | 1 fs/xfs/xfs_dquot.c | 2 - fs/xfs/xfs_log_recover.c | 1 fs/xfs/xfs_mount.c | 1 fs/xfs/xfs_mount.h | 75 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_rtalloc.c | 3 + 8 files changed, 147 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_format.h +1 -1
@@ -412,7 +412,7 @@ static inline bool xfs_sb_version_haspro (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT)); } -static inline void xfs_sb_version_addprojid32bit (struct xfs_sb *sbp) +static inline void xfs_sb_version_addprojid32 (struct xfs_sb *sbp) { sbp->sb_versionnum |=XFS_SB_VERSION_MOREBITSBIT ; sbp->sb_features2 |=XFS_SB_VERSION2_PROJID32BIT ;
fs/xfs/libxfs/xfs_sb.c +64 -0
70 lines not on this page · raw message
fs/xfs/libxfs/xfs_sb.h +1 -0
@@ -29,6 +29,7 @@ extern void xfs_sb_mount_common(struct xextern void xfs_sb_from_disk (struct xfs_sb *to,struct xfs_dsb *from);extern void xfs_sb_to_disk (struct xfs_dsb *to,struct xfs_sb *from);extern void xfs_sb_quota_from_disk (struct xfs_sb *sbp); +extern uint64_t xfs_sb_version_to_features (struct xfs_sb *sbp);extern int xfs_update_secondary_sbs (struct xfs_mount *mp);
fs/xfs/xfs_dquot.c +1 -1
@@ -1218,7 +1218,7 @@ xfs_qm_dqflush_check(/* bigtime flag should never be set on root dquots */ if (dqp->q_type &XFS_DQTYPE_BIGTIME ) { -if (!xfs_sb_version_hasbigtime (&dqp->q_mount->m_sb)) +if (!xfs_has_bigtime (dqp->q_mount))return __this_address;if (dqp->q_id ==0 )return __this_address;
fs/xfs/xfs_log_recover.c +1 -0
@@ -3325,6 +3325,7 @@ xlog_do_recover(xfs_buf_relse (bp);/* re-initialise in-core superblock and geometry structures */ + mp->m_features |=xfs_sb_version_to_features (sbp);xfs_reinit_percpu_counters (mp); error =xfs_initialize_perag (mp, sbp->sb_agcount, &mp->m_maxagi);if (error) {
fs/xfs/xfs_mount.c +1 -0
@@ -345,6 +345,7 @@ reread: goto reread; } + mp->m_features |=xfs_sb_version_to_features (sbp);xfs_reinit_percpu_counters (mp);/* no need to be quiet anymore, so reset the buf ops */
fs/xfs/xfs_mount.h +75 -0
87 lines not on this page · raw message
fs/xfs/xfs_rtalloc.c +3 -0
@@ -1101,6 +1101,9 @@ error_cancel: error =xfs_trans_commit (tp);if (error)break ; + +/* Ensure the mount RT feature flag is now set. */ + mp->m_features |=XFS_FEAT_REALTIME ; }if (error) goto out_free;
Greg Kroah-Hartman
maintainerPATCH 659/699 xfs: fix unreachable BIGTIME check in dquot flush validation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Nepomnyashih <[email protected]>
[ Upstream commit 03866d130ed33ab68cc7faaf4bf2c4abef96d42e ]
The dqp->q_id == 0 check inside the XFS_DQTYPE_BIGTIME block is unreachable because root dquots return successfully earlier. Reject root dquots with XFS_DQTYPE_BIGTIME before that early return, preserving the intended validation and removing the unreachable condition.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- fs/xfs/xfs_dquot.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
fs/xfs/xfs_dquot.c +8 -8
@@ -1201,6 +1201,14 @@ xfs_qm_dqflush_check( type != XFS_DQTYPE_PROJ)return __this_address; +/* bigtime flag should never be set on root dquots */ +if (dqp->q_type &XFS_DQTYPE_BIGTIME ) { +if (!xfs_has_bigtime (dqp->q_mount)) +return __this_address; +if (dqp->q_id ==0 ) +return __this_address; + } +if (dqp->q_id ==0 )return NULL ;
@@ -1216,14 +1224,6 @@ xfs_qm_dqflush_check( !dqp->q_rtb.timer)return __this_address; -/* bigtime flag should never be set on root dquots */ -if (dqp->q_type &XFS_DQTYPE_BIGTIME ) { -if (!xfs_has_bigtime (dqp->q_mount)) -return __this_address; -if (dqp->q_id ==0 ) -return __this_address; - } -return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 660/699 xfs: use null daddr for unset first bad log block
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
[ Upstream commit cc9af5e461ea5f6e37738f3f1e41c45a9b7f45d6 ]
xlog_do_recovery_pass() may return before setting first_bad. The caller must distinguish that case from an error at a valid log block, including block zero after the log wraps.
Initialize first_bad to XFS_BUF_DADDR_NULL and test it explicitly before treating the error as a torn write.
--- fs/xfs/xfs_log_recover.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/xfs/xfs_log_recover.c +3 -2
@@ -1034,7 +1034,7 @@ xlog_verify_head( {struct xlog_rec_header *tmp_rhead;char *tmp_buffer; -xfs_daddr_t first_bad; +xfs_daddr_t first_bad =XFS_BUF_DADDR_NULL ;xfs_daddr_t tmp_rhead_blk;int found;int error;
@@ -1063,7 +1063,8 @@ xlog_verify_head(*/ error =xlog_do_recovery_pass (log, *head_blk, tmp_rhead_blk,XLOG_RECOVER_CRCPASS , &first_bad); -if ((error == -EFSBADCRC || error == -EFSCORRUPTED ) && first_bad) { +if ((error == -EFSBADCRC || error == -EFSCORRUPTED ) && + first_bad !=XFS_BUF_DADDR_NULL ) {/* * We've hit a potential torn write. Reset the error and warn * about it.
Greg Kroah-Hartman
maintainerPATCH 661/699 hfs/hfsplus: prevent getting negative values of offset/length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <[email protected]>
[ Upstream commit 00c14a09a70e10ae18eb3707d0059291425c04bd ]
The syzbot reported KASAN out-of-bounds issue inhfs_bnode_move():
[ 45.588165][ T9821] hfs: dst 14, src 65536, len -65536 [ 45.588895][ T9821] ================================================================== [ 45.590114][ T9821] BUG: KASAN: out-of-bounds in hfs_bnode_move+0xfd/0x140 [ 45.591127][ T9821] Read of size 18446744073709486080 at addr ffff888035935400 by task repro/9821 [ 45.592207][ T9821] [ 45.592420][ T9821] CPU: 0 UID: 0 PID: 9821 Comm: repro Not tainted 6.16.0-rc7-dirty #42 PREEMPT(full) [ 45.592428][ T9821] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 45.592431][ T9821] Call Trace: [ 45.592434][ T9821] <TASK> [ 45.592437][ T9821] dump_stack_lvl+0x1c1/0x2a0 [ 45.592446][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592454][ T9821] ? __pfx_dump_stack_lvl+0x10/0x10 [ 45.592461][ T9821] ? rcu_is_watching+0x15/0xb0 [ 45.592469][ T9821] ? lock_release+0x4b/0x3e0 [ 45.592476][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592483][ T9821] ? __virt_addr_valid+0x4a5/0x5c0 [ 45.592491][ T9821] print_report+0x17e/0x7c0 [ 45.592497][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592504][ T9821] ? __virt_addr_valid+0x4a5/0x5c0 [ 45.592511][ T9821] ? __phys_addr+0xd3/0x180 [ 45.592519][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592526][ T9821] kasan_report+0x147/0x180 [ 45.592531][ T9821] ? _printk+0xcf/0x120 [ 45.592537][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592544][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592552][ T9821] kasan_check_range+0x2b0/0x2c0 [ 45.592557][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592565][ T9821] __asan_memmove+0x29/0x70 [ 45.592572][ T9821] hfs_bnode_move+0xfd/0x140 [ 45.592580][ T9821] hfs_brec_remove+0x473/0x560 [ 45.592589][ T9821] hfs_cat_move+0x6fb/0x960 [ 45.592598][ T9821] ? __pfx_hfs_cat_move+0x10/0x10 [ 45.592607][ T9821] ? seqcount_lockdep_reader_access+0x122/0x1c0 [ 45.592614][ T9821] ? lockdep_hardirqs_on+0x9c/0x150 [ 45.592631][ T9821] ? __lock_acquire+0xaec/0xd80 [ 45.592641][ T9821] hfs_rename+0x1dc/0x2d0 [ 45.592649][ T9821] ? __pfx_hfs_rename+0x10/0x10 [ 45.592657][ T9821] vfs_rename+0xac6/0xed0 [ 45.592664][ T9821] ? __pfx_vfs_rename+0x10/0x10 [ 45.592670][ T9821] ? d_alloc+0x144/0x190 [ 45.592677][ T9821] ? bpf_lsm_path_rename+0x9/0x20 [ 45.592683][ T9821] ? security_path_rename+0x17d/0x490 [ 45.592691][ T9821] do_renameat2+0x890/0xc50 [ 45.592699][ T9821] ? __pfx_do_renameat2+0x10/0x10 [ 45.592707][ T9821] ? getname_flags+0x1e5/0x540 [ 45.592714][ T9821] __x64_sys_rename+0x82/0x90 [ 45.592720][ T9821] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.592725][ T9821] do_syscall_64+0xf3/0x3a0 [ 45.592741][ T9821] ? exc_page_fault+0x9f/0xf0 [ 45.592748][ T9821] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.592754][ T9821] RIP: 0033:0x7f7f73fe3fc9 [ 45.592760][ T9821] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 48 [ 45.592765][ T9821] RSP: 002b:00007ffc7e116cf8 EFLAGS: 00000283 ORIG_RAX: 0000000000000052 [ 45.592772][ T9821] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7f73fe3fc9 [ 45.592776][ T9821] RDX: 0000200000000871 RSI: 0000200000000780 RDI: 00002000000003c0 [ 45.592781][ T9821] RBP: 00007ffc7e116d00 R08: 0000000000000000 R09: 00007ffc7e116d30 [ 45.592784][ T9821] R10: fffffffffffffff0 R11: 0000000000000283 R12: 00005557e81f8250 [ 45.592788][ T9821] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 45.592795][ T9821] </TASK> [ 45.592797][ T9821] [ 45.619721][ T9821] The buggy address belongs to the physical page: [ 45.620300][ T9821] page: refcount:1 mapcount:1 mapping:0000000000000000 index:0x559a88174 pfn:0x35935 [ 45.621150][ T9821] memcg:ffff88810a1d5b00 [ 45.621531][ T9821] anon flags: 0xfff60000020838(uptodate|dirty|lru|owner_2|swapbacked|node=0|zone=1|lastcpupid=0x7ff) [ 45.622496][ T9821] raw: 00fff60000020838 ffffea0000d64d88 ffff888021753e10 ffff888029da0771 [ 45.623260][ T9821] raw: 0000000559a88174 0000000000000000 0000000100000000 ffff88810a1d5b00 [ 45.624030][ T9821] page dumped because: kasan: bad access detected [ 45.624602][ T9821] page_owner tracks the page as allocated [ 45.625115][ T9821] page last allocated via order 0, migratetype Movable, gfp_mask 0x140dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO0 [ 45.626685][ T9821] post_alloc_hook+0x240/0x2a0 [ 45.627127][ T9821] get_page_from_freelist+0x2101/0x21e0 [ 45.627628][ T9821] __alloc_frozen_pages_noprof+0x274/0x380 [ 45.628154][ T9821] alloc_pages_mpol+0x241/0x4b0 [ 45.628593][ T9821] vma_alloc_folio_noprof+0xe4/0x210 [ 45.629066][ T9821] folio_prealloc+0x30/0x180 [ 45.629487][ T9821] __handle_mm_fault+0x34bd/0x5640 [ 45.629957][ T9821] handle_mm_fault+0x40e/0x8e0 [ 45.630392][ T9821] do_user_addr_fault+0xa81/0x1390 [ 45.630862][ T9821] exc_page_fault+0x76/0xf0 [ 45.631273][ T9821] asm_exc_page_fault+0x26/0x30 [ 45.631712][ T9821] page last free pid 5269 tgid 5269 stack trace: [ 45.632281][ T9821] free_unref_folios+0xc73/0x14c0 [ 45.632740][ T9821] folios_put_refs+0x55b/0x640 [ 45.633177][ T9821] free_pages_and_swap_cache+0x26d/0x510 [ 45.633685][ T9821] tlb_flush_mmu+0x3a0/0x680 [ 45.634105][ T9821] tlb_finish_mmu+0xd4/0x200 [ 45.634525][ T9821] exit_mmap+0x44c/0xb70 [ 45.634914][ T9821] __mmput+0x118/0x420 [ 45.635286][ T9821] exit_mm+0x1da/0x2c0 [ 45.635659][ T9821] do_exit+0x652/0x2330 [ 45.636039][ T9821] do_group_exit+0x21c/0x2d0 [ 45.636457][ T9821] __x64_sys_exit_group+0x3f/0x40 [ 45.636915][ T9821] x64_sys_call+0x21ba/0x21c0 [ 45.637342][ T9821] do_syscall_64+0xf3/0x3a0 [ 45.637756][ T9821] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.638290][ T9821] page has been migrated, last migrate reason: numa_misplaced [ 45.638956][ T9821] [ 45.639173][ T9821] Memory state around the buggy address: [ 45.639677][ T9821] ffff888035935300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.640397][ T9821] ffff888035935380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.641117][ T9821] >ffff888035935400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.641837][ T9821] ^ [ 45.642207][ T9821] ffff888035935480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.642929][ T9821] ffff888035935500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.643650][ T9821] ==================================================================
This commit [1] fixes the issue if an offset inside of b-tree node or length of the request is bigger than b-tree node. However, this fix is still not ready for negative values
of the offset or length. Moreover, negative values of the offset or length doesn't make sense for b-tree's operations. Because we could try to access the memory address outside of the beginning of memory page's addresses range. Also, using of negative values make logic very complicated, unpredictable, and we could access the wrong item(s)
in the b-tree node.
This patch changes b-tree interface by means of converting signed integer arguments of offset and length on u32 type. Such conversion has goal to prevent of using negative values unintentionally or by mistake in b-tree operations.
[1] 'commit a431930c9bac ("hfs: fix slab-out-of-bounds in hfs_bnode_read()")'
Stable-dep-of: 966cb76fb285 ("hfs/hfsplus: fix u32 overflow in check_and_correct_requested_length")
--- fs/hfs/bfind.c | 2 - fs/hfs/bnode.c | 52 +++++++++++++++--------------- fs/hfs/brec.c | 2 - fs/hfs/btree.c | 2 - fs/hfs/btree.h | 71 ++++++++++++++++++++--------------------- fs/hfs/hfs_fs.h | 83 ++++++++++++++++++++++++++++-------------------- fs/hfs/inode.c | 2 - fs/hfsplus/bfind.c | 2 - fs/hfsplus/bnode.c | 60 +++++++++++++++++----------------- fs/hfsplus/brec.c | 2 - fs/hfsplus/btree.c | 2 - fs/hfsplus/hfsplus_fs.h | 38 ++++++++++----------- 12 files changed, 167 insertions(+), 151 deletions(-)
fs/hfs/bfind.c +1 -1
@@ -164,7 +164,7 @@ release:return res; } -int hfs_brec_read (struct hfs_find_data *fd,void *rec,int rec_len) +int hfs_brec_read (struct hfs_find_data *fd,void *rec,u32 rec_len) {int res;
fs/hfs/bnode.c +26 -26
172 lines not on this page · raw message
fs/hfs/brec.c +1 -1
@@ -62,7 +62,7 @@ u16 hfs_brec_keylen(struct hfs_bnode *noreturn retval; } -int hfs_brec_insert (struct hfs_find_data *fd,void *entry,int entry_len) +int hfs_brec_insert (struct hfs_find_data *fd,void *entry,u32 entry_len) {struct hfs_btree *tree;struct hfs_bnode *node, *new_node;
fs/hfs/btree.c +1 -1
@@ -221,7 +221,7 @@ static struct hfs_bnode *hfs_bmap_new_bm }/* Make sure @tree has enough space for the @rsvd_nodes */ -int hfs_bmap_reserve (struct hfs_btree *tree,int rsvd_nodes) +int hfs_bmap_reserve (struct hfs_btree *tree,u32 rsvd_nodes) {struct inode *inode = tree->inode;u32 count;
fs/hfs/btree.h +36 -35
84 lines not on this page · raw message
fs/hfs/hfs_fs.h +49 -34
119 lines not on this page · raw message
fs/hfs/inode.c +1 -1
@@ -50,7 +50,7 @@ static void hfs_write_failed(struct addr }static int hfs_write_begin (struct file *file,struct address_space *mapping, -loff_t pos,unsigned len,unsigned flags, +loff_t pos,unsigned int len,unsigned flags,struct page **pagep,void **fsdata) {int ret;
fs/hfsplus/bfind.c +1 -1
@@ -210,7 +210,7 @@ release:return res; } -int hfs_brec_read (struct hfs_find_data *fd,void *rec,int rec_len) +int hfs_brec_read (struct hfs_find_data *fd,void *rec,u32 rec_len) {int res;
fs/hfsplus/bnode.c +30 -30
207 lines not on this page · raw message
fs/hfsplus/brec.c +1 -1
@@ -60,7 +60,7 @@ u16 hfs_brec_keylen(struct hfs_bnode *noreturn retval; } -int hfs_brec_insert (struct hfs_find_data *fd,void *entry,int entry_len) +int hfs_brec_insert (struct hfs_find_data *fd,void *entry,u32 entry_len) {struct hfs_btree *tree;struct hfs_bnode *node, *new_node;
fs/hfsplus/btree.c +1 -1
@@ -343,7 +343,7 @@ static struct hfs_bnode *hfs_bmap_new_bm }/* Make sure @tree has enough space for the @rsvd_nodes */ -int hfs_bmap_reserve (struct hfs_btree *tree,int rsvd_nodes) +int hfs_bmap_reserve (struct hfs_btree *tree,u32 rsvd_nodes) {struct inode *inode = tree->inode;struct hfsplus_inode_info *hip =HFSPLUS_I (inode);
fs/hfsplus/hfsplus_fs.h +19 -19
@@ -399,21 +399,21 @@ u32 hfsplus_calc_btree_clump_size(u32 blstruct hfs_btree *hfs_btree_open (struct super_block *sb,u32 id);void hfs_btree_close (struct hfs_btree *tree);int hfs_btree_write (struct hfs_btree *tree); -int hfs_bmap_reserve (struct hfs_btree *tree,int rsvd_nodes); +int hfs_bmap_reserve (struct hfs_btree *tree,u32 rsvd_nodes);struct hfs_bnode *hfs_bmap_alloc (struct hfs_btree *tree);void hfs_bmap_free (struct hfs_bnode *node);/* bnode.c */ -void hfs_bnode_read (struct hfs_bnode *node,void *buf,int off,int len); -u16 hfs_bnode_read_u16 (struct hfs_bnode *node,int off); -u8 hfs_bnode_read_u8 (struct hfs_bnode *node,int off); -void hfs_bnode_read_key (struct hfs_bnode *node,void *key,int off); -void hfs_bnode_write (struct hfs_bnode *node,void *buf,int off,int len); -void hfs_bnode_write_u16 (struct hfs_bnode *node,int off,u16 data); -void hfs_bnode_clear (struct hfs_bnode *node,int off,int len); -void hfs_bnode_copy (struct hfs_bnode *dst_node,int dst, -struct hfs_bnode *src_node,int src,int len); -void hfs_bnode_move (struct hfs_bnode *node,int dst,int src,int len); +void hfs_bnode_read (struct hfs_bnode *node,void *buf,u32 off,u32 len); +u16 hfs_bnode_read_u16 (struct hfs_bnode *node,u32 off); +u8 hfs_bnode_read_u8 (struct hfs_bnode *node,u32 off); +void hfs_bnode_read_key (struct hfs_bnode *node,void *key,u32 off); +void hfs_bnode_write (struct hfs_bnode *node,void *buf,u32 off,u32 len); +void hfs_bnode_write_u16 (struct hfs_bnode *node,u32 off,u16 data); +void hfs_bnode_clear (struct hfs_bnode *node,u32 off,u32 len); +void hfs_bnode_copy (struct hfs_bnode *dst_node,u32 dst, +struct hfs_bnode *src_node,u32 src,u32 len); +void hfs_bnode_move (struct hfs_bnode *node,u32 dst,u32 src,u32 len);void hfs_bnode_dump (struct hfs_bnode *node);void hfs_bnode_unlink (struct hfs_bnode *node);struct hfs_bnode *hfs_bnode_findhash (struct hfs_btree *tree,u32 cnid);
@@ -428,7 +428,7 @@ bool hfs_bnode_need_zeroout(struct hfs_b/* brec.c */ u16 hfs_brec_lenoff (struct hfs_bnode *node,u16 rec,u16 *off);u16 hfs_brec_keylen (struct hfs_bnode *node,u16 rec); -int hfs_brec_insert (struct hfs_find_data *fd,void *entry,int entry_len); +int hfs_brec_insert (struct hfs_find_data *fd,void *entry,u32 entry_len);int hfs_brec_remove (struct hfs_find_data *fd);/* bfind.c */
@@ -441,7 +441,7 @@ int hfs_find_rec_by_key(struct hfs_bnodeint __hfs_brec_find (struct hfs_bnode *bnode,struct hfs_find_data *fd,search_strategy_t rec_found);int hfs_brec_find (struct hfs_find_data *fd,search_strategy_t do_key_compare); -int hfs_brec_read (struct hfs_find_data *fd,void *rec,int rec_len); +int hfs_brec_read (struct hfs_find_data *fd,void *rec,u32 rec_len);int hfs_brec_goto (struct hfs_find_data *fd,int cnt);/* catalog.c */
@@ -589,14 +589,14 @@ hfsplus_btree_lock_class(struct hfs_btre }static inline -bool is_bnode_offset_valid (struct hfs_bnode *node,int off) +bool is_bnode_offset_valid (struct hfs_bnode *node,u32 off) {bool is_valid = off < node->tree->node_size;if (!is_valid) {pr_err ("requested invalid offset: " "NODE: id %u, type %#x, height %u, " -"node_size %u, offset %d\n" , +"node_size %u, offset %u\n" , node->this, node->type, node->height, node->tree->node_size, off); }
@@ -605,7 +605,7 @@ bool is_bnode_offset_valid(struct hfs_bn }static inline -int check_and_correct_requested_length (struct hfs_bnode *node,int off,int len) +u32 check_and_correct_requested_length (struct hfs_bnode *node,u32 off,u32 len) {unsigned int node_size;
@@ -615,12 +615,12 @@ int check_and_correct_requested_length(s node_size = node->tree->node_size;if ((off + len) > node_size) { -int new_len = (int )node_size - off; +u32 new_len = node_size - off;pr_err ("requested length has been corrected: " "NODE: id %u, type %#x, height %u, " -"node_size %u, offset %d, " -"requested_len %d, corrected_len %d\n" , +"node_size %u, offset %u, " +"requested_len %u, corrected_len %u\n" , node->this, node->type, node->height, node->tree->node_size, off, len, new_len);
Greg Kroah-Hartman
maintainerPATCH 662/699 hfs/hfsplus: fix u32 overflow in check_and_correct_requested_length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 966cb76fb2857a4242cab6ea2ea17acf818a3da7 ]
check_and_correct_requested_length() compares (off + len) against node_size using u32 arithmetic. When the caller passes a large len value (e.g. from an underflowed subtraction in hfs_brec_remove()), off + len can wrap past 2^32 and produce a small result, causing the bounds check to pass when it should fail.
For example, with off=14 and len=0xFFFFFFF2 (underflowed from data_off - keyoffset - size in hfs_brec_remove), off + len wraps to 6, which is less than a typical node_size of 512, so the check passes and the subsequent memmove reads ~4GB past the node buffer.
Fix this by widening the addition to u64 before comparing against node_size. This prevents the u32 wrap while keeping the logic straightforward.
--- fs/hfs/bnode.c | 2 +- fs/hfsplus/hfsplus_fs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
fs/hfs/bnode.c +1 -1
@@ -41,7 +41,7 @@ u32 check_and_correct_requested_length(s node_size = node->tree->node_size; -if ((off + len) > node_size) { +if ((u64 )off + len > node_size) {u32 new_len = node_size - off; pr_err("requested length has been corrected: "
fs/hfsplus/hfsplus_fs.h +1 -1
@@ -614,7 +614,7 @@ u32 check_and_correct_requested_length(s node_size = node->tree->node_size; -if ((off + len) > node_size) { +if ((u64 )off + len > node_size) {u32 new_len = node_size - off; pr_err("requested length has been corrected: "
Greg Kroah-Hartman
maintainerPATCH 663/699 usb: gadget: function: Simplify diagnostic messaging in printer
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrzej Pietrasiewicz <[email protected]>
[ Upstream commit 57b7b733b1a7aeab25bc2670afff608214284863 ]
Don't issue messages which can be easily achieved with ftrace. In case of printer_open() the return code is propagated to other layers so the user will know about -EBUSY anyway.
Stable-dep-of: 30adce93d5c4 ("usb: gadget: f_printer: take kref only for successful open")
--- drivers/usb/gadget/function/f_printer.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/usb/gadget/function/f_printer.c +1 -8
@@ -363,7 +363,7 @@ printer_open(struct inode *inode, structspin_unlock_irqrestore (&dev->lock, flags);kref_get (&dev->kref); -DBG (dev,"printer_open returned %x\n" , ret); +return ret; }
@@ -381,7 +381,6 @@ printer_close(struct inode *inode, strucspin_unlock_irqrestore (&dev->lock, flags);kref_put (&dev->kref, printer_dev_free); -DBG (dev,"printer_close\n" );return 0 ; }
@@ -867,8 +866,6 @@ static void printer_reset_interface(struif (dev->interface <0 )return ; -DBG (dev,"%s\n" , __func__); -if (dev->in_ep->desc)usb_ep_disable (dev->in_ep);
@@ -906,8 +903,6 @@ static void printer_soft_reset(struct pr {struct usb_request *req; -INFO (dev,"Received Printer Reset Request\n" ); -if (usb_ep_disable (dev->in_ep))DBG (dev,"Failed to disable USB in_ep\n" );if (usb_ep_disable (dev->out_ep))
@@ -1204,8 +1199,6 @@ static void printer_func_disable(struct {struct printer_dev *dev =func_to_printer (f); -DBG (dev,"%s\n" , __func__); -printer_reset_interface (dev); }
Greg Kroah-Hartman
maintainerPATCH 664/699 usb: gadget: f_printer: take kref only for successful open
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
[ Upstream commit 30adce93d5c4a5a1ec29d9249e3fdfcc391d406b ]
printer_open() returns -EBUSY when the character device is already open, but it increments dev->kref regardless of the return value. VFS does not call ->release() for a failed open, so every rejected second open permanently leaks one reference.
Move kref_get() into the successful-open branch.
--- drivers/usb/gadget/function/f_printer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/gadget/function/f_printer.c +1 -2
@@ -358,12 +358,11 @@ printer_open(struct inode *inode, struct ret =0 ;/* Change the printer status to show that it's on-line. */ dev->printer_status |=PRINTER_SELECTED ; +kref_get (&dev->kref); }spin_unlock_irqrestore (&dev->lock, flags); -kref_get (&dev->kref); -return ret; }
Greg Kroah-Hartman
maintainerPATCH 665/699 usb: free iso schedules on failed submit
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit b9399d25fbb34a05bbe76eeedd730f62ff2670e9 ]
EHCI and FOTG210 isochronous submits build an ehci_iso_sched before linking the URB to the endpoint queue, and keep the staged schedule in urb->hcpriv until iso_stream_schedule() and the link helpers consume it. If the controller is no longer accessible, or usb_hcd_link_urb_to_ep() fails, submit jumps to done_not_linked before that handoff happens and leaks the staged schedule still attached to urb->hcpriv.
Free the staged schedule from done_not_linked when submit fails before the URB is linked and clear urb->hcpriv after the free.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an EHCI host controller with a USB isochronous device to test with, no runtime testing was able to be performed.
--- drivers/usb/host/ehci-sched.c | 11 +++++++++-- drivers/usb/host/fotg210-hcd.c | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-)
drivers/usb/host/ehci-sched.c +9 -2
@@ -1613,6 +1613,7 @@ iso_stream_schedule( status =1 ;/* and give it back immediately */ iso_sched_free (stream, sched); sched =NULL ; + urb->hcpriv =NULL ; } } urb->error_count = skip / period;
@@ -1643,8 +1644,6 @@ iso_stream_schedule(return status; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -1956,6 +1955,10 @@ static int itd_submit(struct ehci_hcd *eusb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
@@ -2333,6 +2336,10 @@ static int sitd_submit(struct ehci_hcd *usb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
drivers/usb/host/fotg210-hcd.c +4 -2
@@ -4271,8 +4271,6 @@ static int iso_stream_schedule(struct foreturn 0 ; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -4566,6 +4564,10 @@ static int itd_submit(struct fotg210_hcdelse usb_hcd_unlink_urb_from_ep (fotg210_to_hcd (fotg210), urb); done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&fotg210->lock, flags); done:return status;
Greg Kroah-Hartman
maintainerPATCH 666/699 usb: iowarrior: remove inherent race with minor number
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
[ Upstream commit 56dd29088c9d9510c48a8ebad2465248fde36551 ]
The driver saves the minor number it gets upon registration in its descriptor for debugging purposes. However, there is inevitably a window between registration and saving the correct minor in a descriptor. During this window the debugging output will be wrong.
As wrong debug output is worse than no debug output, just remove it.
Stable-dep-of: c602254ba4c1 ("USB: iowarrior: fix use-after-free on disconnect race")
--- drivers/usb/misc/iowarrior.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
drivers/usb/misc/iowarrior.c +3 -14
@@ -74,7 +74,6 @@ struct iowarrior {struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */ -unsigned char minor;/* the starting minor number for this device */ struct usb_endpoint_descriptor *int_out_endpoint;/* endpoint for reading (needed for IOW56 only) */ struct usb_endpoint_descriptor *int_in_endpoint;/* endpoint for reading */ struct urb *int_in_urb;/* the urb for reading data */
@@ -246,7 +245,6 @@ static void iowarrior_write_callback(str*/ static inline void iowarrior_delete (struct iowarrior *dev) { -dev_dbg (&dev->interface->dev,"minor %d\n" , dev->minor);kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -297,9 +295,6 @@ static ssize_t iowarrior_read(struct fil goto exit; } -dev_dbg (&dev->interface->dev,"minor %d, count = %zd\n" , - dev->minor, count); -/* read count must be packet size (+ time stamp) */ if ((count != dev->report_size) && (count != (dev->report_size +1 ))) {
@@ -379,8 +374,6 @@ static ssize_t iowarrior_write(struct fi retval = -ENODEV ; goto exit; } -dev_dbg (&dev->interface->dev,"minor %d, count = %zd\n" , - dev->minor, count);/* if count is 0 we're already done */ if (count ==0 ) { retval =0 ;
@@ -526,9 +519,6 @@ static long iowarrior_ioctl(struct file goto error_out; } -dev_dbg (&dev->interface->dev,"minor %d, cmd 0x%.4x, arg %ld\n" , - dev->minor, cmd, arg); - retval =0 ; io_res =0 ;switch (cmd) {
@@ -675,8 +665,6 @@ static int iowarrior_release(struct inodif (!dev)return -ENODEV ; -dev_dbg (&dev->interface->dev,"minor %d\n" , dev->minor); -/* lock our device */ mutex_lock (&dev->mutex);
@@ -779,6 +767,7 @@ static int iowarrior_probe(struct usb_instruct usb_host_interface *iface_desc;int retval = -ENOMEM ;int res; +int minor;/* allocate memory for our device state and initialize it */ dev =kzalloc (sizeof (struct iowarrior ),GFP_KERNEL );
@@ -894,12 +883,12 @@ static int iowarrior_probe(struct usb_in goto error; } - dev->minor = interface->minor; + minor = interface->minor;/* let the user know what node this device is now attached to */ dev_info (&interface->dev,"IOWarrior product=0x%x, serial=%s interface=%d " "now attached to iowarrior%d\n" , dev->product_id, dev->chip_serial, - iface_desc->desc.bInterfaceNumber, dev->minor -IOWARRIOR_MINOR_BASE ); + iface_desc->desc.bInterfaceNumber, minor -IOWARRIOR_MINOR_BASE );return retval; error:
Greg Kroah-Hartman
maintainerPATCH 667/699 USB: serial: digi_acceleport: fix write buffer corruption
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 24ca1fea8f2753bf33e1d458ec1ae5d9b7796a65 ]
The digi_write_inb_command() is supposed to wait for the write urb to become available or return an error, but instead it updates the transfer buffer and tries to resubmit the urb on timeout.
To make things worse, for commands like break control where no timeout is used, the driver would corrupt the urb immediately due to a broken jiffies comparison (on 32-bit machines this takes five minutes of uptime to trigger due to INITIAL_JIFFIES).
Fix this by adding the missing return on timeout and waiting indefinitely when no timeout has been specified as intended.
This issue was (sort of) flagged by Sashiko when reviewing an unrelated change to the driver.
--- drivers/usb/serial/digi_acceleport.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/usb/serial/digi_acceleport.c +10 -5
@@ -431,20 +431,22 @@ static int digi_write_inb_command(structint len;struct digi_port *priv =usb_get_serial_port_data (port);unsigned char *data = port->write_urb->transfer_buffer; +unsigned long expire;unsigned long flags =0 ;dev_dbg (&port->dev,"digi_write_inb_command: TOP: port=%d, count=%d\n" , priv->dp_port_num, count);if (timeout) - timeout += jiffies; -else - timeout =ULONG_MAX ; + expire = jiffies + timeout;spin_lock_irqsave (&priv->dp_port_lock, flags);while (count >0 && ret ==0 ) { -while (priv->dp_write_urb_in_use && -time_before (jiffies, timeout)) { +while (priv->dp_write_urb_in_use) { +if (timeout &&time_after (jiffies, expire)) { + ret = -ETIMEDOUT ; +break ; + }cond_wait_interruptible_timeout_irqrestore ( &port->write_wait,DIGI_RETRY_TIMEOUT , &priv->dp_port_lock, flags);
@@ -453,6 +455,9 @@ static int digi_write_inb_command(structspin_lock_irqsave (&priv->dp_port_lock, flags); } +if (ret) +break ; +/* len must be a multiple of 4 and small enough to */ /* guarantee the write will send buffered data first, */ /* so commands are in order with data and not split */
Greg Kroah-Hartman
maintainerPATCH 668/699 drm/i2c/sil164: Drop no-op remove function
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit eb09882d64807c24228ed1d005dbbae70860ca3f ]
A remove callback that just returns 0 is equivalent to no callback at all as can be seen in i2c_device_remove(). So simplify accordingly.
Stable-dep-of: 1f0bdc2884b6 ("usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove")
--- drivers/gpu/drm/i2c/sil164_drv.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/gpu/drm/i2c/sil164_drv.c +0 -7
@@ -370,12 +370,6 @@ sil164_probe(struct i2c_client *client,return 0 ; } -static int -sil164_remove (struct i2c_client *client) -{ -return 0 ; -} -static struct i2c_client *sil164_detect_slave (struct i2c_client *client) {
@@ -427,7 +421,6 @@ MODULE_DEVICE_TABLE(i2c, sil164_ids);static struct drm_i2c_encoder_driver sil164_driver = { .i2c_driver = { .probe = sil164_probe, - .remove = sil164_remove, .driver = { .name ="sil164" , },
Greg Kroah-Hartman
maintainerPATCH 669/699 leds: lm3697: Remove duplicated error reporting in .remove()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit af89fa11fae1cee4e07453f780e6e5573ef0f477 ]
Returning an error value from an i2c remove callback results in an error message being emitted by the i2c core, but otherwise it doesn't make a difference. The device goes away anyhow and the devm cleanups are called.
As lm3697_remove() already emits an error message on failure and the additional error message by the i2c core doesn't add any useful information, don't pass the error value up the stack. Instead continue to clean up and return 0.
This patch is a preparation for making i2c remove callbacks return void.
Stable-dep-of: 1f0bdc2884b6 ("usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove")
--- drivers/leds/leds-lm3697.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/leds/leds-lm3697.c +1 -3
@@ -337,10 +337,8 @@ static int lm3697_remove(struct i2c_clie ret =regmap_update_bits (led->regmap,LM3697_CTRL_ENABLE ,LM3697_CTRL_A_B_EN ,0 ); -if (ret) { +if (ret)dev_err (dev,"Failed to disable the device\n" ); -return ret; - }if (led->enable_gpio)gpiod_direction_output (led->enable_gpio,0 );
Greg Kroah-Hartman
maintainerPATCH 670/699 leds: lm3601x: Improve error reporting for problems during .remove()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 22a23436891886a66d21af3619f4a4e8809f0e0a ]
Returning an error value in an i2c remove callback results in a generic error message being emitted by the i2c core, but otherwise it doesn't make a difference. The device goes away anyhow and the devm cleanups are called.
So instead of triggering the generic i2c error message, emit a more helpful message if a problem occurs and return 0 to suppress the generic message.
This patch is a preparation for making i2c remove callbacks return void.
Stable-dep-of: 1f0bdc2884b6 ("usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove")
--- drivers/leds/leds-lm3601x.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/leds/leds-lm3601x.c +8 -3
@@ -443,10 +443,15 @@ static int lm3601x_probe(struct i2c_cliestatic int lm3601x_remove (struct i2c_client *client) {struct lm3601x_led *led =i2c_get_clientdata (client); +int ret; -return regmap_update_bits (led->regmap,LM3601X_ENABLE_REG , -LM3601X_ENABLE_MASK , -LM3601X_MODE_STANDBY ); + ret =regmap_update_bits (led->regmap,LM3601X_ENABLE_REG , +LM3601X_ENABLE_MASK ,LM3601X_MODE_STANDBY ); +if (ret) +dev_warn (&client->dev, +"Failed to put into standby (%pe)\n" ,ERR_PTR (ret)); + +return 0 ; }static const struct i2c_device_id lm3601x_id[] = {
Greg Kroah-Hartman
maintainerPATCH 671/699 gpio: pca953x: Make platform teardown callback return void
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 6a8f359c3132e4f51bdb263ad74ec632c65e55fd ]
All platforms that provide a teardown callback return 0. New users are supposed to not make use of platform support, so there is no functionality lost.
This patch is a preparation for making i2c remove callbacks return void.
Stable-dep-of: 1f0bdc2884b6 ("usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove")
--- arch/arm/mach-davinci/board-da850-evm.c | 12 ++++-------- drivers/gpio/gpio-pca953x.c | 11 +++-------- include/linux/platform_data/pca953x.h | 2 +- 3 files changed, 8 insertions(+), 17 deletions(-)
arch/arm/mach-davinci/board-da850-evm.c +4 -8
@@ -519,8 +519,8 @@ exp_setup_sela_fail:return ret; } -static int da850_evm_ui_expander_teardown (struct i2c_client *client, -unsigned gpio,unsigned ngpio,void *c) +static void da850_evm_ui_expander_teardown (struct i2c_client *client, +unsigned gpio,unsigned ngpio,void *c) {platform_device_unregister (&da850_evm_ui_keys_device);
@@ -532,8 +532,6 @@ static int da850_evm_ui_expander_teardowgpio_free (gpio +DA850_EVM_UI_EXP_SEL_C );gpio_free (gpio +DA850_EVM_UI_EXP_SEL_B );gpio_free (gpio +DA850_EVM_UI_EXP_SEL_A ); - -return 0 ; }/* assign the baseboard expander's GPIOs after the UI board's */
@@ -700,13 +698,11 @@ io_exp_setup_sw_fail:return ret; } -static int da850_evm_bb_expander_teardown (struct i2c_client *client, -unsigned gpio,unsigned ngpio,void *c) +static void da850_evm_bb_expander_teardown (struct i2c_client *client, +unsigned gpio,unsigned ngpio,void *c) {platform_device_unregister (&da850_evm_bb_leds_device);platform_device_unregister (&da850_evm_bb_keys_device); - -return 0 ; }static struct pca953x_platform_data da850_evm_ui_expander_info = {
drivers/gpio/gpio-pca953x.c +3 -8
@@ -1073,20 +1073,15 @@ static int pca953x_remove(struct i2c_cli {struct pca953x_platform_data *pdata =dev_get_platdata (&client->dev);struct pca953x_chip *chip =i2c_get_clientdata (client); -int ret;if (pdata && pdata->teardown) { - ret = pdata->teardown (client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); -if (ret <0 ) -dev_err (&client->dev,"teardown failed, %d\n" , ret); - }else { - ret =0 ; + pdata->teardown (client, chip->gpio_chip.base, + chip->gpio_chip.ngpio, pdata->context); }regulator_disable (chip->regulator); -return ret; +return 0 ; }#ifdef CONFIG_PM_SLEEP
include/linux/platform_data/pca953x.h +1 -1
@@ -22,7 +22,7 @@ struct pca953x_platform_data {int (*setup)(struct i2c_client *client,unsigned gpio,unsigned ngpio,void *context); -int (*teardown)(struct i2c_client *client, +void (*teardown)(struct i2c_client *client,unsigned gpio,unsigned ngpio,void *context);const char *const *names;
Greg Kroah-Hartman
maintainerPATCH 672/699 usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit 1f0bdc2884b67de337215079bba166df0cdf4ac5 ]
The threaded IRQ handler ccg_irq_handler() calls ucsi_notify_common(), which on a connector-change event calls ucsi_connector_change() and schedules connector work. In ucsi_ccg_remove(), ucsi_destroy() frees uc->ucsi (kfree) before free_irq() is called, so a handler invocation already in flight may access the freed object after ucsi_destroy().
CPU 0 (remove) | CPU 1 (threaded IRQ)
ucsi_destroy(uc->ucsi) | ccg_irq_handler()
kfree(ucsi) // FREE | ucsi_notify_common(uc->ucsi) // USEMove free_irq() before ucsi_destroy() in the remove path. It is kept after ucsi_unregister(): ucsi_unregister() cancels connector work whose handler issues GET_CONNECTOR_STATUS through ucsi_send_command_common(), which waits for a completion that is signalled from the IRQ handler, so the IRQ must stay active until that work has been cancelled.
The probe error path already orders free_irq() before ucsi_destroy().
This bug was found by static analysis.
--- drivers/usb/typec/ucsi/ucsi_ccg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/ucsi/ucsi_ccg.c +1 -1
@@ -1418,8 +1418,8 @@ static int ucsi_ccg_remove(struct i2c_clcancel_work_sync (&uc->work);pm_runtime_disable (uc->dev);ucsi_unregister (uc->ucsi); -ucsi_destroy (uc->ucsi);free_irq (uc->irq, uc); +ucsi_destroy (uc->ucsi);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 673/699 usb: atm: ueagle-atm: wait for pre-firmware load in .disconnect()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mauricio Faria de Oliveira <[email protected]>
[ Upstream commit e2674dfbed8a30d57e2bc872c4bfa6c3eec918bf ]
ueagle-atm uses the asynchronous request_firmware_nowait() in .probe(), but does not wait for its completion, not even in .disconnect(); so, if the device is unplugged meanwhile, its teardown runs concurrently with that.
Even though this inconsistency is worth addressing on its own, it has also triggered several bug reports in syzbot over the years (some auto-closed) where the firmware sysfs fallback mechanism (CONFIG_FW_LOADER_USER_HELPER) creates a firmware subdirectory in the device directory during its removal, which might hit unexpected conditions in kernfs, apparently, depending at which point the add and remove operations raced. (See links.)
The pattern is:
usb ?-?: Direct firmware load for ueagle-atm/eagle?.fw failed with error -2 usb ?-?: Falling back to sysfs fallback for: ueagle-atm/eagle?.fw <ERROR>
Call trace: ... kernfs_create_dir_ns sysfs_create_dir_ns create_dir kobject_add_internal kobject_add_varg kobject_add class_dir_create_and_add get_device_parent device_add fw_load_sysfs_fallback fw_load_from_user_helper firmware_fallback_sysfs _request_firmware request_firmware_work_func ...
(Some variations are observed, after fw_load_sysfs_fallback(), e.g., [1].)
While the kernfs side is being looked at, the ueagle-atm side can be fixed by waiting for the pre-firmware load in the .disconnect() handler.
This change has a similar approach to previous work by Andrey Tsygunka [2] (wait_for_completion() in .disconnect()), but it is relatively different in design/implementation; using the Originally-by tag for credit assignment.
This has been tested with:
- synthetic reproducer to check the error path;
- USB gadget (virtual device) to check the firmware upload path;
- QEMU device emulator to check the device ID re-enumeration path; (The latter two were written by Claude; no other code/text in this commit.)
Links (year first reported):
2025 https://syzbot.org/bug?extid=ce1e5a1b4e086b43e56d
2025 https://syzbot.org/bug?extid=9af8471255ac36e34fd4
2024 https://syzbot.org/bug?extid=306212936b13e520679d
2023 https://syzkaller.appspot.com/bug?extid=457452d30bcdda75ead2
2022 https://syzbot.org/bug?extid=782984d6f1701b526edb
2021 https://syzbot.org/bug?id=f3f221579f4ef7e9691281f3c6f56c05f83e8490
2021 https://syzbot.org/bug?id=84d86f0d71394829df6fc53daf6642c045983881
2021 https://syzbot.org/bug?id=3302dc1c0e2b9c94f2e8edb404eabc9267bc6f90
[1] https://syzkaller.appspot.com/bug?extid=457452d30bcdda75ead2
[2] https://lore.kernel.org/lkml/[email protected]/
--- drivers/usb/atm/ueagle-atm.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-)
drivers/usb/atm/ueagle-atm.c +31 -5
@@ -599,7 +599,9 @@ static int uea_send_modem_cmd(struct usbstatic void uea_upload_pre_firmware (const struct firmware *fw_entry,void *context) { -struct usb_device *usb = context; +struct usb_interface *intf = context; +struct usb_device *usb =interface_to_usbdev (intf); +struct completion *fw_done =usb_get_intfdata (intf);const u8 *pfw;u8 value;u32 crc =0 ;
@@ -670,15 +672,17 @@ err_fw_corrupted: err:release_firmware (fw_entry);uea_leaves (usb); +complete (fw_done); }/* * uea_load_firmware - Load usb firmware for pre-firmware devices. */ -static int uea_load_firmware (struct usb_device *usb,unsigned int ver) +static int uea_load_firmware (struct usb_interface *intf,unsigned int ver) {int ret;char *fw_name =EAGLE_FIRMWARE ; +struct usb_device *usb =interface_to_usbdev (intf);uea_enters (usb);uea_info (usb,"pre-firmware device, uploading firmware\n" );
@@ -702,7 +706,7 @@ static int uea_load_firmware(struct usb_ } ret =request_firmware_nowait (THIS_MODULE ,1 , fw_name, &usb->dev, -GFP_KERNEL , usb, +GFP_KERNEL , intf, uea_upload_pre_firmware);if (ret)uea_err (usb,"firmware %s is not available\n" , fw_name);
@@ -2598,8 +2602,23 @@ static int uea_probe(struct usb_interfacusb_reset_device (usb); -if (UEA_IS_PREFIRM (id)) -return uea_load_firmware (usb,UEA_CHIP_VERSION (id)); +if (UEA_IS_PREFIRM (id)) { +struct completion *fw_done; + +/* Wait for the firmware load to be done, in .disconnect() */ + fw_done =kzalloc (sizeof (*fw_done),GFP_KERNEL ); +if (!fw_done) +return -ENOMEM ; + +init_completion (fw_done); +usb_set_intfdata (intf, fw_done); + + ret =uea_load_firmware (intf,UEA_CHIP_VERSION (id)); +if (ret) +kfree (fw_done); + +return ret; + } ret =usbatm_usb_probe (intf, id, &uea_usbatm_driver);if (ret ==0 ) {
@@ -2630,6 +2649,13 @@ static void uea_disconnect(struct usb_inusbatm_usb_disconnect (intf);mutex_unlock (&uea_mutex);uea_info (usb,"ADSL device removed\n" ); + }else if (usb->config->desc.bNumInterfaces ==1 ) { +struct completion *fw_done =usb_get_intfdata (intf); + +uea_dbg (usb,"pre-firmware device, waiting firmware upload\n" ); +wait_for_completion (fw_done); +uea_dbg (usb,"pre-firmware device, finished waiting\n" ); +kfree (fw_done); }uea_leaves (usb);
Greg Kroah-Hartman
maintainerPATCH 674/699 usb: typec: tcpm: Fix VDM type for Enter Mode commands
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Yan <[email protected]>
[ Upstream commit 9cff680e47632b7723cb19f9c5e63669063c3417 ]
VDO() second parameter is VDM type (bit 15): 1 for SVDM, 0 for UVDM. Using 'vdo ? 2 : 1' corrupts SVID low bit when vdo is non-NULL (2 << 15 = BIT(16)). Enter Mode is always SVDM, hardcode to 1.
--- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/tcpm/tcpm.c +1 -1
@@ -1671,7 +1671,7 @@ static int tcpm_altmode_enter(struct typstruct tcpm_port *port =typec_altmode_get_drvdata (altmode);u32 header; - header =VDO (altmode->svid, vdo ?2 :1 ,CMD_ENTER_MODE ); + header =VDO (altmode->svid,1 ,CMD_ENTER_MODE ); header |=VDO_OPOS (altmode->mode);tcpm_queue_vdm_unlocked (port, header, vdo, vdo ?1 :0 );
Greg Kroah-Hartman
maintainerPATCH 675/699 usb: gadget: f_fs: initialize reset_work at allocation time
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tyler Baker <[email protected]>
[ Upstream commit 3137b243c93982fe3460335e12f9247739766e10 ]
ffs_fs_kill_sb() unconditionally calls cancel_work_sync() on ffs->reset_work when a functionfs instance is unmounted:
ffs_data_reset(ffs); cancel_work_sync(&ffs->reset_work);
However ffs->reset_work is only ever initialized via INIT_WORK() in ffs_func_set_alt() and ffs_func_disable(), and only on the FFS_DEACTIVATED path. That state is reached solely by ffs_data_closed() when the instance is mounted with the "no_disconnect" option, so for the common case (no "no_disconnect", or mounted and unmounted without ever being deactivated) reset_work is never initialized.
ffs_data_new() allocates the ffs_data with kzalloc_obj() and does not initialize reset_work, and ffs_data_reset()/ffs_data_clear() do not touch it either, so reset_work.func is left NULL. cancel_work_sync() on such a work then trips the WARN_ON(!work->func) guard in __flush_work():
WARNING: kernel/workqueue.c:4301 at __flush_work+0x330/0x360, CPU#3: umount Call trace: __flush_work cancel_work_sync ffs_fs_kill_sb [usb_f_fs] deactivate_locked_super deactivate_super cleanup_mnt __cleanup_mnt task_work_run exit_to_user_mode_loop el0_svc
On older kernels cancel_work_sync() on a zero-initialized work struct was a silent no-op, which hid the missing initialization.
Initialize reset_work once in ffs_data_new() so it is always valid for the lifetime of the ffs_data, and drop the now-redundant INIT_WORK() calls from the two deactivation paths.
--- drivers/usb/gadget/function/f_fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/gadget/function/f_fs.c +2 -1
@@ -254,6 +254,7 @@ static int ffs_acquire_dev(const char *dstatic void ffs_release_dev (struct ffs_dev *ffs_dev);static int ffs_ready (struct ffs_data *ffs);static void ffs_closed (struct ffs_data *ffs); +static void ffs_reset_work (struct work_struct *work);/* Misc helper functions ****************************************************/
@@ -1774,6 +1775,7 @@ static struct ffs_data *ffs_data_new(coninit_waitqueue_head (&ffs->ev.waitq);init_waitqueue_head (&ffs->wait);init_completion (&ffs->ep0req_completion); +INIT_WORK (&ffs->reset_work, ffs_reset_work);/* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall =1 ;
@@ -3330,7 +3332,6 @@ static int ffs_func_set_alt(struct usb_fif (ffs->state ==FFS_DEACTIVATED ) { ffs->state =FFS_CLOSING ; -INIT_WORK (&ffs->reset_work, ffs_reset_work);schedule_work (&ffs->reset_work);return -ENODEV ; }
Greg Kroah-Hartman
maintainerPATCH 676/699 crypto: atmel-sha204a - Mark OF related data as maybe unused
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <[email protected]>
[ Upstream commit 75f3d950054389e2556277e42170e37dd97cd872 ]
The driver can be compile tested with !CONFIG_OF making certain data unused:
drivers/crypto/atmel-sha204a.c:129:34: error: ‘atmel_sha204a_dt_ids’ defined but not used [-Werror=unused-const-variable=]
Stable-dep-of: ea5e57cc9718 ("crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A")
--- drivers/crypto/atmel-sha204a.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/crypto/atmel-sha204a.c +4 -2
@@ -137,14 +137,16 @@ static int atmel_sha204a_remove(struct ireturn 0 ; } -static const struct of_device_id atmel_sha204a_dt_ids[] = { +static const struct of_device_id atmel_sha204a_dt_ids[]__maybe_unused = { + { .compatible ="atmel,atsha204" , }, { .compatible ="atmel,atsha204a" , }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, atmel_sha204a_dt_ids);static const struct i2c_device_id atmel_sha204a_id[] = { - {"atsha204a" ,0 }, + {"atsha204" }, + {"atsha204a" }, {/* sentinel */ } };MODULE_DEVICE_TABLE (i2c, atmel_sha204a_id);
Greg Kroah-Hartman
maintainerPATCH 677/699 crypto: atmel - Drop explicit initialization of struct i2c_device_id::driver_data to 0
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit d86ad3911a5d4549297ed810ee450e5772fd665f ]
These drivers don't use the driver_data member of struct i2c_device_id, so don't explicitly initialize this member.
This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own.
Stable-dep-of: ea5e57cc9718 ("crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A")
--- drivers/crypto/atmel-ecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/atmel-ecc.c +1 -1
@@ -387,7 +387,7 @@ MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids#endif static const struct i2c_device_id atmel_ecc_id[] = { - {"atecc508a" ,0 }, + {"atecc508a" }, { } };MODULE_DEVICE_TABLE (i2c, atmel_ecc_id);
Greg Kroah-Hartman
maintainerPATCH 678/699 crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit ea5e57cc97185329dcc5ebdcaae7e1500bf0ad0b ]
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
--- drivers/crypto/atmel-sha204a.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/crypto/atmel-sha204a.c +12 -7
@@ -18,6 +18,12 @@#include <linux/workqueue.h> #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) {
@@ -96,6 +102,7 @@ static int atmel_sha204a_probe(struct i2 const struct i2c_device_id *id) {struct atmel_i2c_client_priv *i2c_priv; +const unsigned short *quality;int ret; ret =atmel_i2c_probe (client, id);
@@ -109,11 +116,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)
@@ -138,14 +143,14 @@ static int atmel_sha204a_remove(struct i }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 */ } };
Greg Kroah-Hartman
maintainerPATCH 679/699 usb: gadget: f_fs: Tie read_buffer lifetime to ffs_epfile
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neill Kapron <[email protected]>
[ Upstream commit 8bdcf96eb135aebacac319667f87db034fb38406 ]
Currently, ffs_epfile_release unconditionally frees the endpoint's read_buffer when a file descriptor is closed. If userspace explicitly opens the endpoint multiple times and closes one, the read_buffer is destroyed. This can lead to silent data loss if other file descriptors are still actively reading from the endpoint.
By tying the lifetime of the read_buffer to the ffs_epfile structure itself (which is destroyed when the functionfs instance is torn down in ffs_epfiles_destroy), we eliminate the brittle dependency on open/release calls while correctly matching the conceptual lifetime of unread data on the hardware endpoint.
--- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_fs.c +1 -1
@@ -1279,7 +1279,6 @@ ffs_epfile_release(struct inode *inode,ENTER (); -__ffs_epfile_read_buffer_free (epfile);ffs_data_closed (epfile->ffs);return 0 ;
@@ -1945,6 +1944,7 @@ static void ffs_epfiles_destroy(struct ffor (; count; --count, ++epfile) {BUG_ON (mutex_is_locked (&epfile->mutex)); +__ffs_epfile_read_buffer_free (epfile);if (epfile->dentry) {d_delete (epfile->dentry);dput (epfile->dentry);
Greg Kroah-Hartman
maintainerPATCH 680/699 btrfs: do not trim a device which is not writeable
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
[ Upstream commit 1b1937eb08f51319bf71575484cde2b8c517aedc ]
[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().
--- fs/btrfs/extent-tree.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
fs/btrfs/extent-tree.c +8 -4
@@ -5762,12 +5762,16 @@ static int btrfs_trim_free_extents(struc *trimmed =0 ; -/* Discard not supported = nothing to do. */ -if (!blk_queue_discard (bdev_get_queue (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 (!blk_queue_discard (bdev_get_queue (device->bdev)))return 0 ;/* No free space = nothing to do. */
Greg Kroah-Hartman
maintainerPATCH 681/699 crypto: qat - fix restarting state leak on allocation failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
[ Upstream commit 7d3ed20f7e46b3e991936fedd7a28f3ff4aec8d2 ]
In adf_dev_aer_schedule_reset(), ADF_STATUS_RESTARTING is set before allocating reset_data. If the allocation fails, the function returns -ENOMEM without queuing reset work, so nothing ever clears the bit. This leaves the device permanently stuck in the restarting state, causing all subsequent reset attempts to be silently skipped.
Fix this by using test_and_set_bit() to atomically claim the RESTARTING state, preventing duplicate reset scheduling races under concurrent fatal error reporting. If the subsequent allocation fails, clear the bit to restore clean state so future reset attempts can proceed.
--- drivers/crypto/qat/qat_common/adf_aer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/crypto/qat/qat_common/adf_aer.c +4 -3
@@ -116,13 +116,14 @@ static int adf_dev_aer_schedule_reset(ststruct adf_reset_dev_data *reset_data;if (!adf_dev_started (accel_dev) || -test_bit (ADF_STATUS_RESTARTING , &accel_dev->status)) +test_and_set_bit (ADF_STATUS_RESTARTING , &accel_dev->status))return 0 ; -set_bit (ADF_STATUS_RESTARTING , &accel_dev->status); reset_data =kzalloc (sizeof (*reset_data),GFP_KERNEL ); -if (!reset_data) +if (!reset_data) { +clear_bit (ADF_STATUS_RESTARTING , &accel_dev->status);return -ENOMEM ; + } reset_data->accel_dev = accel_dev;init_completion (&reset_data->compl); reset_data->mode = mode;
Greg Kroah-Hartman
maintainerPATCH 682/699 crypto: qat - validate RSA CRT component lengths
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Giovanni Cabiddu <[email protected]>
[ Upstream commit b3ac78756588059729b9195fcc9f4b37d54057a5 ]
The generic RSA key parser (rsa_helper.c) bounds each CRT component (p, q, dp, dq, qinv) by the modulus size n_sz, but qat_rsa_setkey_crt() allocates half-size DMA buffers (key_sz / 2) and right-aligns each component with:
memcpy(dst + half_key_sz - len, src, len)
When a CRT component is larger than half_key_sz the subtraction underflows and memcpy writes past the DMA buffer, causing memory corruption.
Add a len > half_key_sz check next to the existing !len check for each of the five CRT components so the driver falls back to the non-CRT path instead of writing out of bounds.
--- drivers/crypto/qat/qat_common/qat_asym_algs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/crypto/qat/qat_common/qat_asym_algs.c +5 -5
@@ -1030,7 +1030,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->p; len = rsa_key->p_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto err; ctx->p =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_p,GFP_KERNEL );if (!ctx->p)
@@ -1041,7 +1041,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->q; len = rsa_key->q_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_p; ctx->q =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_q,GFP_KERNEL );if (!ctx->q)
@@ -1052,7 +1052,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->dp; len = rsa_key->dp_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_q; ctx->dp =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_dp,GFP_KERNEL );
@@ -1064,7 +1064,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->dq; len = rsa_key->dq_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_dp; ctx->dq =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_dq,GFP_KERNEL );
@@ -1076,7 +1076,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->qinv; len = rsa_key->qinv_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_dq; ctx->qinv =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_qinv,GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 683/699 audit: add audit_log_nf_skb helper function
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit f19590b07cb620be1fcd5474c49515e21a05d406 ]
Netfilter code (net/netfilter/nft_log.c and net/netfilter/xt_AUDIT.c) have to be kept in sync. Both source files had duplicated versions of audit_ip4() and audit_ip6() functions, which can result in lack of consistency and/or duplicated work.
This patch adds a helper function in audit.c that can be called by netfilter code commonly, aiming to improve maintainability and consistency.
Stable-dep-of: 65dfde57d1e2 ("audit: fix potential integer overflow in audit_log_n_hex()")
--- include/linux/audit.h | 8 +++++ kernel/audit.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ net/netfilter/nft_log.c | 58 ------------------------------------------ net/netfilter/xt_AUDIT.c | 58 ------------------------------------------ 4 files changed, 74 insertions(+), 114 deletions(-)
include/linux/audit.h +8 -0
@@ -186,6 +186,8 @@ extern void audit_log_lost(const chextern int audit_log_task_context (struct audit_buffer *ab);extern void audit_log_task_info (struct audit_buffer *ab); +extern int audit_log_nf_skb (struct audit_buffer *ab, +const struct sk_buff *skb,u8 nfproto);extern int audit_update_lsm_rules (void );
@@ -251,6 +253,12 @@ static inline int audit_log_task_contextstatic inline void audit_log_task_info (struct audit_buffer *ab) { } +static inline int audit_log_nf_skb (struct audit_buffer *ab, +const struct sk_buff *skb,u8 nfproto) +{ +return 0 ; +} +static inline kuid_t audit_get_loginuid (struct task_struct *tsk) {return INVALID_UID ;
kernel/audit.c +64 -0
76 lines not on this page · raw message
net/netfilter/nft_log.c +1 -57
74 lines not on this page · raw message
net/netfilter/xt_AUDIT.c +1 -57
74 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 684/699 audit: fix potential integer overflow in audit_log_n_hex()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit 65dfde57d1e29ce2b76fc23dd565eccd5c0bc0f0 ]
The function calculates new_len as len << 1 for hex encoding. This has two overflow risks: the shift itself can overflow when len is large, and the result can be truncated when assigned to new_len (declared as int) from the size_t calculation.
Fix by using check_shl_overflow() to catch shift overflow and changing new_len and loop counter i to size_t to prevent truncation.
--- kernel/audit.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/audit.c +9 -2
@@ -61,6 +61,7 @@#include <net/netns/generic.h> #include <net/ip.h> #include <net/ipv6.h> +#include <linux/overflow.h> #include "audit.h"
@@ -2034,7 +2035,8 @@ void audit_log_format(struct audit_buffevoid audit_log_n_hex (struct audit_buffer *ab,const unsigned char *buf,size_t len) { -int i, avail, new_len; +int avail; +size_t i, new_len;unsigned char *ptr;struct sk_buff *skb;
@@ -2044,7 +2046,12 @@ void audit_log_n_hex(struct audit_bufferBUG_ON (!ab->skb); skb = ab->skb; avail =skb_tailroom (skb); - new_len = len<<1 ; + +if (check_shl_overflow (len,1 , &new_len)) { +audit_log_format (ab,"?" ); +return ; + } +if (new_len >= avail) {/* Round the buffer request up to the next multiple */ new_len =AUDIT_BUFSIZ *(((new_len-avail)/AUDIT_BUFSIZ ) +1 );
Greg Kroah-Hartman
maintainerPATCH 685/699 posix-cpu-timers: Use u64 multiplication in update_rlimit_cpu()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit 26aff38fefb1d6cd87e22525f41cc8f1aa61b24f upstream.
update_rlimit_cpu() converts the RLIMIT_CPU value to nanoseconds with
u64 nsecs = rlim_new * NSEC_PER_SEC;
On 32-bit kernels both rlim_new (unsigned long) and NSEC_PER_SEC (1000000000L) are 32-bit, so the multiplication is performed in unsigned long and truncated for rlim_new > 4 seconds before being widened to u64.
The same file already casts to u64 for the matching computation in check_process_timers():
u64 softns = (u64)soft * NSEC_PER_SEC;
As a result, the truncated value is installed into the CPUCLOCK_PROF expiry cache (nextevt), causing the process CPU timer to be programmed to fire prematurely for any RLIMIT_CPU soft limit >= 5 seconds. The actual SIGXCPU/SIGKILL decision in check_process_timers() already casts to u64 and is therefore correct, so limit enforcement is not broken; only the expiry-cache programming is wrong. Apply the same cast here so both paths convert rlim_cur identically.
64-bit kernels are unaffected.
--- kernel/time/posix-cpu-timers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/posix-cpu-timers.c +1 -1
@@ -37,7 +37,7 @@ void posix_cputimers_group_init(struct p*/ void update_rlimit_cpu (struct task_struct *task,unsigned long rlim_new) { -u64 nsecs = rlim_new *NSEC_PER_SEC ; +u64 nsecs = (u64 )rlim_new *NSEC_PER_SEC ;spin_lock_irq (&task->sighand->siglock);set_process_cpu_timer (task,CPUCLOCK_PROF , &nsecs,NULL );
Greg Kroah-Hartman
maintainerPATCH 686/699 KVM: Move kvm_io_bus_get_dev() locking responsibilities to callers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit 3a07249981629ace483ebbef81ef6b34c2d2afec upstream.
kvm_io_bus_get_dev() returns a device that is only matched by the address, and nothing else. This can cause a lifetime issue if the matched device is not the expected type, as by the time the caller can introspect the object, it might be gone (the srcu lock having been dropped).
Given that there is only a single user of this helper, the simplest option is to move the locking responsibility to the caller, which can keep the srcu lock held for as long as it wants.
Note that this aligns with other kvm_io_bus*() helpers, which already require the srcu lock to be held by the callers.
--- arch/arm64/kvm/vgic/vgic-its.c | 15 +++++++++++---- virt/kvm/kvm_main.c | 16 +++++----------- 2 files changed, 16 insertions(+), 15 deletions(-)
arch/arm64/kvm/vgic/vgic-its.c +11 -4
@@ -704,6 +704,8 @@ struct vgic_its *vgic_msi_to_its(structu64 address;struct kvm_io_device *kvm_io_dev;struct vgic_io_device *iodev; +struct vgic_its *its =NULL ; +int srcu_idx;if (!vgic_has_its (kvm))return ERR_PTR (-ENODEV );
@@ -713,18 +715,23 @@ struct vgic_its *vgic_msi_to_its(struct address = (u64 )msi->address_hi <<32 | msi->address_lo; + srcu_idx =srcu_read_lock (&kvm->srcu); + kvm_io_dev =kvm_io_bus_get_dev (kvm,KVM_MMIO_BUS , address);if (!kvm_io_dev) -return ERR_PTR (-EINVAL ); + goto out;if (kvm_io_dev->ops != &kvm_io_gic_ops) -return ERR_PTR (-EINVAL ); + goto out; iodev = container_of(kvm_io_dev, struct vgic_io_device, dev);if (iodev->iodev_type !=IODEV_ITS ) -return ERR_PTR (-EINVAL ); + goto out; -return iodev->its; + its = iodev->its; +out: +srcu_read_unlock (&kvm->srcu, srcu_idx); +return its ?:ERR_PTR (-EINVAL ); }/*
virt/kvm/kvm_main.c +5 -11
@@ -4558,25 +4558,19 @@ struct kvm_io_device *kvm_io_bus_get_dev gpa_t addr) {struct kvm_io_bus *bus; -int dev_idx, srcu_idx; -struct kvm_io_device *iodev =NULL ; +int dev_idx; - srcu_idx =srcu_read_lock (&kvm->srcu); +lockdep_assert_held (&kvm->srcu); bus =srcu_dereference (kvm->buses[bus_idx], &kvm->srcu);if (!bus) - goto out_unlock; +return NULL ; dev_idx =kvm_io_bus_get_first_dev (bus, addr,1 );if (dev_idx <0 ) - goto out_unlock; +return NULL ; - iodev = bus->range[dev_idx].dev; - -out_unlock: -srcu_read_unlock (&kvm->srcu, srcu_idx); - -return iodev; +return bus->range[dev_idx].dev; }EXPORT_SYMBOL_GPL (kvm_io_bus_get_dev);
Greg Kroah-Hartman
maintainerPATCH 687/699 Bluetooth: L2CAP: Fix regressions caused by reusing ident
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
commit 761fb8ec8778f0caf2bba5a41e3cff1ea86974f3 upstream.
This attempt to fix regressions caused by reusing ident which apparently is not handled well on certain stacks causing the stack to not respond to requests, so instead of simple returning the first unallocated id this stores the last used tx_ident and then attempt to use the next until all available ids are exausted and then cycle starting over to 1.
--- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-)
include/net/bluetooth/l2cap.h +1 -0
@@ -691,6 +691,7 @@ struct l2cap_conn {struct sk_buff *rx_skb;__u32 rx_len;struct ida tx_ida; +__u8 tx_ident;struct sk_buff_head pending_rx;struct work_struct pending_rx_work;
net/bluetooth/l2cap_core.c +26 -3
@@ -941,16 +941,39 @@ int l2cap_chan_check_security(struct l2cstatic int l2cap_get_ident (struct l2cap_conn *conn) { +u8 max; +int ident; +/* LE link does not support tools like l2ping so use the full range */ if (conn->hcon->type ==LE_LINK ) -return ida_alloc_range (&conn->tx_ida,1 ,255 ,GFP_ATOMIC ); - + max =255 ;/* Get next available identificator. * 1 - 128 are used by kernel. * 129 - 199 are reserved. * 200 - 254 are used by utilities like l2ping, etc. */ -return ida_alloc_range (&conn->tx_ida,1 ,128 ,GFP_ATOMIC ); +else + max =128 ; + +/* Allocate ident using min as last used + 1 (cyclic) */ + ident =ida_alloc_range (&conn->tx_ida,READ_ONCE (conn->tx_ident) +1 , + max,GFP_ATOMIC ); +/* Force min 1 to start over */ +if (ident <=0 ) { + ident =ida_alloc_range (&conn->tx_ida,1 , max,GFP_ATOMIC ); +if (ident <=0 ) { +/* If all idents are in use, log an error, this is +* extremely unlikely to happen and would indicate a bug +* in the code that idents are not being freed properly. +*/ +BT_ERR ("Unable to allocate ident: %d" , ident); +return 0 ; + } + } + +WRITE_ONCE (conn->tx_ident, ident); + +return ident; } static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
Greg Kroah-Hartman
maintainerPATCH 688/699 iio: imu: inv_mpu6050: fix frequency setting when chip is off
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jean-Baptiste Maneyrol <[email protected]>
commit daec424cc57b33a28f8621eb7ac85f8bd327bd6b upstream.
Track correctly FIFO state and apply ODR change before starting the chip. Without the fix, you cannot change ODR more than 1 time when data buffering is off. This restriction on a single pending ODR change should only apply when the FIFO is on.
--- drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +5 -0
@@ -112,6 +112,7 @@ int inv_mpu6050_prepare_fifo(struct inv_if (enable) {/* reset timestamping */ inv_sensors_timestamp_reset (&st->timestamp); +inv_sensors_timestamp_apply_odr (&st->timestamp,0 ,0 ,0 );/* reset FIFO */ d = st->chip_config.user_ctrl |INV_MPU6050_BIT_FIFO_RST ; ret =regmap_write (st->map, st->reg->user_ctrl, d);
@@ -187,6 +188,10 @@ static int inv_mpu6050_set_enable(structif (result) goto error_power_off; }else { + st->chip_config.gyro_fifo_enable =0 ; + st->chip_config.accl_fifo_enable =0 ; + st->chip_config.temp_fifo_enable =0 ; + st->chip_config.magn_fifo_enable =0 ; result =inv_mpu6050_prepare_fifo (st, false);if (result) goto error_power_off;
Greg Kroah-Hartman
maintainerPATCH 689/699 iio: invensense: fix odr switching to same value
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jean-Baptiste Maneyrol <[email protected]>
commit 95444b9eeb8c5c0330563931d70c61ca3b101548 upstream.
ODR switching happens in 2 steps, update to store the new value and then apply when the ODR change flag is received in the data. When switching to the same ODR value, the ODR change flag is never happening, and frequency switching is blocked waiting for the never coming apply.
Fix the issue by preventing update to happen when switching to same ODR value.
--- drivers/iio/common/inv_sensors/inv_sensors_timestamp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +5 -1
@@ -60,11 +60,15 @@ EXPORT_SYMBOL_NS_GPL(inv_sensors_timestaint inv_sensors_timestamp_update_odr (struct inv_sensors_timestamp *ts,uint32_t period,bool fifo) { +uint32_t mult; +/* when FIFO is on, prevent odr change if one is already pending */ if (fifo && ts->new_mult !=0 )return -EAGAIN ; - ts->new_mult = period / ts->chip.clock_period; + mult = period / ts->chip.clock_period; +if (mult != ts->mult) + ts->new_mult = mult;return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 690/699 iio: imu: inv_icm42600: fix timestamp clock period by using lower value
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jean-Baptiste Maneyrol <[email protected]>
commit 8b0b864c11a2e2ada470f9d5010e1c2bf1eceef2 upstream.
Clock period value is used for computing periods of sampling. There is no need for it to be higher than the maximum odr, otherwise we are losing precision in the computation for nothing.
Switch clock period value to maximum odr period (8kHz).
--- drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c | 4 ++-- drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +2 -2
@@ -725,10 +725,10 @@ struct iio_dev *inv_icm42600_accel_init(return ERR_PTR (-ENOMEM );/* -* clock period is 32kHz (31250ns) +* clock period is 8kHz (125000ns) * jitter is +/- 2% (20 per mille) */ - ts_chip.clock_period =31250 ; + ts_chip.clock_period =125000 ; ts_chip.jitter =20 ; ts_chip.init_period =inv_icm42600_odr_to_period (st->conf.accel.odr); ts =iio_priv (indio_dev);
drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +2 -2
@@ -736,10 +736,10 @@ struct iio_dev *inv_icm42600_gyro_init(sreturn ERR_PTR (-ENOMEM );/* -* clock period is 32kHz (31250ns) +* clock period is 8kHz (125000ns) * jitter is +/- 2% (20 per mille) */ - ts_chip.clock_period =31250 ; + ts_chip.clock_period =125000 ; ts_chip.jitter =20 ; ts_chip.init_period =inv_icm42600_odr_to_period (st->conf.accel.odr); ts =iio_priv (indio_dev);
Greg Kroah-Hartman
maintainerPATCH 691/699 mld: change lockdep annotation for ip6_sf_socklist and ipv6_mc_socklist
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
commit 4b4b84468aa27d0a18be8cb727f246aa35a3406d upstream.
struct ip6_sf_socklist and ipv6_mc_socklist are per-socket MLD data. These data are protected by rtnl lock, socket lock, and RCU. So, when these are used, it verifies whether rtnl lock is acquired or not.
ip6_mc_msfget() is called by do_ipv6_getsockopt().
But caller doesn't acquire rtnl lock.
So, when these data are used in the ip6_mc_msfget() lockdep warns about it. But accessing these is actually safe because socket lock was acquired by do_ipv6_getsockopt().
So, it changes lockdep annotation from rtnl lock to socket lock. (rtnl_dereference -> sock_dereference)
Locking graph for mld data is like below:
When writing mld data:do_ipv6_setsockopt()
rtnl_lock
lock_sock
(mld functions)
idev->mc_lock(if per-interface mld data is modified)When reading mld data:do_ipv6_getsockopt()
lock_sock
ip6_mc_msfget()Splat looks like:
=============================
WARNING: suspicious RCU usage
5.12.0-rc4+ #503 Not tainted
-----------------------------net/ipv6/mcast.c:610 suspicious rcu_dereference_protected() usage!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
1 lock held by mcast-listener-/923:
#0: ffff888007958a70 (sk_lock-AF_INET6){+.+.}-{0:0}, at:
ipv6_get_msfilter+0xaf/0x190 stack backtrace: CPU: 1 PID: 923 Comm: mcast-listener- Not tainted 5.12.0-rc4+ #503 Call Trace: dump_stack+0xa4/0xe5 ip6_mc_msfget+0x553/0x6c0 ? ipv6_sock_mc_join_ssm+0x10/0x10 ? lockdep_hardirqs_on_prepare+0x3e0/0x3e0 ? mark_held_locks+0xb7/0x120 ? lockdep_hardirqs_on_prepare+0x27c/0x3e0 ? __local_bh_enable_ip+0xa5/0xf0 ? lock_sock_nested+0x82/0xf0 ipv6_get_msfilter+0xc3/0x190 ? compat_ipv6_get_msfilter+0x300/0x300 ? lock_downgrade+0x690/0x690 do_ipv6_getsockopt.isra.6.constprop.13+0x1809/0x29e0 ? do_ipv6_mcast_group_source+0x150/0x150 ? register_lock_class+0x1750/0x1750 ? kvm_sched_clock_read+0x14/0x30 ? sched_clock+0x5/0x10 ? sched_clock_cpu+0x18/0x170 ? find_held_lock+0x3a/0x1c0 ? lock_downgrade+0x690/0x690 ? ipv6_getsockopt+0xdb/0x1b0 ipv6_getsockopt+0xdb/0x1b0
[ ... ]
--- net/ipv6/mcast.c | 48 +++++++++++++++++++++++------------------------- net/tipc/udp_media.c | 2 ++ 2 files changed, 25 insertions(+), 25 deletions(-)
net/ipv6/mcast.c +23 -25
@@ -114,10 +114,13 @@ int sysctl_mld_qrv __read_mostly = MLD_Q#define mc_dereference (e, idev) \ rcu_dereference_protected(e, lockdep_is_held(&(idev)->mc_lock)) -#define for_each_pmc_rtnl (np, pmc) \ - for (pmc = rtnl_dereference((np)->ipv6_mc_list); \ +#define sock_dereference (e, sk) \ + rcu_dereference_protected(e, lockdep_sock_is_held(sk)) + +#define for_each_pmc_socklock (np, sk, pmc) \ + for (pmc = sock_dereference((np)->ipv6_mc_list, sk); \ pmc; \ - pmc = rtnl_dereference(pmc->next)) + pmc = sock_dereference(pmc->next, sk))#define for_each_pmc_rcu (np, pmc) \ for (pmc = rcu_dereference((np)->ipv6_mc_list); \
@@ -183,7 +186,7 @@ static int __ipv6_sock_mc_join(struct soif (!ipv6_addr_is_multicast (addr))return -EINVAL ; -for_each_pmc_rtnl (np, mc_lst) { +for_each_pmc_socklock (np, sk, mc_lst) {if ((ifindex ==0 || mc_lst->ifindex == ifindex) &&ipv6_addr_equal (&mc_lst->addr, addr))return -EADDRINUSE ;
@@ -261,7 +264,7 @@ int ipv6_sock_mc_drop(struct sock *sk, ireturn -EINVAL ;for (lnk = &np->ipv6_mc_list; - (mc_lst =rtnl_dereference (*lnk)) !=NULL ; + (mc_lst =sock_dereference (*lnk, sk)) !=NULL ; lnk = &mc_lst->next) {if ((ifindex ==0 || mc_lst->ifindex == ifindex) &&ipv6_addr_equal (&mc_lst->addr, addr)) {
@@ -326,7 +329,7 @@ void __ipv6_sock_mc_close(struct sock *sASSERT_RTNL (); -while ((mc_lst =rtnl_dereference (np->ipv6_mc_list)) !=NULL ) { +while ((mc_lst =sock_dereference (np->ipv6_mc_list, sk)) !=NULL ) {struct net_device *dev; np->ipv6_mc_list = mc_lst->next;
@@ -353,8 +356,11 @@ void ipv6_sock_mc_close(struct sock *sk)if (!rcu_access_pointer (np->ipv6_mc_list))return ; +rtnl_lock (); +lock_sock (sk);__ipv6_sock_mc_close (sk); +release_sock (sk);rtnl_unlock (); }
@@ -384,7 +390,7 @@ int ip6_mc_source(int add, int omode, st err = -EADDRNOTAVAIL ;mutex_lock (&idev->mc_lock); -for_each_pmc_rtnl (inet6, pmc) { +for_each_pmc_socklock (inet6, sk, pmc) {if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)continue ;if (ipv6_addr_equal (&pmc->addr, group))
@@ -407,7 +413,7 @@ int ip6_mc_source(int add, int omode, st pmc->sfmode = omode; } - psl =rtnl_dereference (pmc->sflist); + psl =sock_dereference (pmc->sflist, sk);if (!add) {if (!psl) goto done;/* err = -EADDRNOTAVAIL */
@@ -514,7 +520,7 @@ int ip6_mc_msfilter(struct sock *sk, str goto done; } -for_each_pmc_rtnl (inet6, pmc) { +for_each_pmc_socklock (inet6, sk, pmc) {if (pmc->ifindex != gsf->gf_interface)continue ;if (ipv6_addr_equal (&pmc->addr, group))
@@ -555,7 +561,7 @@ int ip6_mc_msfilter(struct sock *sk, str }mutex_lock (&idev->mc_lock); - psl =rtnl_dereference (pmc->sflist); + psl =sock_dereference (pmc->sflist, sk);if (psl) {ip6_mc_del_src (idev, group, pmc->sfmode, psl->sl_count, psl->sl_addr,0 );
@@ -577,40 +583,32 @@ done:int ip6_mc_msfget (struct sock *sk,struct group_filter *gsf,struct sockaddr_storage *p) { -int err, i, count, copycount; +struct ipv6_pinfo *inet6 =inet6_sk (sk);const struct in6_addr *group;struct ipv6_mc_socklist *pmc; -struct inet6_dev *idev; -struct ipv6_pinfo *inet6 =inet6_sk (sk);struct ip6_sf_socklist *psl; -struct net *net =sock_net (sk); +int i, count, copycount; group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;if (!ipv6_addr_is_multicast (group))return -EINVAL ; - idev =ip6_mc_find_dev_rtnl (net, group, gsf->gf_interface); -if (!idev) -return -ENODEV ; - - err = -EADDRNOTAVAIL ;/* changes to the ipv6_mc_list require the socket lock and -* rtnl lock. We have the socket lock and rcu read lock, -* so reading the list is safe. +* rtnl lock. We have the socket lock, so reading the list is safe. */ -for_each_pmc_rtnl (inet6, pmc) { +for_each_pmc_socklock (inet6, sk, pmc) {if (pmc->ifindex != gsf->gf_interface)continue ;if (ipv6_addr_equal (group, &pmc->addr))break ; }if (!pmc)/* must have a prior join */ -return err; +return -EADDRNOTAVAIL ; gsf->gf_fmode = pmc->sfmode; - psl =rtnl_dereference (pmc->sflist); + psl =sock_dereference (pmc->sflist, sk); count = psl ? psl->sl_count :0 ; copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
@@ -2620,7 +2618,7 @@ static int ip6_mc_leave_src(struct sockstruct ip6_sf_socklist *psl;int err; - psl =rtnl_dereference (iml->sflist); + psl =sock_dereference (iml->sflist, sk);if (idev)mutex_lock (&idev->mc_lock);
net/tipc/udp_media.c +2 -0
@@ -411,8 +411,10 @@ static int enable_mcast(struct udp_beare err =ip_mc_join_group (sk, &mreqn);#if IS_ENABLED (CONFIG_IPV6 ) } else { +lock_sock (sk); err = ipv6_stub->ipv6_sock_mc_join (sk, ub->ifindex, &remote->ipv6); +release_sock (sk);#endif }return err;
Greg Kroah-Hartman
maintainerPATCH 692/699 ipv6: mcast: Delay put pmc->idev in mld_del_delrec()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yue Haibing <[email protected]>
commit ae3264a25a4635531264728859dbe9c659fad554 upstream.
pmc->idev is still used in ip6_mc_clear_src(), so as mld_clear_delrec() does, the reference should be put after ip6_mc_clear_src() return.
--- net/ipv6/mcast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/mcast.c +1 -1
@@ -806,8 +806,8 @@ static void mld_del_delrec(struct inet6_ }else { im->mca_crcount = idev->mc_qrv; } -in6_dev_put (pmc->idev);ip6_mc_clear_src (pmc); +in6_dev_put (pmc->idev);kfree_rcu (pmc, rcu); } }
Greg Kroah-Hartman
maintainerPATCH 693/699 net: ethernet: rmnet: Always subtract MAP header
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kristian Evensen <[email protected]>
commit 8b8701d0b4925807a6d4dc4699cb80a1e16218ad upstream.
Commit e1d9a90a9bfd ("net: ethernet: rmnet: Support for ingress MAPv5 checksum offload") broke ingress handling for devices where RMNET_FLAGS_INGRESS_MAP_CKSUMV5 or RMNET_FLAGS_INGRESS_MAP_CKSUMV4 are not set. Unless either of these flags are set, the MAP header is not removed. This commit restores the original logic by ensuring that the MAP header is removed for all MAP packets.
--- drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +3 -2
@@ -88,11 +88,12 @@ __rmnet_map_ingress_handler(struct sk_bu goto free_skb;skb_pull (skb,sizeof (*map_header));rmnet_set_skb_proto (skb); - }else if (port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV4 ) { + }else {/* Subtract MAP header */ skb_pull (skb,sizeof (*map_header));rmnet_set_skb_proto (skb); -if (!rmnet_map_checksum_downlink_packet (skb, len + pad)) +if (port->data_format &RMNET_FLAGS_INGRESS_MAP_CKSUMV4 && + !rmnet_map_checksum_downlink_packet (skb, len + pad)) skb->ip_summed =CHECKSUM_UNNECESSARY ; }
Greg Kroah-Hartman
maintainerPATCH 694/699 ipv6: mcast: use rcu-safe version of ipv6_get_lladdr()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ignat Korchagin <[email protected]>
commit 26394fc118d6115390bd5b3a0fb17096271da227 upstream.
Some time ago 8965779d2c0e ("ipv6,mcast: always hold idev->lock before mca_lock") switched ipv6_get_lladdr() to __ipv6_get_lladdr(), which is rcu-unsafe version. That was OK, because idev->lock was held for these codepaths.
In 88e2ca308094 ("mld: convert ifmcaddr6 to RCU") these external locks were removed, so we probably need to restore the original rcu-safe call.
Otherwise, we occasionally get a machine crashed/stalled with the following in dmesg:
[ 3405.966610][T230589] general protection fault, probably for non-canonical address 0xdead00000000008c: 0000 [#1] SMP NOPTI [ 3405.982083][T230589] CPU: 44 PID: 230589 Comm: kworker/44:3 Tainted: G O 5.15.19-cloudflare-2022.2.1 #1 [ 3405.998061][T230589] Hardware name: SUPA-COOL-SERV [ 3406.009552][T230589] Workqueue: mld mld_ifc_work [ 3406.017224][T230589] RIP: 0010:__ipv6_get_lladdr+0x34/0x60 [ 3406.025780][T230589] Code: 57 10 48 83 c7 08 48 89 e5 48 39 d7 74 3e 48 8d 82 38 ff ff ff eb 13 48 8b 90 d0 00 00 00 48 8d 82 38 ff ff ff 48 39 d7 74 22 <66> 83 78 32 20 77 1b 75 e4 89 ca 23 50 2c 75 dd 48 8b 50 08 48 8b [ 3406.055748][T230589] RSP: 0018:ffff94e4b3fc3d10 EFLAGS: 00010202 [ 3406.065617][T230589] RAX: dead00000000005a RBX: ffff94e4b3fc3d30 RCX: 0000000000000040 [ 3406.077477][T230589] RDX: dead000000000122 RSI: ffff94e4b3fc3d30 RDI: ffff8c3a31431008 [ 3406.089389][T230589] RBP: ffff94e4b3fc3d10 R08: 0000000000000000 R09: 0000000000000000 [ 3406.101445][T230589] R10: ffff8c3a31430000 R11: 000000000000000b R12: ffff8c2c37887100 [ 3406.113553][T230589] R13: ffff8c3a39537000 R14: 00000000000005dc R15: ffff8c3a31431000 [ 3406.125730][T230589] FS: 0000000000000000(0000) GS:ffff8c3b9fc80000(0000) knlGS:0000000000000000 [ 3406.138992][T230589] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3406.149895][T230589] CR2: 00007f0dfea1db60 CR3: 000000387b5f2000 CR4: 0000000000350ee0 [ 3406.162421][T230589] Call Trace: [ 3406.170235][T230589] <TASK> [ 3406.177736][T230589] mld_newpack+0xfe/0x1a0 [ 3406.186686][T230589] add_grhead+0x87/0xa0 [ 3406.195498][T230589] add_grec+0x485/0x4e0 [ 3406.204310][T230589] ? newidle_balance+0x126/0x3f0 [ 3406.214024][T230589] mld_ifc_work+0x15d/0x450 [ 3406.223279][T230589] process_one_work+0x1e6/0x380 [ 3406.232982][T230589] worker_thread+0x50/0x3a0 [ 3406.242371][T230589] ? rescuer_thread+0x360/0x360 [ 3406.252175][T230589] kthread+0x127/0x150 [ 3406.261197][T230589] ? set_kthread_struct+0x40/0x40 [ 3406.271287][T230589] ret_from_fork+0x22/0x30 [ 3406.280812][T230589] </TASK> [ 3406.288937][T230589] Modules linked in: ... [last unloaded: kheaders] [ 3406.476714][T230589] ---[ end trace 3525a7655f2f3b9e ]---
--- include/net/addrconf.h | 2 -- net/ipv6/addrconf.c | 4 ++-- net/ipv6/mcast.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-)
include/net/addrconf.h +0 -2
@@ -117,8 +117,6 @@ struct inet6_ifaddr *ipv6_get_ifaddr(strint ipv6_dev_get_saddr (struct net *net,const struct net_device *dev,const struct in6_addr *daddr,unsigned int srcprefs,struct in6_addr *saddr); -int __ipv6_get_lladdr (struct inet6_dev *idev,struct in6_addr *addr, -u32 banned_flags);int ipv6_get_lladdr (struct net_device *dev,struct in6_addr *addr,u32 banned_flags); bool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
net/ipv6/addrconf.c +2 -2
@@ -1851,8 +1851,8 @@ out: }EXPORT_SYMBOL (ipv6_dev_get_saddr); -int __ipv6_get_lladdr (struct inet6_dev *idev,struct in6_addr *addr, -u32 banned_flags) +static int __ipv6_get_lladdr (struct inet6_dev *idev,struct in6_addr *addr, +u32 banned_flags) {struct inet6_ifaddr *ifp;int err = -EADDRNOTAVAIL ;
net/ipv6/mcast.c +1 -1
@@ -1776,7 +1776,7 @@ static struct sk_buff *mld_newpack(strucskb_reserve (skb, hlen);skb_tailroom_reserve (skb, mtu, tlen); -if (__ipv6_get_lladdr (idev, &addr_buf,IFA_F_TENTATIVE )) { +if (ipv6_get_lladdr (dev, &addr_buf,IFA_F_TENTATIVE )) {/* <draft-ietf-magma-mld-source-05.txt>: * use unspecified address as the source address * when a valid link-local address is not available.
Greg Kroah-Hartman
maintainerPATCH 695/699 ipv6: fix lockdep splat in in6_dump_addrs()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 4e43e64d0f1332fcc503babad4dc31aead7131ca upstream.
As reported by syzbot, we should not use rcu_dereference() when rcu_read_lock() is not held.
WARNING: suspicious RCU usage
5.19.0-rc2-syzkaller #0 Not tainted
net/ipv6/addrconf.c:5175 suspicious rcu_dereference_check() usage!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
1 lock held by syz-executor326/3617:
#0: ffffffff8d5848e8 (rtnl_mutex){+.+.}-{3:3}, at: netlink_dump+0xae/0xc20 net/netlink/af_netlink.c:2223
stack backtrace: CPU: 0 PID: 3617 Comm: syz-executor326 Not tainted 5.19.0-rc2-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 in6_dump_addrs+0x12d1/0x1790 net/ipv6/addrconf.c:5175 inet6_dump_addr+0x9c1/0xb50 net/ipv6/addrconf.c:5300 netlink_dump+0x541/0xc20 net/netlink/af_netlink.c:2275 __netlink_dump_start+0x647/0x900 net/netlink/af_netlink.c:2380 netlink_dump_start include/linux/netlink.h:245 [inline] rtnetlink_rcv_msg+0x73e/0xc90 net/core/rtnetlink.c:6046 netlink_rcv_skb+0x153/0x420 net/netlink/af_netlink.c:2501 netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline] netlink_unicast+0x543/0x7f0 net/netlink/af_netlink.c:1345 netlink_sendmsg+0x917/0xe10 net/netlink/af_netlink.c:1921 sock_sendmsg_nosec net/socket.c:714 [inline] sock_sendmsg+0xcf/0x120 net/socket.c:734 ____sys_sendmsg+0x6eb/0x810 net/socket.c:2492 ___sys_sendmsg+0xf3/0x170 net/socket.c:2546 __sys_sendmsg net/socket.c:2575 [inline] __do_sys_sendmsg net/socket.c:2584 [inline] __se_sys_sendmsg net/socket.c:2582 [inline] __x64_sys_sendmsg+0x132/0x220 net/socket.c:2582 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x46/0xb0
--- net/ipv6/addrconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/addrconf.c +2 -2
@@ -5178,9 +5178,9 @@ next: fillargs->event =RTM_GETMULTICAST ;/* multicast address */ -for (ifmca =rcu_dereference (idev->mc_list); +for (ifmca =rtnl_dereference (idev->mc_list); ifmca; - ifmca =rcu_dereference (ifmca->next), ip_idx++) { + ifmca =rtnl_dereference (ifmca->next), ip_idx++) {if (ip_idx < s_ip_idx)continue ; err =inet6_fill_ifmcaddr (skb, ifmca, fillargs);
Greg Kroah-Hartman
maintainerPATCH 696/699 net: mld: fix reference count leak in mld_{query | report}_work()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
commit 3e7d18b9dca388940a19cae30bfc1f76dccd8c28 upstream.
mld_{query | report}_work() processes queued events.
If there are too many events in the queue, it re-queue a work. And then, it returns without in6_dev_put().
But if queuing is failed, it should call in6_dev_put(), but it doesn't. So, a reference count leak would occur.
THREAD0 THREAD1mld_report_work()
spin_lock_bh() if (!mod_delayed_work()) in6_dev_hold(); spin_unlock_bh() spin_lock_bh() schedule_delayed_work() spin_unlock_bh()
Script to reproduce(by Hangbin Liu):
ip netns add ns1
ip netns add ns2
ip netns exec ns1 sysctl -w net.ipv6.conf.all.force_mld_version=1 ip netns exec ns2 sysctl -w net.ipv6.conf.all.force_mld_version=1
ip -n ns1 link add veth0 type veth peer name veth0 netns ns2 ip -n ns1 link set veth0 up
ip -n ns2 link set veth0 up
for i in `seq 50`; do
for j in `seq 100`; do
ip -n ns1 addr add 2021:${i}::${j}/64 dev veth0
ip -n ns2 addr add 2022:${i}::${j}/64 dev veth0
done
done
modprobe -r veth
ip -a netns delsplat looks like:
unregister_netdevice: waiting for veth0 to become free. Usage count = 2 leaked reference.
ipv6_add_dev+0x324/0xec0 addrconf_notify+0x481/0xd10 raw_notifier_call_chain+0xe3/0x120 call_netdevice_notifiers+0x106/0x160 register_netdevice+0x114c/0x16b0 veth_newlink+0x48b/0xa50 [veth] rtnl_newlink+0x11a2/0x1a40 rtnetlink_rcv_msg+0x63f/0xc00 netlink_rcv_skb+0x1df/0x3e0 netlink_unicast+0x5de/0x850 netlink_sendmsg+0x6c9/0xa90 ____sys_sendmsg+0x76a/0x780 __sys_sendmsg+0x27c/0x340 do_syscall_64+0x43/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd
--- net/ipv6/mcast.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
net/ipv6/mcast.c +8 -6
@@ -1545,7 +1545,6 @@ static void mld_query_work(struct work_sif (++cnt >=MLD_MAX_QUEUE ) { rework = true; -schedule_delayed_work (&idev->mc_query_work,0 );break ; } }
@@ -1556,8 +1555,10 @@ static void mld_query_work(struct work_s__mld_query_work (skb);mutex_unlock (&idev->mc_lock); -if (!rework) -in6_dev_put (idev); +if (rework &&queue_delayed_work (mld_wq, &idev->mc_query_work,0 )) +return ; + +in6_dev_put (idev); }/* called with rcu_read_lock() */
@@ -1652,7 +1653,6 @@ static void mld_report_work(struct work_if (++cnt >=MLD_MAX_QUEUE ) { rework = true; -schedule_delayed_work (&idev->mc_report_work,0 );break ; } }
@@ -1663,8 +1663,10 @@ static void mld_report_work(struct work___mld_report_work (skb);mutex_unlock (&idev->mc_lock); -if (!rework) -in6_dev_put (idev); +if (rework &&queue_delayed_work (mld_wq, &idev->mc_report_work,0 )) +return ; + +in6_dev_put (idev); } static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
Greg Kroah-Hartman
maintainerPATCH 697/699 ipv6: mcast: fix data-race in ipv6_mc_down / mld_ifc_work
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikita Zhandarovich <[email protected]>
commit 2e7ef287f07c74985f1bf2858bedc62bd9ebf155 upstream.
idev->mc_ifc_count can be written over without proper locking.
Originally found by syzbot [1], fix this issue by encapsulating calls to mld_ifc_stop_work() (and mld_gq_stop_work() for good measure) with mutex_lock() and mutex_unlock() accordingly as these functions should only be called with mc_lock per their declarations.
[1]
BUG: KCSAN: data-race in ipv6_mc_down / mld_ifc_work
write to 0xffff88813a80c832 of 1 bytes by task 3771 on cpu 0:
mld_ifc_stop_work net/ipv6/mcast.c:1080 [inline] ipv6_mc_down+0x10a/0x280 net/ipv6/mcast.c:2725 addrconf_ifdown+0xe32/0xf10 net/ipv6/addrconf.c:3949 addrconf_notify+0x310/0x980 notifier_call_chain kernel/notifier.c:93 [inline] raw_notifier_call_chain+0x6b/0x1c0 kernel/notifier.c:461 __dev_notify_flags+0x205/0x3d0 dev_change_flags+0xab/0xd0 net/core/dev.c:8685 do_setlink+0x9f6/0x2430 net/core/rtnetlink.c:2916 rtnl_group_changelink net/core/rtnetlink.c:3458 [inline] __rtnl_newlink net/core/rtnetlink.c:3717 [inline] rtnl_newlink+0xbb3/0x1670 net/core/rtnetlink.c:3754 rtnetlink_rcv_msg+0x807/0x8c0 net/core/rtnetlink.c:6558 netlink_rcv_skb+0x126/0x220 net/netlink/af_netlink.c:2545 rtnetlink_rcv+0x1c/0x20 net/core/rtnetlink.c:6576 netlink_unicast_kernel net/netlink/af_netlink.c:1342 [inline] netlink_unicast+0x589/0x650 net/netlink/af_netlink.c:1368 netlink_sendmsg+0x66e/0x770 net/netlink/af_netlink.c:1910 ...
write to 0xffff88813a80c832 of 1 bytes by task 22 on cpu 1:
mld_ifc_work+0x54c/0x7b0 net/ipv6/mcast.c:2653 process_one_work kernel/workqueue.c:2627 [inline] process_scheduled_works+0x5b8/0xa30 kernel/workqueue.c:2700 worker_thread+0x525/0x730 kernel/workqueue.c:2781 ...
--- net/ipv6/mcast.c | 4 ++++ 1 file changed, 4 insertions(+)
net/ipv6/mcast.c +4 -0
@@ -2754,8 +2754,12 @@ void ipv6_mc_down(struct inet6_dev *idevsynchronize_net ();mld_query_stop_work (idev);mld_report_stop_work (idev); + +mutex_lock (&idev->mc_lock);mld_ifc_stop_work (idev);mld_gq_stop_work (idev); +mutex_unlock (&idev->mc_lock); +mld_dad_stop_work (idev); }
Greg Kroah-Hartman
maintainerPATCH 698/699 ipv6: mcast: remove one synchronize_net() barrier in ipv6_mc_down()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 17ef8efc00b34918b966388b2af0993811895a8c upstream.
As discussed in the past (commit 2d3916f31891 ("ipv6: fix skb drops in igmp6_event_query() and igmp6_event_report()")) I think the synchronize_net() call in ipv6_mc_down() is not needed.
Under load, synchronize_net() can last between 200 usec and 5 ms.
KASAN seems to agree as well.
--- net/ipv6/mcast.c | 1 - 1 file changed, 1 deletion(-)
net/ipv6/mcast.c +0 -1
@@ -2751,7 +2751,6 @@ void ipv6_mc_down(struct inet6_dev *idev/* Should stop work after group drop. or we will * start work again in mld_ifc_event() */ -synchronize_net ();mld_query_stop_work (idev);mld_report_stop_work (idev);
Greg Kroah-Hartman
maintainerPATCH 699/699 mld: fix suspicious RCU usage in __ipv6_dev_mc_dec()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Taehee Yoo <[email protected]>
commit aa8caa767e319bad34a82bfce7da1ed2b9c0ed6f upstream.
__ipv6_dev_mc_dec() internally uses sleepable functions so that caller must not acquire atomic locks. But caller, which is addrconf_verify_rtnl() acquires rcu_read_lock_bh().
So this warning occurs in the __ipv6_dev_mc_dec().
Test commands:
ip netns add A
ip link add veth0 type veth peer name veth1
ip link set veth1 netns A
ip link set veth0 up
ip netns exec A ip link set veth1 up
ip a a 2001:db8::1/64 dev veth0 valid_lft 2 preferred_lft 1
Splat looks like:
============================
WARNING: suspicious RCU usage
5.12.0-rc6+ #515 Not tainted
-----------------------------kernel/sched/core.c:8294 Illegal context switch in RCU-bh read-side critical section!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
4 locks held by kworker/4:0/1997:
#0: ffff88810bd72d48 ((wq_completion)ipv6_addrconf){+.+.}-{0:0}, at:
process_one_work+0x761/0x1440
#1: ffff888105c8fe00 ((addr_chk_work).work){+.+.}-{0:0}, at:
process_one_work+0x795/0x1440
#2: ffffffffb9279fb0 (rtnl_mutex){+.+.}-{3:3}, at:
addrconf_verify_work+0xa/0x20
#3: ffffffffb8e30860 (rcu_read_lock_bh){....}-{1:2}, at:
addrconf_verify_rtnl+0x23/0xc60
stack backtrace:
CPU: 4 PID: 1997 Comm: kworker/4:0 Not tainted 5.12.0-rc6+ #515
Workqueue: ipv6_addrconf addrconf_verify_work
Call Trace:
dump_stack+0xa4/0xe5
___might_sleep+0x27d/0x2b0
__mutex_lock+0xc8/0x13f0
? lock_downgrade+0x690/0x690
? __ipv6_dev_mc_dec+0x49/0x2a0
? mark_held_locks+0xb7/0x120
? mutex_lock_io_nested+0x1270/0x1270
? lockdep_hardirqs_on_prepare+0x12c/0x3e0
? _raw_spin_unlock_irqrestore+0x47/0x50
? trace_hardirqs_on+0x41/0x120
? __wake_up_common_lock+0xc9/0x100
? __wake_up_common+0x620/0x620
? memset+0x1f/0x40
? netlink_broadcast_filtered+0x2c4/0xa70
? __ipv6_dev_mc_dec+0x49/0x2a0
__ipv6_dev_mc_dec+0x49/0x2a0
? netlink_broadcast_filtered+0x2f6/0xa70
addrconf_leave_solict.part.64+0xad/0xf0
? addrconf_join_solict.part.63+0xf0/0xf0
? nlmsg_notify+0x63/0x1b0
__ipv6_ifa_notify+0x22c/0x9c0
? inet6_fill_ifaddr+0xbe0/0xbe0
? lockdep_hardirqs_on_prepare+0x12c/0x3e0
? __local_bh_enable_ip+0xa5/0xf0
? ipv6_del_addr+0x347/0x870
ipv6_del_addr+0x3b1/0x870
? addrconf_ifdown+0xfe0/0xfe0
? rcu_read_lock_any_held.part.27+0x20/0x20
addrconf_verify_rtnl+0x8a9/0xc60
addrconf_verify_work+0xf/0x20
process_one_work+0x84c/0x1440In order to avoid this problem, it uses rcu_read_unlock_bh() for a short time. RCU is used for avoiding freeing ifp(struct *inet6_ifaddr) while ifp is being used. But this will not be released even if rcu_read_unlock_bh() is used. Because before rcu_read_unlock_bh(), it uses in6_ifa_hold(ifp). So this is safe.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -4550,7 +4550,9 @@ restart: age >= ifp->valid_lft) {spin_unlock (&ifp->lock);in6_ifa_hold (ifp); +rcu_read_unlock_bh ();ipv6_del_addr (ifp); +rcu_read_lock_bh (); goto restart; } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {spin_unlock (&ifp->lock);
Greg Kroah-Hartman wrote on Tue, Jul 21, 2026 at 05:15:59PM +0200:
Quoted 5 lines
This is the start of the stable review cycle for the 5.10.261 release. There are 699 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 8 lines
Responses should be made by Thu, 23 Jul 2026 15:23:00 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.10.261-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-5.10.y
and the diffstat can be found below.
Tested 9067606e05eb ("Linux 5.10.261-rc1") on:
- arm i.MX6ULL (Armadillo 640)
- arm64 i.MX8MP (Armadillo G4)
- arm64 i.MX8ULP (Armadillo IoT A9E)
No obvious regression in dmesg or basic tests:
Signature · 1 line
Dominique Martinet