6.18.42-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 109/675 Bluetooth: hci_sync: extend conn_hash lookup critical sections
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit d5efd6e4b8b0634af6843178fe1a7dd2b2178a3d ]
Using RCU-protected pointers outside the critical sections without refcount is incorrect and may result to UAF.
Extend critical section to cover both hci_conn_hash lookup and use of the returned conn.
Add surrounding rcu_read_lock() also when return value is not used, in preparation for RCU lockdep requirement to hci_lookup_le_connect().
This avoids concurrent deletion of the conn before we are done dereferencing it.
Also, make sure to hold hdev->lock when accessing hdev->accept_list.
--- net/bluetooth/hci_sync.c | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +39 -3
@@ -1054,14 +1054,19 @@ static int hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)* In this kind of scenario skip the update and let the random * address be updated at the next cycle. */ +rcu_read_lock (); +if (bacmp (&hdev->random_addr,BDADDR_ANY ) && (hci_dev_test_flag (hdev,HCI_LE_ADV ) ||hci_lookup_le_connect (hdev))) {bt_dev_dbg (hdev,"Deferring random address update" );hci_dev_set_flag (hdev,HCI_RPA_EXPIRED ); +rcu_read_unlock ();return 0 ; } +rcu_read_unlock (); +return __hci_cmd_sync_status (hdev,HCI_OP_LE_SET_RANDOM_ADDR ,6 , rpa,HCI_CMD_TIMEOUT ); }
@@ -2647,12 +2652,17 @@ static int hci_pause_addr_resolution(struct hci_dev *hdev)/* Cannot disable addr resolution if scanning is enabled or * when initiating an LE connection. */ +rcu_read_lock (); +if (hci_dev_test_flag (hdev,HCI_LE_SCAN ) ||hci_lookup_le_connect (hdev)) { +rcu_read_unlock ();bt_dev_err (hdev,"Command not allowed when scan/LE connect" );return -EPERM ; } +rcu_read_unlock (); +/* Cannot disable addr resolution if advertising is enabled. */ err =hci_pause_advertising_sync (hdev);if (err) {
@@ -2790,6 +2800,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)if (hci_dev_test_flag (hdev,HCI_PA_SYNC )) {struct hci_conn *conn; +rcu_read_lock (); + conn =hci_conn_hash_lookup_create_pa_sync (hdev);if (conn) {struct conn_params pa;
@@ -2799,6 +2811,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)bacpy (&pa.addr, &conn->dst); pa.addr_type = conn->dst_type; +rcu_read_unlock (); +/* Clear first since there could be addresses left * behind. */
@@ -2808,6 +2822,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) err =hci_le_add_accept_list_sync (hdev, &pa, &num_entries); goto done; + }else { +rcu_read_unlock (); } }
@@ -2818,10 +2834,13 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)* the controller. */ list_for_each_entry_safe (b, t, &hdev->le_accept_list, list) { -if (hci_conn_hash_lookup_le (hdev, &b->bdaddr, b->bdaddr_type)) +rcu_read_lock (); + +if (hci_conn_hash_lookup_le (hdev, &b->bdaddr, b->bdaddr_type)) { +rcu_read_unlock ();continue ; + } -/* Pointers not dereferenced, no locks needed */ pend_conn =hci_pend_le_action_lookup (&hdev->pend_le_conns, &b->bdaddr, b->bdaddr_type);
@@ -2829,6 +2848,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) &b->bdaddr, b->bdaddr_type); +rcu_read_unlock (); +/* If the device is not likely to connect or report, * remove it from the acceptlist. */
@@ -2955,6 +2976,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,if (sent) {struct hci_conn *conn; +rcu_read_lock (); + conn =hci_conn_hash_lookup_ba (hdev,PA_LINK , &sent->bdaddr);if (conn) {
@@ -2979,8 +3002,12 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type, phy++; } +rcu_read_unlock (); +if (num_phy) goto done; + }else { +rcu_read_unlock (); } } }
@@ -3231,12 +3258,16 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev)/* If there is at least one pending LE connection, we should * keep the background scan running. */ +bool exists;/* If controller is connecting, we should not start scanning * since some controllers are not able to scan and connect at * the same time. */ -if (hci_lookup_le_connect (hdev)) +rcu_read_lock (); + exists =hci_lookup_le_connect (hdev); +rcu_read_unlock (); +if (exists)return 0 ;bt_dev_dbg (hdev,"start background scanning" );
@@ -3451,6 +3482,7 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable) }static bool disconnected_accept_list_entries (struct hci_dev *hdev) + __must_hold(&hdev->lock) {struct bdaddr_list *b;
@@ -3491,12 +3523,16 @@ int hci_update_scan_sync(struct hci_dev *hdev)if (hdev->scanning_paused)return 0 ; +hci_dev_lock (hdev); +if (hci_dev_test_flag (hdev,HCI_CONNECTABLE ) ||disconnected_accept_list_entries (hdev)) scan =SCAN_PAGE ;else scan =SCAN_DISABLED ; +hci_dev_unlock (hdev); +if (hci_dev_test_flag (hdev,HCI_DISCOVERABLE )) scan |=SCAN_INQUIRY ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 110/675 Bluetooth: mgmt: fix locking in unpair_device/disconnect_sync
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 16cd66443957e4ad42155c6fec401012f600c6f8 ]
Dereferencing RCU-protected pointers outside critical sections is invalid and may lead to UAF.
Take hdev->lock for hci_conn lookup and hci_abort_conn(). Don't use RCU to ensure the conn is fully initialized at this point.
--- net/bluetooth/mgmt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
net/bluetooth/mgmt.c +16 -0
@@ -3082,6 +3082,8 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)struct mgmt_cp_unpair_device *cp = cmd->param;struct hci_conn *conn; +hci_dev_lock (hdev); +if (cp->addr.type ==BDADDR_BREDR ) conn =hci_conn_hash_lookup_ba (hdev,ACL_LINK , &cp->addr.bdaddr);
@@ -3089,6 +3091,11 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data) conn =hci_conn_hash_lookup_le (hdev, &cp->addr.bdaddr,le_addr_type (cp->addr.type)); +if (conn) +hci_conn_get (conn); + +hci_dev_unlock (hdev); +if (!conn)return 0 ;
@@ -3096,6 +3103,7 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)* will clean up the connection no matter the error. */ hci_abort_conn (conn,HCI_ERROR_REMOTE_USER_TERM ); +hci_conn_put (conn);return 0 ; }
@@ -3243,6 +3251,8 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)struct mgmt_cp_disconnect *cp = cmd->param;struct hci_conn *conn; +hci_dev_lock (hdev); +if (cp->addr.type ==BDADDR_BREDR ) conn =hci_conn_hash_lookup_ba (hdev,ACL_LINK , &cp->addr.bdaddr);
@@ -3250,6 +3260,11 @@ static int disconnect_sync(struct hci_dev *hdev, void *data) conn =hci_conn_hash_lookup_le (hdev, &cp->addr.bdaddr,le_addr_type (cp->addr.type)); +if (conn) +hci_conn_get (conn); + +hci_dev_unlock (hdev); +if (!conn)return -ENOTCONN ;
@@ -3257,6 +3272,7 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)* will clean up the connection no matter the error. */ hci_abort_conn (conn,HCI_ERROR_REMOTE_USER_TERM ); +hci_conn_put (conn);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 111/675 Bluetooth: mgmt: hold reference for hci_conn in mgmt_pending_cmds
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit da55f570191d5d72f10c607a7043b947eb05ea46 ]
Dereferencing RCU-protected pointers outside critical sections is invalid and may lead to UAF. Use of hci_conn in hci_sync callbacks also needs to hold refcount to avoid UAF.
Take appropriate locks for hci_conn lookups, and take refcount for hci_conn pointers stored in mgmt_pending_cmd so that the pointer stays valid.
When accessing conn->state, ensure hdev->lock is held to avoid data race.
--- net/bluetooth/mgmt.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
net/bluetooth/mgmt.c +22 -4
@@ -7325,6 +7325,9 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err) rp.max_tx_power =HCI_TX_POWER_INVALID ; } +if (conn) +hci_conn_put (conn); +mgmt_cmd_complete (cmd->sk, cmd->hdev->id,MGMT_OP_GET_CONN_INFO , status, &rp,sizeof (rp));
@@ -7339,6 +7342,8 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)int err;__le16 handle; +hci_dev_lock (hdev); +/* Make sure we are still connected */ if (cp->addr.type ==BDADDR_BREDR ) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
@@ -7346,12 +7351,16 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)else conn =hci_conn_hash_lookup_ba (hdev,LE_LINK , &cp->addr.bdaddr); -if (!conn || conn->state !=BT_CONNECTED ) +if (!conn || conn->state !=BT_CONNECTED ) { +hci_dev_unlock (hdev);return MGMT_STATUS_NOT_CONNECTED ; + } - cmd->user_data = conn; + cmd->user_data =hci_conn_get (conn); handle =cpu_to_le16 (conn->handle); +hci_dev_unlock (hdev); +/* Refresh RSSI each time */ err =hci_read_rssi_sync (hdev, handle);
@@ -7485,6 +7494,9 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err) } complete: +if (conn) +hci_conn_put (conn); +mgmt_cmd_complete (cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,sizeof (rp));
@@ -7501,15 +7513,21 @@ static int get_clock_info_sync(struct hci_dev *hdev, void *data)memset (&hci_cp,0 ,sizeof (hci_cp));hci_read_clock_sync (hdev, &hci_cp); +hci_dev_lock (hdev); +/* Make sure connection still exists */ conn =hci_conn_hash_lookup_ba (hdev,ACL_LINK , &cp->addr.bdaddr); -if (!conn || conn->state !=BT_CONNECTED ) +if (!conn || conn->state !=BT_CONNECTED ) { +hci_dev_unlock (hdev);return MGMT_STATUS_NOT_CONNECTED ; + } - cmd->user_data = conn; + cmd->user_data =hci_conn_get (conn); hci_cp.handle =cpu_to_le16 (conn->handle); hci_cp.which =0x01 ;/* Piconet clock */ +hci_dev_unlock (hdev); +return hci_read_clock_sync (hdev, &hci_cp); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 112/675 Bluetooth: hci_qca: Clear memdump state on invalid dump size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit bf587a10c33e5571a299742e45bc18960b9912e7 ]
qca_controller_memdump() allocates qca->qca_memdump before processing the first dump packet. For a sequence-zero packet it then disables IBS, marks memdump collection active, and reads the advertised dump size.
If the controller reports a zero dump size, the error path frees the local qca_memdump object and returns without clearing qca->qca_memdump or undoing the collection state. A later memdump work item initializes its local pointer from qca->qca_memdump and skips allocation when that pointer is non-NULL, so it can operate on freed memory. The stale collection and IBS-disabled flags can also leave waiters or later transmit handling blocked behind an aborted dump.
Clear the saved pointer and memdump state before returning from the invalid-size path, matching the cleanup used when hci_devcd_init() fails.
A static analysis checker reported the stale memdump state, and manual source review confirmed the invalid-size failure path.
--- drivers/bluetooth/hci_qca.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/bluetooth/hci_qca.c +4 -0
@@ -1083,6 +1083,10 @@ static void qca_controller_memdump(struct work_struct *work)if (!(qca_memdump->ram_dump_size)) {bt_dev_err (hu->hdev,"Rx invalid memdump size" );kfree (qca_memdump); + qca->qca_memdump =NULL ; + qca->memdump_state =QCA_MEMDUMP_COLLECTED ; +clear_and_wake_up_bit (QCA_MEMDUMP_COLLECTION , &qca->flags); +clear_bit (QCA_IBS_DISABLED , &qca->flags);kfree_skb (skb);mutex_unlock (&qca->hci_memdump_lock);return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 113/675 smb/client: handle overlapping allocated ranges in fallocate
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
[ Upstream commit b09ae45d85dc816987a71db9eebc54b0ae288e94 ]
smb3_simple_fallocate_range() can skip holes when an allocated range returned by the server starts before the current fallocate offset. The skipped hole is not zero-filled, but fallocate still returns success. A later write to that hole may therefore fail with ENOSPC.
The function queries allocated ranges so that it can preserve existing contents and write zeroes only into holes. However, the server may return a range that starts before the current fallocate offset.
For example, assume the fallocate request is [100, 400) and the only allocated range returned by the server is [0, 200):
Request: [100, 400)
Server range: [ 0, 200) allocated
Correct:
[100, 200) allocated data, skip
[200, 400) hole, zero-fill
Current:
[100, 300) skipped
[300, 400) zero-filled afterwardsThe current code adds the full server range length, 200, to the current offset 100 and moves to 300. As a result, the hole in [200, 300) is skipped without being zero-filled.
Fix this by advancing only over the part of the allocated range that overlaps the current fallocate offset. Ignore ranges that end before the current offset and reject ranges whose end offset overflows.
This also prevents a malformed range length from causing an out-of-bounds zero-buffer read.
--- fs/smb/client/smb2ops.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
fs/smb/client/smb2ops.c +18 -7
@@ -3546,6 +3546,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,struct file_allocated_range_buffer in_data, *out_data =NULL , *tmp_data;u32 out_data_len;char *buf =NULL ; +u64 range_start, range_len, range_end;loff_t l;int rc;
@@ -3582,13 +3583,21 @@ static int smb3_simple_fallocate_range(unsigned int xid, goto out; } -if (off <le64_to_cpu (tmp_data->file_offset)) { + range_start =le64_to_cpu (tmp_data->file_offset); + range_len =le64_to_cpu (tmp_data->length); +if (check_add_overflow (range_start, range_len, &range_end) || + range_end >S64_MAX ) { + rc = -EINVAL ; + goto out; + } + +if (off < range_start) {/* * We are at a hole. Write until the end of the region * or until the next allocated data, * whichever comes next. */ - l =le64_to_cpu (tmp_data->file_offset) - off; + l = range_start - off;if (len < l) l = len; rc = smb3_simple_fallocate_write_range(xid, tcon,
@@ -3605,11 +3614,13 @@ static int smb3_simple_fallocate_range(unsigned int xid,* until the end of the data or the end of the region * we are supposed to fallocate, whichever comes first. */ - l =le64_to_cpu (tmp_data->length); -if (len < l) - l = len; - off += l; - len -= l; +if (off < range_end) { + l = range_end - off; +if (len < l) + l = len; + off += l; + len -= l; + } tmp_data = &tmp_data[1 ]; out_data_len -=sizeof (struct file_allocated_range_buffer );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 114/675 drm/i915/gt: use correct selftest config symbol
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit a82f1bb8191aec98a971a2196136016ef70c0880 ]
intel_engine_user.c checks CONFIG_DRM_I915_SELFTESTS before running the engine UABI isolation check. Kconfig defines DRM_I915_SELFTEST, without the trailing "S", and the rest of i915 uses CONFIG_DRM_I915_SELFTEST.
Because CONFIG_DRM_I915_SELFTESTS is not backed by any Kconfig symbol, the IS_ENABLED() test is always false. Use the existing selftest symbol so the debug/selftest guarded path can be reached when selftests are enabled.
This is a source-level fix. It does not claim dynamic hardware reproduction; the evidence is the Kconfig definition and the inconsistent guard in intel_engine_user.c.
--- drivers/gpu/drm/i915/gt/intel_engine_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_engine_user.c +1 -1
@@ -257,7 +257,7 @@ void intel_engines_driver_register(struct drm_i915_private *i915) p = &prev->rb_right; } -if (IS_ENABLED (CONFIG_DRM_I915_SELFTESTS ) && +if (IS_ENABLED (CONFIG_DRM_I915_SELFTEST ) &&IS_ENABLED (CONFIG_DRM_I915_DEBUG_GEM )) {struct intel_engine_cs *engine;unsigned int isolation;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 115/675 can: raw: add locking for raw flags bitfield
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Hartkopp <[email protected]>
[ Upstream commit 1e5185c090589f4146d728ab36417d8a5419f127 ]
With commit 890e5198a6e5 ("can: raw: use bitfields to store flags in struct raw_sock") the formerly separate integer values have been integrated into a single bitfield. This led to a read-modify-write operation when changing a flag in raw_setsockopt() which now needs a locking to prevent concurrent access.
Instead of adding a lock/unlock hell in each of the flag manipulations this patch introduces a wrapper for a new raw_setsockopt_locked() function analogue to the isotp_setsockopt[_locked]() approach in net/can/isotp.c
--- net/can/raw.c | 66 +++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 36 deletions(-)
net/can/raw.c +30 -36
@@ -560,8 +560,8 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,return RAW_MIN_NAMELEN ; } -static int raw_setsockopt (struct socket *sock,int level,int optname, -sockptr_t optval,unsigned int optlen) +static int raw_setsockopt_locked (struct socket *sock,int optname, +sockptr_t optval,unsigned int optlen) {struct sock *sk = sock->sk;struct raw_sock *ro =raw_sk (sk);
@@ -573,9 +573,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,int flag;int err =0 ; -if (level !=SOL_CAN_RAW ) -return -EINVAL ; -switch (optname) {case CAN_RAW_FILTER :if (optlen %sizeof (struct can_filter ) !=0 )
@@ -596,17 +593,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,return -EFAULT ; } -rtnl_lock (); -lock_sock (sk); - dev = ro->dev; -if (ro->bound && dev) { -if (dev->reg_state !=NETREG_REGISTERED ) { -if (count >1 ) -kfree (filter); - err = -ENODEV ; - goto out_fil; - } +if (ro->bound && dev && dev->reg_state !=NETREG_REGISTERED ) { +if (count >1 ) +kfree (filter); +return -ENODEV ; }if (ro->bound) {
@@ -620,7 +611,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,if (err) {if (count >1 )kfree (filter); - goto out_fil; +return err; }/* remove old filter registrations */
@@ -640,11 +631,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, } ro->filter = filter; ro->count = count; - - out_fil: -release_sock (sk); -rtnl_unlock (); -break ;case CAN_RAW_ERR_FILTER :
@@ -656,16 +642,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, err_mask &=CAN_ERR_MASK ; -rtnl_lock (); -lock_sock (sk); - dev = ro->dev; -if (ro->bound && dev) { -if (dev->reg_state !=NETREG_REGISTERED ) { - err = -ENODEV ; - goto out_err; - } - } +if (ro->bound && dev && dev->reg_state !=NETREG_REGISTERED ) +return -ENODEV ;/* remove current error mask */ if (ro->bound) {
@@ -674,7 +653,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, err_mask);if (err) - goto out_err; +return err;/* remove old err_mask registration */ raw_disable_errfilter(sock_net(sk), dev, sk,
@@ -683,11 +662,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,/* link new err_mask to the socket */ ro->err_mask = err_mask; - - out_err: -release_sock (sk); -rtnl_unlock (); -break ;case CAN_RAW_LOOPBACK :
@@ -767,6 +741,26 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,return err; } +static int raw_setsockopt (struct socket *sock,int level,int optname, +sockptr_t optval,unsigned int optlen) +{ +struct sock *sk = sock->sk; +int err; + +if (level !=SOL_CAN_RAW ) +return -EINVAL ; + +rtnl_lock (); +lock_sock (sk); + + err =raw_setsockopt_locked (sock, optname, optval, optlen); + +release_sock (sk); +rtnl_unlock (); + +return err; +} +static int raw_getsockopt (struct socket *sock,int level,int optname,char __user *optval,int __user *optlen) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 116/675 powerpc/85xx: Add fsl,ifc to common device ids
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit 25957f7c3dac3265332d766b71233e3622f17e14 ]
Add fsl,ifc to mpc85xx_common_ids so that of_platform_bus_probe creates a platform device for the IFC node even without 'simple-bus' in its compatible property. On P1010 and similar platforms the IFC node is a direct child of the root, so it must be explicitly matched to be populated.
--- arch/powerpc/platforms/85xx/common.c | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/platforms/85xx/common.c +2 -0
@@ -42,6 +42,8 @@ static const struct of_device_id mpc85xx_common_ids[] __initconst = { { .compatible = "fsl,qoriq-pcie-v2.3", }, { .compatible = "fsl,qoriq-pcie-v2.2", }, { .compatible = "fsl,fman", }, + /* IFC NAND and NOR controllers */ + { .compatible = "fsl,ifc", }, {}, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 117/675 powerpc/time: Prepare to stop elapsing in dynticks-idle
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frederic Weisbecker <[email protected]>
[ Upstream commit c8ba971cf8567d49eb5f43ee90c4e50424331c18 ]
Currently the tick subsystem stores the idle cputime accounting in private fields, allowing cohabitation with architecture idle vtime accounting. The former is fetched on online CPUs, the latter on offline CPUs.
For consolidation purpose, architecture vtime accounting will continue to account the cputime but will make a break when the idle tick is stopped. The dyntick cputime accounting will then be relayed by the tick subsystem so that the idle cputime is still seen advancing coherently even when the tick isn't there to flush the idle vtime.
Prepare for that and introduce three new APIs which will be used in subsequent patches:
- vtime_dynticks_start() is deemed to be called when idle enters in dyntick mode. The idle cputime that elapsed so far is accumulated.
- vtime_dynticks_stop() is deemed to be called when idle exits from dyntick mode. The vtime entry clocks are fast-forward to current time so that idle accounting restarts elapsing from now.
- vtime_reset() is deemed to be called from dynticks idle IRQ entry to fast-forward the clock to current time so that the IRQ time is still accounted by vtime while nohz cputime is paused.
Also accumulated vtime won't be flushed from dyntick-idle ticks to avoid accounting twice the idle cputime, along with nohz accounting.
Stable-dep-of: c1c1ffa490fc ("powerpc/vtime: Initialize starttime at boot for native accounting")
--- arch/powerpc/kernel/time.c | 41 ++++++++++++++++++++++++++++++++++++++ include/linux/vtime.h | 6 ++++++ 2 files changed, 47 insertions(+)
arch/powerpc/kernel/time.c +41 -0
@@ -376,6 +376,47 @@ void vtime_task_switch(struct task_struct *prev) acct->starttime = acct0->starttime; } } + +#ifdef CONFIG_NO_HZ_COMMON +/** +* vtime_reset - Fast forward vtime entry clocks +* +* Called from dynticks idle IRQ entry to fast-forward the clocks to current time +* so that the IRQ time is still accounted by vtime while nohz cputime is paused. +*/ +void vtime_reset (void ) +{ +struct cpu_accounting_data *acct =get_accounting (current); + + acct->starttime =mftb (); +#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME + acct->startspurr =read_spurr (acct->starttime); +#endif +} + +/** +* vtime_dyntick_start - Inform vtime about entry to idle-dynticks +* +* Called when idle enters in dyntick mode. The idle cputime that elapsed so far +* is accumulated and the tick subsystem takes over the idle cputime accounting. +*/ +void vtime_dyntick_start (void ) +{ +vtime_account_idle (current); +} + +/** +* vtime_dyntick_stop - Inform vtime about exit from idle-dynticks +* +* Called when idle exits from dyntick mode. The vtime entry clocks are +* fast-forward to current time so that idle accounting restarts elapsing from +* now. +*/ +void vtime_dyntick_stop (void ) +{ +vtime_reset (); +} +#endif /* CONFIG_NO_HZ_COMMON */ #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ void __no_kcsan __delay(unsigned long loops)
include/linux/vtime.h +6 -0
@@ -32,11 +32,17 @@ extern void vtime_account_irq(struct task_struct *tsk, unsigned int offset);extern void vtime_account_softirq (struct task_struct *tsk);extern void vtime_account_hardirq (struct task_struct *tsk);extern void vtime_flush (struct task_struct *tsk); +extern void vtime_reset (void ); +extern void vtime_dyntick_start (void ); +extern void vtime_dyntick_stop (void );#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ static inline void vtime_account_irq (struct task_struct *tsk,unsigned int offset) { }static inline void vtime_account_softirq (struct task_struct *tsk) { }static inline void vtime_account_hardirq (struct task_struct *tsk) { }static inline void vtime_flush (struct task_struct *tsk) { } +static inline void vtime_reset (void ) { } +static inline void vtime_dyntick_start (void ) { } +static inline void vtime_dyntick_stop (void ) { }#endif /*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 118/675 powerpc/vtime: Initialize starttime at boot for native accounting
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shrikanth Hegde <[email protected]>
[ Upstream commit c1c1ffa490fc33591e90852ed0d38804dd20bc36 ]
It was observed that /proc/stat had very large value for one ore more CPUs. It was more visible after recent code simplifications around cpustats.
System has 240 CPUs.
cat /proc/uptime;
194.18 46500.55
cat /proc/stat
cpu 5966 39 837032887 4650070 164 185 100 0 0 0
cpu0 108 0 837030890 19109 24 4 23 0 0 0
Since uptime is 194s, system time of each CPU can't be more than 19400. Sum of system time of all CPUs can't be more than 19400*240 4656000. In fact huge value is close to mftb(). Note mftb doesn't reset on powerVM when the LPAR restart. It only resets when whole system resets. The same issue exists for kexec too.
This happens since starttime is not setup at init time. Once it is set then subsequent vtime_delta will return the right delta.
Fix it by initializing the starttime during CPU initialization. This fixes the large times seen.
cat /proc/uptime; cat /proc/stat
15.78 3694.63
cpu 6035 35 1347 369479 23 144 49 0 0 0
cpu0 19 0 38 1508 0 1 14 0 0 0
Now, system time is reported as expected.
--- arch/powerpc/kernel/time.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/powerpc/kernel/time.c +3 -1
@@ -377,7 +377,6 @@ void vtime_task_switch(struct task_struct *prev) } } -#ifdef CONFIG_NO_HZ_COMMON /** * vtime_reset - Fast forward vtime entry clocks *
@@ -394,6 +393,7 @@ void vtime_reset(void)#endif } +#ifdef CONFIG_NO_HZ_COMMON /** * vtime_dyntick_start - Inform vtime about entry to idle-dynticks *
@@ -933,6 +933,7 @@ static void __init set_decrementer_max(void)static void __init init_decrementer_clockevent (void ) {register_decrementer_clockevent (smp_processor_id ()); +vtime_reset (); }void secondary_cpu_time_init (void )
@@ -948,6 +949,7 @@ void secondary_cpu_time_init(void)/* FIME: Should make unrelated change to move snapshot_timebase * call here ! */ register_decrementer_clockevent (smp_processor_id ()); +vtime_reset (); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 119/675 bpf, sockmap: Reject unhashed UDP sockets on sockmap update
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Luczaj <[email protected]>
[ Upstream commit 66efd3368ae10d05e08fbe6425b50fdec7186ac7 ]
UDP sockets get SOCK_RCU_FREE set when (auto-)bound. This means sk_is_refcounted(unbound) = true, while sk_is_refcounted(bound) = false.
Because sockmap accepts unbound UDP sockets, a BPF program can increment a socket's refcount via lookup. If the socket is subsequently bound, the transition from unbound to bound causes bpf_sk_release() to skip the decrement of the refcount, causing a memory leak.
unreferenced object 0xffff88810bc2eb40 (size 1984):
comm "test_progs", pid 2451, jiffies 4295320596 hex dump (first 32 bytes):
7f 00 00 01 7f 00 00 01 d2 04 1b b7 04 d2 00 00 ................
02 00 01 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............
backtrace (crc bdee079d):
kmem_cache_alloc_noprof+0x557/0x660
sk_prot_alloc+0x69/0x240
sk_alloc+0x30/0x460
inet_create+0x2ce/0xf80
__sock_create+0x25b/0x5c0
__sys_socket+0x119/0x1d0
__x64_sys_socket+0x72/0xd0
do_syscall_64+0xa1/0x5f0
entry_SYSCALL_64_after_hwframe+0x76/0x7eInstead of special-casing for refcounted sockets, reject unhashed UDP sockets during sockmap updates, as there is no benefit to supporting those. This effectively reverts the commit under Fixes, with two exceptions:
1. sock_map_sk_state_allowed() maintains a fall-through return true.
2. In the spirit of commit b8b8315e39ff ("bpf, sockmap: Remove unhash handler for BPF sockmap usage"), the proto::unhash BPF handler is not reintroduced.
Historical note: this issue is related to commit 67312adc96b5 ("bpf: reject unhashed sockets in bpf_sk_assign").
--- net/core/sock_map.c | 2 ++ 1 file changed, 2 insertions(+)
net/core/sock_map.c +2 -0
@@ -542,6 +542,8 @@ static bool sock_map_sk_state_allowed(const struct sock *sk) {if (sk_is_tcp (sk))return (1 << sk->sk_state) & (TCPF_ESTABLISHED |TCPF_LISTEN ); +if (sk_is_udp (sk)) +return sk_hashed (sk);if (sk_is_stream_unix (sk))return (1 << sk->sk_state) &TCPF_ESTABLISHED ; if (sk_is_vsock(sk) &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 120/675 drm/panthor: Check debugfs GEM lock initialization
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 022e901333c3054656a640794e842bab7af5a75c ]
drmm_mutex_init() can fail while registering the managed cleanup action. When that happens, drmm_add_action_or_reset() destroys the mutex before returning the error. Continuing initialization would therefore leave the debugfs GEM object list with an unusable lock.
Propagate the error as is already done for the other managed mutexes in panthor_device_init().
--- drivers/gpu/drm/panthor/panthor_device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/panthor/panthor_device.c +4 -1
@@ -182,7 +182,10 @@ int panthor_device_init(struct panthor_device *ptdev)return ret;#ifdef CONFIG_DEBUG_FS -drmm_mutex_init (&ptdev->base, &ptdev->gems.lock); + ret =drmm_mutex_init (&ptdev->base, &ptdev->gems.lock); +if (ret) +return ret; +INIT_LIST_HEAD (&ptdev->gems.node);#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 121/675 s390/checksum: Fix csum_partial() without vector facility
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Gorbik <[email protected]>
[ Upstream commit 4bb06b60d982355e22647b3d12d6619419f8c1fa ]
Currently csum_partial() calls csum_copy() with copy=false and dst=NULL. On machines without the vector facility, csum_copy() falls back to cksm(dst, ...), causing the checksum to be calculated from address zero instead of the source buffer.
The VX implementation already checksums data loaded from src. Make the fallback do the same by passing src to cksm().
--- arch/s390/lib/csum-partial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/lib/csum-partial.c +1 -1
@@ -23,7 +23,7 @@ static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __wif (!cpu_has_vx ()) {if (copy)memcpy (dst, src, len); -return cksm (dst, len, sum); +return cksm (src, len, sum); }kernel_fpu_begin (&vxstate,KERNEL_VXR_V16V23 );fpu_vlvgf (16 , (__force u32 )sum,1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 122/675 riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harris <[email protected]>
[ Upstream commit 5caae1deee89a6582c761d5dcd4b924b744426cc ]
When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully initialize its copy of the cpu mask, which could cause non-deterministic results from the riscv_hwprobe syscall on a system with more than 8 CPUs when the supplied cpu mask is empty. Address this by fully initializing the cpu mask.
--- arch/riscv/kernel/sys_hwprobe.c | 1 + 1 file changed, 1 insertion(+)
arch/riscv/kernel/sys_hwprobe.c +1 -0
@@ -409,6 +409,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,if (cpusetsize >cpumask_size ()) cpusetsize =cpumask_size (); +cpumask_clear (&cpus); ret =copy_from_user (&cpus, cpus_user, cpusetsize);if (ret)return -EFAULT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 123/675 can: j1939: fix lockless local-destination check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuhao Fu <[email protected]>
[ Upstream commit e4e8af62adab2fdcca230006f829407a953070cd ]
j1939_priv.ents[].nusers is documented as protected by priv->lock, and its updates already happen under that lock. j1939_can_recv() also reads it under read_lock_bh(). However, j1939_session_skb_queue() and j1939_tp_send() still read priv->ents[da].nusers without taking the lock.
Those transport-side checks decide whether to set J1939_ECU_LOCAL_DST, so they can race with j1939_local_ecu_get() and j1939_local_ecu_put() while userspace is binding or releasing sockets concurrently with TP traffic. This can misclassify TP/ETP sessions as local or remote and take the wrong transport path.
Fix both transport paths by routing the destination-locality check through a helper that reads ents[].nusers under read_lock_bh(&priv->lock).
--- net/can/j1939/transport.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
net/can/j1939/transport.c +14 -4
@@ -350,6 +350,18 @@ static void j1939_session_skb_drop_old(struct j1939_session *session) } } +static bool j1939_address_is_local (struct j1939_priv *priv,u8 addr) +{ +bool local = false; + +read_lock_bh (&priv->lock); +if (j1939_address_is_unicast (addr) && priv->ents[addr].nusers) + local = true; +read_unlock_bh (&priv->lock); + +return local; +} +void j1939_session_skb_queue (struct j1939_session *session,struct sk_buff *skb) {
@@ -358,8 +370,7 @@ void j1939_session_skb_queue(struct j1939_session *session,j1939_ac_fixup (priv, skb); -if (j1939_address_is_unicast (skcb->addr.da) && - priv->ents[skcb->addr.da].nusers) +if (j1939_address_is_local (priv, skcb->addr.da)) skcb->flags |=J1939_ECU_LOCAL_DST ; skcb->flags |=J1939_ECU_LOCAL_SRC ;
@@ -2017,8 +2028,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv,return ERR_PTR (ret);/* fix DST flags, it may be used there soon */ -if (j1939_address_is_unicast (skcb->addr.da) && - priv->ents[skcb->addr.da].nusers) +if (j1939_address_is_local (priv, skcb->addr.da)) skcb->flags |=J1939_ECU_LOCAL_DST ;/* src is always local, I'm sending ... */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 124/675 drm/xe: Allow the caller to pass guc_buf_cache size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michał Winiarski <[email protected]>
[ Upstream commit dca2701a6277399f9d255f09b4c34d9a7171c09b ]
An upcoming change will use GuC buffer cache as a place where GuC migration data will be stored, and the memory requirement for that is larger than indirect data.
Allow the caller to pass the size based on the intended usecase.
Stable-dep-of: 56441f9e08ad ("drm/xe/vf: Fix VF CCS attach/detach race with in-flight BO moves")
--- drivers/gpu/drm/xe/xe_guc_buf.c | 44 ++++++++++++++++++++++++--------- drivers/gpu/drm/xe/xe_guc_buf.h | 1 + 2 files changed, 34 insertions(+), 11 deletions(-)
drivers/gpu/drm/xe/xe_guc_buf.c +33 -11
@@ -13,6 +13,8 @@#include "xe_guc_buf.h" #include "xe_sa.h" +#define XE_GUC_BUF_CACHE_DEFAULT_SIZE SZ_8K +static struct xe_guc *cache_to_guc (struct xe_guc_buf_cache *cache) { return container_of(cache, struct xe_guc, buf);
@@ -23,21 +25,12 @@ static struct xe_gt *cache_to_gt(struct xe_guc_buf_cache *cache)return guc_to_gt (cache_to_guc (cache)); } -/** -* xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache. -* @cache: the &xe_guc_buf_cache to initialize -* -* The Buffer Cache allows to obtain a reusable buffer that can be used to pass -* indirect H2G data to GuC without a need to create a ad-hoc allocation. -* -* Return: 0 on success or a negative error code on failure. -*/ -int xe_guc_buf_cache_init (struct xe_guc_buf_cache *cache) +static int guc_buf_cache_init (struct xe_guc_buf_cache *cache,u32 size) {struct xe_gt *gt =cache_to_gt (cache);struct xe_sa_manager *sam; - sam =__xe_sa_bo_manager_init (gt_to_tile (gt),SZ_8K ,0 ,sizeof (u32)); + sam =__xe_sa_bo_manager_init (gt_to_tile (gt), size,0 ,sizeof (u32));if (IS_ERR (sam))return PTR_ERR (sam); cache->sam = sam;
@@ -48,6 +41,35 @@ int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache)return 0 ; } +/** +* xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache. +* @cache: the &xe_guc_buf_cache to initialize +* +* The Buffer Cache allows to obtain a reusable buffer that can be used to pass +* data to GuC or read data from GuC without a need to create a ad-hoc allocation. +* +* Return: 0 on success or a negative error code on failure. +*/ +int xe_guc_buf_cache_init (struct xe_guc_buf_cache *cache) +{ +return guc_buf_cache_init (cache,XE_GUC_BUF_CACHE_DEFAULT_SIZE ); +} + +/** +* xe_guc_buf_cache_init_with_size() - Initialize the GuC Buffer Cache. +* @cache: the &xe_guc_buf_cache to initialize +* @size: size in bytes +* +* Like xe_guc_buf_cache_init(), except it allows the caller to make the cache +* buffer larger, allowing to accommodate larger objects. +* +* Return: 0 on success or a negative error code on failure. +*/ +int xe_guc_buf_cache_init_with_size (struct xe_guc_buf_cache *cache,u32 size) +{ +return guc_buf_cache_init (cache,max (XE_GUC_BUF_CACHE_DEFAULT_SIZE , size)); +} +/** * xe_guc_buf_cache_dwords() - Number of dwords the GuC Buffer Cache supports. * @cache: the &xe_guc_buf_cache to query
drivers/gpu/drm/xe/xe_guc_buf.h +1 -0
@@ -12,6 +12,7 @@#include "xe_guc_buf_types.h" int xe_guc_buf_cache_init (struct xe_guc_buf_cache *cache); +int xe_guc_buf_cache_init_with_size (struct xe_guc_buf_cache *cache,u32 size);u32 xe_guc_buf_cache_dwords (struct xe_guc_buf_cache *cache);struct xe_guc_buf xe_guc_buf_reserve (struct xe_guc_buf_cache *cache,u32 dwords); struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 125/675 drm/xe/sa: Shadow buffer support in the sub-allocator pool
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyanarayana K V P <[email protected]>
[ Upstream commit 1f2cf5295cdba71818288c9e495b4ef5097565ed ]
The existing sub-allocator is limited to managing a single buffer object. This enhancement introduces shadow buffer functionality to support scenarios requiring dual buffer management.
The changes include added shadow buffer object creation capability, Management for both primary and shadow buffers, and appropriate locking mechanisms for thread-safe operations.
This enables more flexible buffer allocation strategies in scenarios where shadow buffering is required.
Stable-dep-of: 56441f9e08ad ("drm/xe/vf: Fix VF CCS attach/detach race with in-flight BO moves")
--- drivers/gpu/drm/xe/xe_guc_buf.c | 2 +- drivers/gpu/drm/xe/xe_sa.c | 67 +++++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_sa.h | 20 ++++++++- drivers/gpu/drm/xe/xe_sa_types.h | 3 ++ drivers/gpu/drm/xe/xe_sriov_vf_ccs.c | 3 ++ 5 files changed, 91 insertions(+), 4 deletions(-)
drivers/gpu/drm/xe/xe_guc_buf.c +1 -1
@@ -30,7 +30,7 @@ static int guc_buf_cache_init(struct xe_guc_buf_cache *cache, u32 size)struct xe_gt *gt =cache_to_gt (cache);struct xe_sa_manager *sam; - sam =__xe_sa_bo_manager_init (gt_to_tile (gt), size,0 ,sizeof (u32)); + sam =__xe_sa_bo_manager_init (gt_to_tile (gt), size,0 ,sizeof (u32),0 );if (IS_ERR (sam))return PTR_ERR (sam); cache->sam = sam;
drivers/gpu/drm/xe/xe_sa.c +66 -1
96 lines not on this page · raw message
drivers/gpu/drm/xe/xe_sa.h +18 -2
@@ -14,12 +14,14 @@struct dma_fence ;struct xe_tile ; -struct xe_sa_manager *__xe_sa_bo_manager_init (struct xe_tile *tile,u32 size,u32 guard,u32 align); +#define XE_SA_BO_MANAGER_FLAG_SHADOW BIT(0) +struct xe_sa_manager *__xe_sa_bo_manager_init (struct xe_tile *tile,u32 size, +u32 guard,u32 align,u32 flags);struct drm_suballoc *__xe_sa_bo_new (struct xe_sa_manager *sa_manager,u32 size,gfp_t gfp);static inline struct xe_sa_manager *xe_sa_bo_manager_init (struct xe_tile *tile,u32 size,u32 align) { -return __xe_sa_bo_manager_init (tile, size,SZ_4K , align); +return __xe_sa_bo_manager_init (tile, size,SZ_4K , align,0 ); }/**
@@ -68,4 +70,18 @@ static inline void *xe_sa_bo_cpu_addr(struct drm_suballoc *sa) drm_suballoc_soffset(sa); } +void xe_sa_bo_swap_shadow (struct xe_sa_manager *sa_manager); +void xe_sa_bo_sync_shadow (struct drm_suballoc *sa_bo); + +/** +* xe_sa_bo_swap_guard() - Retrieve the SA BO swap guard within sub-allocator. +* @sa_manager: the &xe_sa_manager +* +* Return: Sub alloctor swap guard mutex. +*/ +static inline struct mutex *xe_sa_bo_swap_guard (struct xe_sa_manager *sa_manager) +{ +return &sa_manager->swap_guard; +} +#endif
drivers/gpu/drm/xe/xe_sa_types.h +3 -0
@@ -12,6 +12,9 @@ struct xe_bo;struct xe_sa_manager {struct drm_suballoc_manager base;struct xe_bo *bo; +struct xe_bo *shadow; +/** @swap_guard: Timeline guard updating @bo and @shadow */ +struct mutex swap_guard;void *cpu_ptr;bool is_iomem; };
drivers/gpu/drm/xe/xe_sriov_vf_ccs.c +3 -0
@@ -160,9 +160,12 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) offset =0 ;xe_map_memset (xe, &sa_manager->bo->vmap, offset,MI_NOOP , bb_pool_size); +xe_map_memset (xe, &sa_manager->shadow->vmap, offset,MI_NOOP , + bb_pool_size); offset = bb_pool_size -sizeof (u32);xe_map_wr (xe, &sa_manager->bo->vmap, offset, u32,MI_BATCH_BUFFER_END ); +xe_map_wr (xe, &sa_manager->shadow->vmap, offset, u32,MI_BATCH_BUFFER_END ); ctx->mem.ccs_bb_pool = sa_manager;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 126/675 drm/xe/vf: Shadow buffer management for CCS read/write operations
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyanarayana K V P <[email protected]>
[ Upstream commit fa18290bf0723b02bfa8d30d2e14722f0d096c2c ]
CCS copy command consist of 5-dword sequence. If vCPU halts during save/restore operations while these sequences are being programmed, incomplete writes can cause page faults during IGPU CCS metadata saving.
Use shadow buffer management to prevent partial write issues during CCS operations.
Stable-dep-of: 56441f9e08ad ("drm/xe/vf: Fix VF CCS attach/detach race with in-flight BO moves")
--- drivers/gpu/drm/xe/xe_migrate.c | 57 ++++++++++++++++++++++++++-- drivers/gpu/drm/xe/xe_migrate.h | 3 ++ drivers/gpu/drm/xe/xe_sriov_vf_ccs.c | 19 ++++++++-- drivers/gpu/drm/xe/xe_sriov_vf_ccs.h | 1 + 4 files changed, 73 insertions(+), 7 deletions(-)
drivers/gpu/drm/xe/xe_migrate.c +54 -3
@@ -33,6 +33,7 @@#include "xe_res_cursor.h" #include "xe_sa.h" #include "xe_sched_job.h" +#include "xe_sriov_vf_ccs.h" #include "xe_sync.h" #include "xe_trace_bo.h" #include "xe_validation.h"
@@ -1022,12 +1023,16 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,u32 batch_size, batch_size_allocated;struct xe_device *xe =gt_to_xe (gt);struct xe_res_cursor src_it, ccs_it; +struct xe_sriov_vf_ccs_ctx *ctx; +struct xe_sa_manager *bb_pool;u64 size =xe_bo_size (src_bo);struct xe_bb *bb =NULL ;u64 src_L0, src_L0_ofs;u32 src_L0_pt;int err; + ctx = &xe->sriov.vf.ccs.contexts[read_write]; +xe_res_first_sg (xe_bo_sg (src_bo),0 , size, &src_it); xe_res_first_sg(xe_bo_sg(src_bo), xe_bo_ccs_pages_start(src_bo),
@@ -1060,11 +1065,15 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, size -= src_L0; } + bb_pool = ctx->mem.ccs_bb_pool; +guard (mutex) (xe_sa_bo_swap_guard (bb_pool)); +xe_sa_bo_swap_shadow (bb_pool); + bb =xe_bb_ccs_new (gt, batch_size, read_write);if (IS_ERR (bb)) {drm_err (&xe->drm,"BB allocation failed.\n" ); err =PTR_ERR (bb); - goto err_ret; +return err; } batch_size_allocated = batch_size;
@@ -1113,10 +1122,52 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,xe_assert (xe, (batch_size_allocated == bb->len)); src_bo->bb_ccs[read_write] = bb; +xe_sriov_vf_ccs_rw_update_bb_addr (ctx); +xe_sa_bo_sync_shadow (bb->bo);return 0 ; +} -err_ret: -return err; +/** +* xe_migrate_ccs_rw_copy_clear() - Clear the CCS read/write batch buffer +* content. +* @src_bo: The buffer object @src is currently bound to. +* @read_write : Creates BB commands for CCS read/write. +* +* Directly clearing the BB lacks atomicity and can lead to undefined +* behavior if the vCPU is halted mid-operation during the clearing +* process. To avoid this issue, we use a shadow buffer object approach. +* +* First swap the SA BO address with the shadow BO, perform the clearing +* operation on the BB, update the shadow BO in the ring buffer, then +* sync the shadow and the actual buffer to maintain consistency. +* +* Returns: None. +*/ +void xe_migrate_ccs_rw_copy_clear (struct xe_bo *src_bo, +enum xe_sriov_vf_ccs_rw_ctxs read_write) +{ +struct xe_bb *bb = src_bo->bb_ccs[read_write]; +struct xe_device *xe =xe_bo_device (src_bo); +struct xe_sriov_vf_ccs_ctx *ctx; +struct xe_sa_manager *bb_pool; +u32 *cs; + +xe_assert (xe,IS_SRIOV_VF (xe)); + + ctx = &xe->sriov.vf.ccs.contexts[read_write]; + bb_pool = ctx->mem.ccs_bb_pool; + +guard (mutex) (xe_sa_bo_swap_guard (bb_pool)); +xe_sa_bo_swap_shadow (bb_pool); + + cs =xe_sa_bo_cpu_addr (bb->bo); +memset (cs,MI_NOOP , bb->len *sizeof (u32)); +xe_sriov_vf_ccs_rw_update_bb_addr (ctx); + +xe_sa_bo_sync_shadow (bb->bo); + +xe_bb_free (bb,NULL ); + src_bo->bb_ccs[read_write] =NULL ; }/**
drivers/gpu/drm/xe/xe_migrate.h +3 -0
@@ -131,6 +131,9 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,struct xe_bo *src_bo, enum xe_sriov_vf_ccs_rw_ctxs read_write); +void xe_migrate_ccs_rw_copy_clear (struct xe_bo *src_bo, +enum xe_sriov_vf_ccs_rw_ctxs read_write); +struct xe_lrc *xe_migrate_lrc (struct xe_migrate *migrate);struct xe_exec_queue *xe_migrate_exec_queue (struct xe_migrate *migrate); int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
drivers/gpu/drm/xe/xe_sriov_vf_ccs.c +15 -4
@@ -148,7 +148,8 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx)xe_sriov_info (xe,"Allocating %s CCS BB pool size = %lldMB\n" , ctx->ctx_id ?"Restore" :"Save" , bb_pool_size /SZ_1M ); - sa_manager =xe_sa_bo_manager_init (tile, bb_pool_size,SZ_16 ); + sa_manager =__xe_sa_bo_manager_init (tile, bb_pool_size,SZ_4K ,SZ_16 , +XE_SA_BO_MANAGER_FLAG_SHADOW );if (IS_ERR (sa_manager)) { xe_sriov_err(xe, "Suballocator init failed with error: %pe\n",
@@ -314,6 +315,18 @@ int xe_sriov_vf_ccs_init(struct xe_device *xe)return err; } +#define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) +void xe_sriov_vf_ccs_rw_update_bb_addr (struct xe_sriov_vf_ccs_ctx *ctx) +{ +u64 addr =xe_sa_manager_gpu_addr (ctx->mem.ccs_bb_pool); +struct xe_lrc *lrc =xe_exec_queue_lrc (ctx->mig_q); +struct xe_device *xe =gt_to_xe (ctx->mig_q->gt); + +xe_device_wmb (xe); +xe_map_wr (xe, &lrc->bo->vmap,XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET , u32, addr); +xe_device_wmb (xe); +} +/** * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO. * @bo: the &buffer object to which batch buffer commands will be added.
@@ -374,9 +387,7 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo)if (!bb)continue ; -memset (bb->cs,MI_NOOP , bb->len *sizeof (u32)); -xe_bb_free (bb,NULL ); - bo->bb_ccs[ctx_id] =NULL ; +xe_migrate_ccs_rw_copy_clear (bo, ctx_id); }return 0 ; }
drivers/gpu/drm/xe/xe_sriov_vf_ccs.h +1 -0
@@ -19,6 +19,7 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo);int xe_sriov_vf_ccs_detach_bo (struct xe_bo *bo);int xe_sriov_vf_ccs_register_context (struct xe_device *xe);void xe_sriov_vf_ccs_print (struct xe_device *xe,struct drm_printer *p); +void xe_sriov_vf_ccs_rw_update_bb_addr (struct xe_sriov_vf_ccs_ctx *ctx);static inline bool xe_sriov_vf_ccs_ready (struct xe_device *xe) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 127/675 drm/xe/vf: Fix VF CCS attach/detach race with in-flight BO moves
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <[email protected]>
[ Upstream commit 56441f9e08ad68697295b8835266d2bc48ab59b5 ]
xe_bo_move() attaches VF CCS read/write batch buffers (BBs) to a BO after it transitions NULL/SYSTEM -> TT, and detaches them after it transitions TT -> SYSTEM. Both operations were done synchronously on the CPU immediately after building the move's copy/clear fence, without waiting for that fence to signal. This creates two races with VF migration:
- Attach happens too late relative to the copy job it is meant to protect. If the copy job is submitted before the CCS BBs are attached, a VF migration event that pauses execution mid-copy can observe partially copied CCS metadata without the attach state needed to correctly save/restore it.
- Detach happens too early relative to the copy job that moves data out of TT. The CCS BBs are torn down right after the copy fence is obtained, while the actual blit may still be in flight. A VF migration event that pauses execution mid-copy can then race the save/restore path against the still-running blit, and the CCS BBs it would need to make sense of the paused state have already been removed.
Fix both races:
- Move the attach call to before the copy/clear job is submitted, so the CCS BBs are already registered by the time the copy runs. On attach failure, unwind and bail out of the move. xe_migrate_ccs_rw_copy() now takes the destination resource explicitly, since bo->ttm.resource is not updated to the new resource until after the move commits.
- Detach only after explicitly waiting for the copy fence to signal, instead of tearing down the CCS BBs immediately after obtaining it.
While here, also fix xe_sriov_vf_ccs_attach_bo() to properly unwind and propagate errors: the per-context loop previously never broke out on error, silently discarding earlier failures. Unwind by clearing each attached context directly via xe_migrate_ccs_rw_copy_clear() instead of reusing xe_sriov_vf_ccs_detach_bo(), which requires both contexts to be attached before it will clean up either one.
--- drivers/gpu/drm/xe/xe_bo.c | 34 +++++++++++++++++++--------- drivers/gpu/drm/xe/xe_migrate.c | 5 +++- drivers/gpu/drm/xe/xe_migrate.h | 1 + drivers/gpu/drm/xe/xe_sriov_vf_ccs.c | 20 ++++++++++++++-- drivers/gpu/drm/xe/xe_sriov_vf_ccs.h | 3 ++- 5 files changed, 48 insertions(+), 15 deletions(-)
drivers/gpu/drm/xe/xe_bo.c +23 -11
@@ -930,6 +930,21 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,xe_pm_runtime_get_noresume (xe); } +/* +* Attach CCS BBs before submitting the copy job below so a VF +* migration racing the copy sees valid, up to date attach state. +*/ +if (IS_VF_CCS_READY (xe) && + ((move_lacks_source && new_mem->mem_type ==XE_PL_TT ) || + (old_mem_type ==XE_PL_SYSTEM && new_mem->mem_type ==XE_PL_TT )) && + handle_system_ccs) { + ret =xe_sriov_vf_ccs_attach_bo (bo, new_mem); +if (ret) { +xe_pm_runtime_put (xe); + goto out; + } + } +if (move_lacks_source) {u32 flags =0 ;
@@ -967,22 +982,19 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,ttm_bo_move_null (ttm_bo, new_mem); } -dma_fence_put (fence); -xe_pm_runtime_put (xe); -/* -* CCS meta data is migrated from TT -> SMEM. So, let us detach the -* BBs from BO as it is no longer needed. +* Detach must wait for the copy above to complete: a VF migration +* racing an in-flight copy must still see valid CCS BBs, so don't +* tear them down until the copy fence has signaled. */ if (IS_VF_CCS_READY (xe) && old_mem_type ==XE_PL_TT && - new_mem->mem_type ==XE_PL_SYSTEM ) + new_mem->mem_type ==XE_PL_SYSTEM ) { +dma_fence_wait (fence, false);xe_sriov_vf_ccs_detach_bo (bo); + } -if (IS_VF_CCS_READY (xe) && - ((move_lacks_source && new_mem->mem_type ==XE_PL_TT ) || - (old_mem_type ==XE_PL_SYSTEM && new_mem->mem_type ==XE_PL_TT )) && - handle_system_ccs) - ret =xe_sriov_vf_ccs_attach_bo (bo); +dma_fence_put (fence); +xe_pm_runtime_put (xe); out: if ((!ttm_bo->resource || ttm_bo->resource->mem_type == XE_PL_SYSTEM) &&
drivers/gpu/drm/xe/xe_migrate.c +4 -1
@@ -1001,6 +1001,8 @@ static int emit_flush_invalidate(struct xe_exec_queue *q, u32 *dw, int i,* @tile: Tile whose migration context to be used. * @q : Execution to be used along with migration context. * @src_bo: The buffer object @src is currently bound to. +* @new_mem: The (not yet committed) destination resource @src_bo is being +* moved into; src_bo->ttm.resource is still the old resource. * @read_write : Creates BB commands for CCS read/write. * * Creates batch buffer instructions to copy CCS metadata from CCS pool to
@@ -1012,12 +1014,13 @@ static int emit_flush_invalidate(struct xe_exec_queue *q, u32 *dw, int i,*/ int xe_migrate_ccs_rw_copy (struct xe_tile *tile,struct xe_exec_queue *q,struct xe_bo *src_bo, +struct ttm_resource *new_mem,enum xe_sriov_vf_ccs_rw_ctxs read_write) {bool src_is_pltt = read_write ==XE_SRIOV_VF_CCS_READ_CTX ;bool dst_is_pltt = read_write ==XE_SRIOV_VF_CCS_WRITE_CTX ; -struct ttm_resource *src = src_bo->ttm.resource; +struct ttm_resource *src = new_mem;struct xe_migrate *m = tile->migrate;struct xe_gt *gt = tile->primary_gt;u32 batch_size, batch_size_allocated;
drivers/gpu/drm/xe/xe_migrate.h +1 -0
@@ -129,6 +129,7 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m,int xe_migrate_ccs_rw_copy (struct xe_tile *tile,struct xe_exec_queue *q,struct xe_bo *src_bo, +struct ttm_resource *new_mem,enum xe_sriov_vf_ccs_rw_ctxs read_write); void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo,
drivers/gpu/drm/xe/xe_sriov_vf_ccs.c +18 -2
@@ -330,6 +330,8 @@ void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx)/** * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO. * @bo: the &buffer object to which batch buffer commands will be added. +* @new_mem: the (not yet committed) destination resource @bo is being moved +* into; bo->ttm.resource is still the old resource at this point. * * This function shall be called only by VF. It inserts the PTEs and copy * command instructions in the BO by calling xe_migrate_ccs_rw_copy()
@@ -337,7 +339,7 @@ void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx)* * Returns: 0 if successful, negative error code on failure. */ -int xe_sriov_vf_ccs_attach_bo (struct xe_bo *bo) +int xe_sriov_vf_ccs_attach_bo (struct xe_bo *bo,struct ttm_resource *new_mem) {struct xe_device *xe =xe_bo_device (bo);enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
@@ -356,7 +358,21 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo)xe_assert (xe, !bb); ctx = &xe->sriov.vf.ccs.contexts[ctx_id]; - err =xe_migrate_ccs_rw_copy (tile, ctx->mig_q, bo, ctx_id); + err =xe_migrate_ccs_rw_copy (tile, ctx->mig_q, bo, new_mem, ctx_id); +if (err) + goto err_unwind; + } +return 0 ; + +err_unwind: +/* +* Clean up any contexts already attached. Can't reuse +* xe_sriov_vf_ccs_detach_bo() here as it requires both contexts +* attached before cleaning up either one. +*/ +for_each_ccs_rw_ctx (ctx_id) { +if (bo->bb_ccs[ctx_id]) +xe_migrate_ccs_rw_copy_clear (bo, ctx_id); }return err; }
drivers/gpu/drm/xe/xe_sriov_vf_ccs.h +2 -1
@@ -11,11 +11,12 @@#include "xe_sriov_vf_ccs_types.h" struct drm_printer ; +struct ttm_resource ;struct xe_device ;struct xe_bo ;int xe_sriov_vf_ccs_init (struct xe_device *xe); -int xe_sriov_vf_ccs_attach_bo (struct xe_bo *bo); +int xe_sriov_vf_ccs_attach_bo (struct xe_bo *bo,struct ttm_resource *new_mem);int xe_sriov_vf_ccs_detach_bo (struct xe_bo *bo);int xe_sriov_vf_ccs_register_context (struct xe_device *xe);void xe_sriov_vf_ccs_print (struct xe_device *xe,struct drm_printer *p);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 128/675 drm/xe/wopcm: fix WOPCM size for LNL+
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniele Ceraolo Spurio <[email protected]>
[ Upstream commit ad87e2476b3b246580f407afc8ffa91d621bc849 ]
Starting on LNL the WOPCM size is 8MB instead of 4, so we need to avoid using the [0, 8MB) range of the GGTT as that can be unaccessible from the microcontrollers.
Note that the proper long-term fix here is to read the WOPCM size from the HW, but that is a more serious rework that would be difficult to backport, so we can do that as a follow-up.
--- drivers/gpu/drm/xe/xe_wopcm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/xe_wopcm.c +10 -5
@@ -49,9 +49,9 @@*/ /* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */ -/* FIXME: Larger size require for 2 tile PVC, do a proper probe sooner or later */ +/* FIXME: Larger size require for some platforms, do a proper probe sooner or later */ #define DGFX_WOPCM_SIZE SZ_4M -/* FIXME: Larger size require for MTL, do a proper probe sooner or later */ +#define LNL_WOPCM_SIZE SZ_8M#define MTL_WOPCM_SIZE SZ_4M#define WOPCM_SIZE SZ_2M
@@ -181,9 +181,14 @@ static int __wopcm_init_regs(struct xe_device *xe, struct xe_gt *gt,u32 xe_wopcm_size (struct xe_device *xe) { -return IS_DGFX (xe) ?DGFX_WOPCM_SIZE : - xe->info.platform ==XE_METEORLAKE ?MTL_WOPCM_SIZE : -WOPCM_SIZE ; +if (xe->info.platform >=XE_LUNARLAKE ) +return LNL_WOPCM_SIZE ; +else if (IS_DGFX (xe)) +return DGFX_WOPCM_SIZE ; +else if (xe->info.platform ==XE_METEORLAKE ) +return MTL_WOPCM_SIZE ; +else +return WOPCM_SIZE ; }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 129/675 ksmbd: pin conn during async oplock break notification
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qihang <[email protected]>
[ Upstream commit aa5d8f3f96aa11a4a54ce993c11ce8af11c546f9 ]
smb2_oplock_break_noti() and smb2_lease_break_noti() store a ksmbd_conn pointer in an async ksmbd_work and then queue that work on ksmbd-io. The work only increments conn->r_count, which prevents teardown from passing the pending-request wait after the increment, but it does not pin the struct ksmbd_conn object.
If connection teardown races with an oplock break notification, the last conn reference can be dropped before the queued worker finishes. The worker then uses the freed conn in ksmbd_conn_write() and ksmbd_conn_r_count_dec().
Take a real conn reference when publishing the conn pointer to the async work item, and drop it after the notification work has decremented r_count. Apply the same lifetime rule to lease break notification, which uses the same work->conn pattern.
--- fs/smb/server/oplock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/smb/server/oplock.c +4 -2
@@ -705,6 +705,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) out:ksmbd_free_work_struct (work);ksmbd_conn_r_count_dec (conn); +ksmbd_conn_put (conn); }/**
@@ -740,7 +741,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo) br_info->open_trunc = opinfo->open_trunc; work->request_buf = (char *)br_info; - work->conn = conn; + work->conn =ksmbd_conn_get (conn); work->sess = opinfo->sess;ksmbd_conn_r_count_inc (conn);
@@ -814,6 +815,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk) out:ksmbd_free_work_struct (work);ksmbd_conn_r_count_dec (conn); +ksmbd_conn_put (conn); }/**
@@ -853,7 +855,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)memcpy (br_info->lease_key, lease->lease_key,SMB2_LEASE_KEY_SIZE ); work->request_buf = (char *)br_info; - work->conn = conn; + work->conn =ksmbd_conn_get (conn); work->sess = opinfo->sess;ksmbd_conn_r_count_inc (conn);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 130/675 ksmbd: validate compound request size before reading StructureSize2
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit 15b38176fd1530372905c602fde51fe89ec8c877 ]
When ksmbd validates a compound (chained) SMB2 request, ksmbd_smb2_check_message() reads pdu->StructureSize2 without first checking that the compound element is large enough to contain it. StructureSize2 is a 2-byte field at offset 64 (__SMB2_HEADER_STRUCTURE_SIZE) from the start of each element.
The compound-walking logic only guarantees that a full 64-byte SMB2 header is present for the trailing element: when NextCommand is 0, len is reduced to the number of bytes remaining after next_smb2_rcv_hdr_off. A remote client can craft a compound request whose last element has exactly 64 bytes, so the 2-byte StructureSize2 read at offset 64 extends one byte past the receive buffer, producing a slab-out-of-bounds read.
BUG: KASAN: slab-out-of-bounds in ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402) Read of size 2 at addr ffff888012ae31ac by task kworker/0:1/14 The buggy address is located 172 bytes inside of allocated 173-byte region Workqueue: ksmbd-io handle_ksmbd_work Call Trace: ... kasan_report (mm/kasan/report.c:595) ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402) handle_ksmbd_work (fs/smb/server/server.c:119) process_one_work (kernel/workqueue.c:3314) worker_thread (kernel/workqueue.c:3397) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:158) ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
Reject any compound element that is too small to hold StructureSize2 before dereferencing it.
--- fs/smb/server/smb2misc.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/smb/server/smb2misc.c +5 -0
@@ -400,6 +400,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)return 1 ; } +if (len < __SMB2_HEADER_STRUCTURE_SIZE +sizeof (__le16)) { +ksmbd_debug (SMB ,"Message is too small for StructureSize2\n" ); +return 1 ; + } +if (smb2_req_struct_sizes[command] != pdu->StructureSize2) { if (!(command == SMB2_OPLOCK_BREAK_HE && (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 131/675 drm/i915/wm: clear the plane ddb_y entries on plane disable
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinod Govindapillai <[email protected]>
[ Upstream commit e89978c1cff54e265345c66e1177d19ea5a8bc00 ]
The UV/Y plane DDB entriess are never cleared on sk_wm_plane_disable_noatomic() and can leave stale DDB state for NV12 planes on pre-Gen11 devices
--- drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/display/skl_watermark.c +1 -1
@@ -3815,7 +3815,7 @@ void skl_wm_plane_disable_noatomic(struct intel_crtc *crtc,return ;skl_ddb_entry_init (&crtc_state->wm.skl.plane_ddb[plane->id],0 ,0 ); -skl_ddb_entry_init (&crtc_state->wm.skl.plane_ddb[plane->id],0 ,0 ); +skl_ddb_entry_init (&crtc_state->wm.skl.plane_ddb_y[plane->id],0 ,0 ); crtc_state->wm.skl.plane_min_ddb[plane->id] =0 ; crtc_state->wm.skl.plane_interim_ddb[plane->id] =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 132/675 drm/i915/selftests: Fix GT PM sort comparators
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emre Cecanpunar <[email protected]>
[ Upstream commit 612978b83f45bf7018815209db5395d759db6f26 ]
Compare the sampled clock values instead of their addresses. Comparing addresses leaves the samples unsorted, preventing the code from discarding the minimum and maximum samples.
--- drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/gt/selftest_gt_pm.c +4 -4
@@ -16,9 +16,9 @@ static int cmp_u64(const void *A, const void *B) {const u64 *a =A , *b =B ; -if (a < b) +if (*a < *b)return -1 ; -else if (a > b) +else if (*a > *b)return 1 ;else return 0 ;
@@ -28,9 +28,9 @@ static int cmp_u32(const void *A, const void *B) {const u32 *a =A , *b =B ; -if (a < b) +if (*a < *b)return -1 ; -else if (a > b) +else if (*a > *b)return 1 ;else return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 133/675 accel/amdxdna: Fix use-after-free of mm_struct in job scheduler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lizhi Hou <[email protected]>
[ Upstream commit faebb7ba1ac65fa5810b640df02ce04e509fdc11 ]
amdxdna_cmd_submit() stores current->mm in job->mm without holding any reference. aie2_sched_job_run() later access job->mm from the DRM scheduler worker thread. With only a raw pointer and no structural reference, the mm_struct can be freed before the scheduler runs the job.
Fix this by calling mmgrab() to hold a structural mm_count reference for the lifetime of the job, paired with mmdrop() in every cleanup path.
--- drivers/accel/amdxdna/amdxdna_ctx.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/accel/amdxdna/amdxdna_ctx.c +4 -0
@@ -393,6 +393,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)amdxdna_arg_bos_put (job);amdxdna_gem_put_obj (job->cmd_bo);dma_fence_put (job->fence); +mmdrop (job->mm); } int amdxdna_cmd_submit(struct amdxdna_client *client,
@@ -443,6 +444,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, job->hwctx = hwctx; job->mm = current->mm; +mmgrab (job->mm); job->fence =amdxdna_fence_create (hwctx);if (!job->fence) {
@@ -475,6 +477,8 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, cmd_put:amdxdna_gem_put_obj (job->cmd_bo); free_job: +if (job->mm) +mmdrop (job->mm);kfree (job);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 134/675 tcp: fix TIME_WAIT socket reference leak on PSP policy failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 2c1931a81122c3cdc4c89448fe0442c69e21c0d5 ]
Release the TIME_WAIT socket reference and jump to discard_it upon PSP policy failure in both IPv4 and IPv6 receive paths. This prevents a memory leak of tcp_tw_bucket structures.
--- net/ipv4/tcp_ipv4.c | 6 ++++-- net/ipv6/tcp_ipv6.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-)
net/ipv4/tcp_ipv4.c +4 -2
@@ -2452,8 +2452,10 @@ int tcp_v4_rcv(struct sk_buff *skb) } drop_reason =psp_twsk_rx_policy_check (inet_twsk (sk), skb); -if (drop_reason) -break ; +if (drop_reason) { +inet_twsk_put (inet_twsk (sk)); + goto discard_it; + } }/* to ACK */ fallthrough;
net/ipv6/tcp_ipv6.c +4 -2
@@ -1984,8 +1984,10 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) } drop_reason =psp_twsk_rx_policy_check (inet_twsk (sk), skb); -if (drop_reason) -break ; +if (drop_reason) { +inet_twsk_put (inet_twsk (sk)); + goto discard_it; + } }/* to ACK */ fallthrough;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 135/675 dpll: fix NULL pointer dereference in dpll_msg_add_pin_ref_sync()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Vecera <[email protected]>
[ Upstream commit d2e914a4a0d0f753dbae830264850d044026167c ]
When a dpll_pin is shared across multiple dpll_device instances and those devices are being unregistered (e.g. during driver module removal), a NULL pointer dereference can occur in dpll_msg_add_pin_ref_sync().
This happens under the following conditions:
- A pin is registered with two or more dpll devices (dpll_A, dpll_B)
- The pin has ref_sync pairs with other pins
- During unregistration of dpll_A's pins, a ref_sync partner pin is unregistered first, removing it from dpll_A->pin_refs
- But since the partner pin is still registered with dpll_B, its dpll_refs is not empty, so dpll_pin_ref_sync_pair_del() does NOT run and the partner stays in the pin's ref_sync_pins xarray
- When the pin itself is then unregistered from dpll_A, the delete notification calls dpll_msg_add_pin_ref_sync() which finds the partner in ref_sync_pins, passes dpll_pin_available() (partner is still registered with dpll_B), but dpll_pin_on_dpll_priv(dpll_A, partner) returns NULL because partner was already removed from dpll_A->pin_refs
- The NULL priv pointer is passed to the driver's ref_sync_get callback, which dereferences it
BUG: kernel NULL pointer dereference, address: 0000000000000034 Oops: Oops: 0000 [#1] SMP NOPTI RIP: 0010:zl3073x_dpll_input_pin_ref_sync_get+0x73/0x80 [zl3073x] Call Trace: dpll_msg_add_pin_ref_sync+0xb8/0x200 dpll_cmd_pin_get_one+0x3b6/0x4b0 dpll_pin_event_send+0x72/0x140 __dpll_pin_unregister+0x5a/0x2b0 dpll_pin_unregister+0x49/0x70
Fix this by skipping ref_sync pins whose priv pointer cannot be resolved for the current dpll device.
--- drivers/dpll/dpll_netlink.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/dpll/dpll_netlink.c +3 -0
@@ -486,6 +486,9 @@ dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin,if (!dpll_pin_available (ref_sync_pin))continue ; ref_sync_pin_priv =dpll_pin_on_dpll_priv (dpll, ref_sync_pin); +/* Pin may have been unregistered from this dpll already */ +if (!ref_sync_pin_priv) +continue ;if (WARN_ON (!ops->ref_sync_get))return -EOPNOTSUPP ; ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 136/675 net/sched: act_tunnel_key: Defer dst_release to RCU callback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit f1f5c8a3955f8fda3f84ed883ac8daa1847e724c ]
Fix a race-condition use-after-free in tunnel_key_release_params().
The function releases the metadata_dst of the old params synchronously via dst_release() while deferring the params struct free with kfree_rcu(). A concurrent tunnel_key_act() reader on the datapath may still hold the old params pointer (under rcu_read_lock_bh) and proceed to call dst_clone(¶ms->tcft_enc_metadata->dst) after the writer's dst_release has already pushed the dst's rcuref to RCUREF_DEAD.
[email protected] produced a poc which i (and Victor) verified that KASAN reports:
==================================================================
BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 BUG: KASAN: slab-use-after-free in atomic_sub_return_release include/linux/atomic/atomic-instrumented.h:326 BUG: KASAN: slab-use-after-free in __rcuref_put include/linux/rcuref.h:109 BUG: KASAN: slab-use-after-free in rcuref_put include/linux/rcuref.h:173 BUG: KASAN: slab-use-after-free in dst_release+0x5b/0x370 net/core/dst.c:168 Write of size 4 at addr ffff88806158de40 by task poc/9388 CPU: 0 UID: 0 PID: 9388 Comm: poc Tainted: G W 7.1.0-rc7 #7 PREEMPT(lazy) Tainted: [W]=WARN Hardware name: QEMU Ubuntu 25.10 PC v2 (i440FX + PIIX, + 10.1 machine, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 print_report+0x139/0x4ad mm/kasan/report.c:482 kasan_report+0xe4/0x1d0 mm/kasan/report.c:595 check_region_inline mm/kasan/generic.c:186 kasan_check_range+0x125/0x200 mm/kasan/generic.c:200 instrument_atomic_read_write include/linux/instrumented.h:112 atomic_sub_return_release include/linux/atomic/atomic-instrumented.h:326 __rcuref_put include/linux/rcuref.h:109 rcuref_put include/linux/rcuref.h:173 dst_release+0x5b/0x370 net/core/dst.c:168 refdst_drop include/net/dst.h:272 skb_dst_drop include/net/dst.h:284 skb_release_head_state+0x293/0x400 net/core/skbuff.c:1163 skb_release_all net/core/skbuff.c:1187 [..] Allocated by task 9391: kasan_save_stack+0x30/0x50 mm/kasan/common.c:57 kasan_save_track+0x14/0x30 mm/kasan/common.c:78 poison_kmalloc_redzone mm/kasan/common.c:398 __kasan_kmalloc+0x9a/0xb0 mm/kasan/common.c:415 kasan_kmalloc include/linux/kasan.h:263 __do_kmalloc_node mm/slub.c:5296 __kmalloc_noprof+0x2f1/0x830 mm/slub.c:5308 kmalloc_noprof include/linux/slab.h:954 kzalloc_noprof include/linux/slab.h:1188 offload_action_alloc+0x2f/0x130 net/core/flow_offload.c:35 tcf_action_offload_add_ex+0x1ba/0x880 net/sched/act_api.c:258 tcf_action_offload_add net/sched/act_api.c:293 tcf_action_init+0x66e/0xa20 net/sched/act_api.c:1547 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101 [..] Freed by task 9391: kasan_save_stack+0x30/0x50 mm/kasan/common.c:57 kasan_save_track+0x14/0x30 mm/kasan/common.c:78 kasan_save_free_info+0x3b/0x70 mm/kasan/generic.c:584 poison_slab_object mm/kasan/common.c:253 __kasan_slab_free+0x6b/0x90 mm/kasan/common.c:285 kasan_slab_free include/linux/kasan.h:235 slab_free_hook mm/slub.c:2689 slab_free mm/slub.c:6251 kfree+0x21f/0x6b0 mm/slub.c:6566 tcf_action_offload_add_ex+0x4ad/0x880 net/sched/act_api.c:284 tcf_action_offload_add net/sched/act_api.c:293 tcf_action_init+0x66e/0xa20 net/sched/act_api.c:1547 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101 The buggy address belongs to the object at ffff88806158de00 which belongs to the cache kmalloc-256 of size 256
The buggy address is located 64 bytes inside of
freed 256-byte region [ffff88806158de00, ffff88806158df00)
The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff88806158d600 pfn:0x6158c head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 flags: 0x4fff00000000240(workingset|head|node=1|zone=1|lastcpupid=0x7ff) page_type: f5(slab) raw: 04fff00000000240 ffff88801c841b40 ffffea0001856290 ffffea0001856190 raw: ffff88806158d600 0000000800100009 00000000f5000000 0000000000000000
head: 04fff00000000240 ffff88801c841b40 ffffea0001856290 ffffea0001856190
head: ffff88806158d600 0000000800100009 00000000f5000000 0000000000000000
head: 04fff00000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002
page dumped because: kasan: bad access detected page_owner tracks the page as allocated page last allocated via order 1, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 9391, tgid 9378 (poc), ts 123227323196, free_ts 0 set_page_owner include/linux/page_owner.h:32 post_alloc_hook+0xfe/0x140 mm/page_alloc.c:1853 prep_new_page mm/page_alloc.c:1861 get_page_from_freelist+0x110c/0x2fc0 mm/page_alloc.c:3941 __alloc_frozen_pages_noprof+0x263/0x2bc0 mm/page_alloc.c:5221 alloc_slab_page mm/slub.c:3278 allocate_slab mm/slub.c:3467 new_slab+0xa6/0x690 mm/slub.c:3525 refill_objects+0x271/0x420 mm/slub.c:7272 refill_sheaf mm/slub.c:2816 __pcs_replace_empty_main+0x373/0x630 mm/slub.c:4652 alloc_from_pcs mm/slub.c:4750 slab_alloc_node mm/slub.c:4884 __do_kmalloc_node mm/slub.c:5295 __kmalloc_noprof+0x66d/0x830 mm/slub.c:5308 kmalloc_noprof include/linux/slab.h:954 metadata_dst_alloc+0x26/0x90 net/core/dst.c:298 tun_rx_dst include/net/dst_metadata.h:144 __ip_tun_set_dst include/net/dst_metadata.h:208 tunnel_key_init+0xb01/0x1b90 net/sched/act_tunnel_key.c:451 tcf_action_init_1+0x46b/0x6c0 net/sched/act_api.c:1428 tcf_action_init+0x448/0xa20 net/sched/act_api.c:1503 tcf_action_add+0xf6/0x5d0 net/sched/act_api.c:2101
[..]
==================================================================
Fix by moving dst_release() into a custom RCU callback that runs after the grace period, matching the lifetime of the containing params struct. Readers in the datapath therefore always find a live rcuref when calling dst_clone().
--- net/sched/act_tunnel_key.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
net/sched/act_tunnel_key.c +10 -4
@@ -342,14 +342,20 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = { [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 }, }; -static void tunnel_key_release_params (struct tcf_tunnel_key_params *p) +static void tunnel_key_release_params_rcu (struct rcu_head *head) { -if (!p) -return ; +struct tcf_tunnel_key_params *p =container_of (head,typeof (*p), rcu); +if (p->tcft_action ==TCA_TUNNEL_KEY_ACT_SET )dst_release (&p->tcft_enc_metadata->dst); +kfree (p); +} -kfree_rcu (p, rcu); +static void tunnel_key_release_params (struct tcf_tunnel_key_params *p) +{ +if (!p) +return ; +call_rcu (&p->rcu, tunnel_key_release_params_rcu); } static int tunnel_key_init(struct net *net, struct nlattr *nla,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 137/675 sctp: fix auth_hmacs array size in struct sctp_cookie
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit e0b5252a59383b77d1b8dbeda00b7184dd95f4d3 ]
The auth_hmacs array in struct sctp_cookie is supposed to store a complete SCTP_AUTH_HMAC_ALGO parameter, which consists of a struct sctp_paramhdr followed by N HMAC identifiers.
However, the array size was calculated using an extra 2 bytes instead of sizeof(struct sctp_paramhdr), which is 4 bytes. When four HMAC identifiers are configured, the HMAC-ALGO parameter stored in the endpoint is larger than the auth_hmacs buffer in the cookie.
As a result, sctp_association_init() copies beyond the end of auth_hmacs when initializing the association, corrupting the adjacent auth_chunks field. This can lead to an invalid HMAC identifier being accepted and later cause an out-of-bounds read in sctp_auth_get_hmac().
Fix the array size calculation by including the full SCTP parameter header size.
--- include/net/sctp/structs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/net/sctp/structs.h +2 -1
@@ -316,7 +316,8 @@ struct sctp_cookie {__u8 auth_random[sizeof (struct sctp_paramhdr ) +SCTP_AUTH_RANDOM_LENGTH ]; -__u8 auth_hmacs[SCTP_AUTH_NUM_HMACS *sizeof (__u16) +2 ]; +__u8 auth_hmacs[sizeof (struct sctp_paramhdr ) + +SCTP_AUTH_NUM_HMACS *sizeof (__u16)];__u8 auth_chunks[sizeof (struct sctp_paramhdr ) +SCTP_AUTH_MAX_CHUNKS ];/* This is a shim for my peer's INIT packet, followed by
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 138/675 mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 56d96fededd61192cd7cc8d2b0f36adfd59036c3 ]
On CONFIG_INET=n builds, mpls_valid_fib_dump_req() walks the parsed attribute table itself instead of calling ip_valid_fib_dump_req(). The RTA_OIF arm passes tb[RTA_OIF] to nla_get_u32() without checking it is present, so an RTM_GETROUTE dump for AF_MPLS with strict checking and no RTA_OIF hits a NULL dereference.
RTM_GETROUTE is RTNL_KIND_GET, which rtnetlink_rcv_msg() permits without CAP_NET_ADMIN, so an unprivileged user can trigger it.
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
RIP: 0010:mpls_valid_fib_dump_req (net/mpls/af_mpls.c:2189)
Call Trace:
mpls_dump_routes (net/mpls/af_mpls.c:2236)
netlink_dump (net/netlink/af_netlink.c:2331)
__netlink_dump_start (net/netlink/af_netlink.c:2446)
rtnetlink_rcv_msg (net/core/rtnetlink.c:7033)
netlink_rcv_skb (net/netlink/af_netlink.c:2556)
netlink_unicast (net/netlink/af_netlink.c:1345)
netlink_sendmsg (net/netlink/af_netlink.c:1900)
__sock_sendmsg (net/socket.c:790)
____sys_sendmsg (net/socket.c:2684)
___sys_sendmsg (net/socket.c:2738)
__sys_sendmsg (net/socket.c:2770)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)Skip unset attributes, as ip_valid_fib_dump_req() does.
--- net/mpls/af_mpls.c | 3 +++ 1 file changed, 3 insertions(+)
net/mpls/af_mpls.c +3 -0
@@ -2123,6 +2123,9 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,int ifindex;if (i ==RTA_OIF ) { +if (!tb[i]) +continue ; + ifindex =nla_get_u32 (tb[i]); filter->dev =__dev_get_by_index (net, ifindex);if (!filter->dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 139/675 usb: core: sysfs: add lock to bos_descriptors_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit 4e0197fbb0eec588795d5431716a244d9ac8fa93 upstream.
Add a lock to the function bos_descriptors_read().
This function accesses udev->bos, which could be simultaneously freed in usb_reset_and_verify_device(), a function that is commonly called in drivers all over the kernel.
--- drivers/usb/core/sysfs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/usb/core/sysfs.c +7 -1
@@ -899,10 +899,15 @@ bos_descriptors_read(struct file *filp, {struct device *dev =kobj_to_dev (kobj);struct usb_device *udev =to_usb_device (dev); -struct usb_host_bos *bos = udev->bos; +struct usb_host_bos *bos;struct usb_bos_descriptor *desc;size_t desclen, n =0 ; +int rc; + rc =usb_lock_device_interruptible (udev); +if (rc <0 ) +return -EINTR ; + bos = udev->bos;if (bos) { desc = bos->desc; desclen =le16_to_cpu (desc->wTotalLength);
@@ -911,6 +916,7 @@ bos_descriptors_read(struct file *filp,memcpy (buf, (void *) desc + off, n); } } +usb_unlock_device (udev);return n; } static const BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */
Greg Kroah-Hartman
maintainerPATCH 140/675 wifi: at76c50x-usb: avoid length underflow in at76_guess_freq()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huihui Huang <[email protected]>
commit 61a799ffd1e5a4fd3702d547828b7ff3d161468e upstream.
at76_guess_freq() checks only that the received frame is at least a bare 802.11 header (24 bytes) before subtracting the fixed management-body offset:
len -= el_off;
For both beacon and probe response frames, el_off is 36. If the frame is shorter than el_off, subtracting it causes the calculated IE length to wrap. The length is eventually passed to cfg80211_find_elem_match() as a very large unsigned value, so the element walk runs beyond the RX skb.
This path is reached from at76_rx_tasklet() while scanning. If the device delivers a truncated beacon or probe response, the oversized IE length causes an out-of-bounds read during scanning.
Skip the IE lookup if the frame does not reach the variable elements, before subtracting el_off.
--- drivers/net/wireless/atmel/at76c50x-usb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/wireless/atmel/at76c50x-usb.c +5 -2
@@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(structif (ieee80211_is_probe_resp (hdr->frame_control)) { el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable; }else if (ieee80211_is_beacon (hdr->frame_control)) { el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable); - el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable; }else { goto exit; } + +if (len < el_off) + goto exit; + + el = priv->rx_skb->data + el_off; len -= el_off; el =cfg80211_find_ie (WLAN_EID_DS_PARAMS , el, len);
Greg Kroah-Hartman
maintainerPATCH 141/675 usb: core: port: Deattach Type-C connector on component unbind
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chia-Lin Kao (AceLan) <[email protected]>
commit e0b291fe117964037e0ba382eff4bb365d531c3a upstream.
connector_unbind() is the mirror of connector_bind(), but it is missing the symmetric call to typec_deattach() that connector_bind() makes via:
if (port_dev->child)
typec_attach(port_dev->connector, &port_dev->child->dev);When a Thunderbolt dock is unplugged, two teardown paths race:
1. The component framework calls connector_unbind() first, which sets port_dev->connector = NULL without calling typec_deattach(). This leaves port->usb2_dev/port->usb3_dev in struct typec_port pointing at the USB device that is about to be freed.
2. usb_disconnect() then calls typec_deattach(port_dev->connector, ...), but port_dev->connector is already NULL, so the call is a no-op and port->usb2_dev is never cleared.
3. Concurrently, UCSI detects a PD partner-disconnect event and calls typec_unregister_partner(), which reads port->usb2_dev (now a dangling pointer to freed memory) and passes it to typec_partner_unlink_device() -> sysfs_remove_link() -> dev_name() on the freed device, corrupting the typec/UCSI partner state.
This corruption leaves the Thunderbolt tunnel in an inconsistent state on the next dock hot-plug. On affected hardware the dock's I225/igc NIC fails to enumerate: AER fires a slot reset while the igc driver is still initialising ("PCIe link lost"), and the subsequent igc_reset attempt hits igc_rd32 on an already-detached device:
igc 0000:2e:00.0 eth0: PCIe link lost, device now detached
igc: Failed to read reg 0x0!
WARNING: CPU: 9 PID: 129 at drivers/net/ethernet/intel/igc/igc_main.c:7005
igc_rd32+0xa4/0xc0 [igc]
Call Trace:
igc_disable_pcie_master+0x16/0xa0 [igc]
igc_reset_hw_base+0x14/0x170 [igc]
igc_reset+0x63/0x110 [igc]
igc_io_slot_reset+0x9e/0xd0 [igc]
report_slot_reset+0x5d/0xc0
pcie_do_recovery+0x209/0x400
aer_isr_one_error_type+0x235/0x430
aer_isr+0x4e/0x80
irq_thread+0xf4/0x1f04. UCSI later handles the PD partner-disconnect and calls typec_unregister_partner(), which still sees the stale port->usb2_dev and tries to remove its sysfs link a second time:
kernfs: can not remove 'typec', no directory
WARNING: CPU: 6 PID: 55 at fs/kernfs/dir.c:1706 kernfs_remove_by_name_ns+0xe9/0xf0
Workqueue: events ucsi_handle_connector_change [typec_ucsi]
Call Trace:
sysfs_remove_link+0x19/0x50
typec_unregister_partner+0x6e/0x120 [typec]
ucsi_unregister_partner+0x107/0x150 [typec_ucsi]
ucsi_handle_connector_change+0x3ec/0x490 [typec_ucsi]
process_one_work+0x18e/0x3e0
worker_thread+0x2e3/0x420
kthread+0x10a/0x230
ret_from_fork+0x121/0x140
ret_from_fork_asm+0x1a/0x30With worse timing the same stale pointer is dereferenced after the backing memory is freed, turning the warning into a use-after-free.
Fix the asymmetry: call typec_deattach() before clearing port_dev->connector, matching what connector_bind() does on the bind side. typec_partner_deattach() is already protected by port->partner_link_lock, so it serialises safely with the concurrent typec_unregister_partner() path.
--- drivers/usb/core/port.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/core/port.c +2 -0
@@ -726,6 +726,8 @@ static void connector_unbind(struct devisysfs_remove_link (&connector->kobj,dev_name (dev));sysfs_remove_link (&dev->kobj,"connector" ); +if (port_dev->child) +typec_deattach (port_dev->connector, &port_dev->child->dev); port_dev->connector =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 142/675 usb: musb: omap2430: Do not put borrowed of_node in probe
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit c947360ae63eee1c9eacc030dd6f5a53f717addf upstream.
omap2430_probe() stores pdev->dev.of_node in a local np variable. This is a borrowed pointer and the probe function does not take a reference to it.
The success and error paths nevertheless call of_node_put(np). This drops a reference that is owned by the platform device, and can leave pdev->dev.of_node with an unbalanced reference count.
Do not put the borrowed platform device node from omap2430_probe(). References taken for the child MUSB device are handled by the device core, and the ctrl-module phandle reference is still released separately.
--- drivers/usb/musb/omap2430.c | 2 -- 1 file changed, 2 deletions(-)
drivers/usb/musb/omap2430.c +0 -2
@@ -455,7 +455,6 @@ static int omap2430_probe(struct platfordev_err (&pdev->dev,"failed to register musb device\n" ); goto err_disable_rpm; } -of_node_put (np);return 0 ;
@@ -465,7 +464,6 @@ err_put_control_otghs:if (!IS_ERR (glue->control_otghs))put_device (glue->control_otghs); err_put_musb: -of_node_put (np);platform_device_put (musb);return ret;
Greg Kroah-Hartman
maintainerPATCH 143/675 USB: storage: add NO_ATA_1X quirk for Longmai USB Key
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huang Wei <[email protected]>
commit 3b4ca2e01c1dd8c00b675b794732945f460a471b upstream.
The Longmai Technologies USB Key (0x04b4:0xb708) advertises itself as a SCSI/Bulk-only mass storage device but does not correctly handle ATA pass-through commands. When such a command (ATA_12 or ATA_16) is sent to the device it fails to respond and the transfer eventually times out, leaving the device unusable.
Add an unusual_devs entry for this device that sets the US_FL_NO_ATA_1X flag, so usb-storage short-circuits ATA pass-through commands and returns INVALID COMMAND OPERATION CODE (0x20 0x05 0x24 0x00) instead of forwarding them to the device.
Information about the device in /sys/kernel/debug/usb/devices:
T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 12 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=06 Prot=50 MxPS=64 #Cfgs= 1 P: Vendor=04b4 ProdID=b708 Rev= 1.00 S: Manufacturer=Longmai Technologies S: Product=USB Key C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/usb/storage/unusual_devs.h +7 -0
@@ -395,6 +395,13 @@ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x USB_SC_DEVICE, USB_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), +/* Reported by Ai Chao <[email protected]> */ +UNUSUAL_DEV (0x04b4 ,0xb708 ,0x0000 ,0xffff , +"Longmai Technologies" , +"USB Key" , +USB_SC_SCSI ,USB_PR_BULK ,NULL , + US_FL_NO_ATA_1X), +/* * Reported by Simon Levitt <[email protected]> * This entry needs Sub and Proto fields
Greg Kroah-Hartman
maintainerPATCH 144/675 usb: chipidea: fix usage_count leak when autosuspend_delay is negative
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
commit fc3afb5728e297994863f8a2a01b88a920bbf53e upstream.
The probe() calls pm_runtime_use_autosuspend(), but remove() does not call pm_runtime_dont_use_autosuspend(). This can lead to a usage_count leak if autosuspend_delay is set to a negative value.
The pm_runtime_use_autosuspend() also notes that it's important to undo this with pm_runtime_dont_use_autosuspend() at driver exit time.
--- drivers/usb/chipidea/core.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/chipidea/core.c +1 -0
@@ -1265,6 +1265,7 @@ static void ci_hdrc_remove(struct platfousb_role_switch_unregister (ci->role_switch);if (ci->supports_runtime_pm) { +pm_runtime_dont_use_autosuspend (&pdev->dev);pm_runtime_get_sync (&pdev->dev);pm_runtime_disable (&pdev->dev);pm_runtime_put_noidle (&pdev->dev);
Greg Kroah-Hartman
maintainerPATCH 145/675 usb: gadget: dummy_hcd: prevent fifo_req reuse during giveback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinchao Wang <[email protected]>
commit d5e5cd3654d2b5359a12ea6586120f05b28634ee upstream.
dummy_hcd embeds a single shared usb_request (dum->fifo_req) that the "emulated single-request FIFO" fast-path in dummy_queue() reuses for small IN transfers: it copies the caller's request into it (req->req = *_req) and queues it, treating list_empty(&fifo_req.queue) as "the slot is free".
The completion side (dummy_timer/transfer/nuke/dummy_dequeue) follows the standard pattern: list_del_init(&req->queue) unlinks the request, then the lock is dropped and usb_gadget_giveback_request() invokes req->complete(). But list_del_init() makes fifo_req.queue look empty *before* the completion callback returns, so a concurrent dummy_queue() on another CPU sees the slot as free, reuses fifo_req and runs req->req = *_req -- overwriting req->complete while dummy_timer is mid-calling it. The indirect call then jumps to a clobbered pointer, causing a general protection fault / page fault in dummy_timer (syzkaller extid faf3a6cf579fc65591ca). The clobbering write is an in-bounds memcpy on a live shared object, so KASAN cannot flag it.
Add a fifo_req_busy bit covering the shared request's whole lifetime:
set it in dummy_queue() when the FIFO fast-path takes fifo_req (making it the fast-path guard, replacing the list_empty(&fifo_req.queue) test), and clear it after the completion callback has returned, via a dummy_giveback() helper used at all four gadget-request giveback sites. The shared slot can no longer be reused until its completion callback has finished.
--- drivers/usb/gadget/udc/dummy_hcd.c | 40 ++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-)
drivers/usb/gadget/udc/dummy_hcd.c +27 -13
@@ -278,6 +278,7 @@ struct dummy { unsigned ints_enabled:1; unsigned udc_suspended:1; unsigned pullup:1; + unsigned fifo_req_busy:1;/* * HOST side support
@@ -329,6 +330,26 @@ static inline struct dummy *gadget_dev_t/* DEVICE/GADGET SIDE UTILITY ROUTINES */ +/* +* Give back a gadget request with dum->lock dropped around the callback. +* If @req is the shared fifo_req, clear fifo_req_busy afterward: the flag +* was set in dummy_queue() when the shared request was taken and must stay +* set until its completion callback has returned; list_del_init() alone +* makes the request look idle while the callback is still running. +* Caller holds dum->lock and has already done list_del_init() + status. +*/ +static void dummy_giveback (struct dummy *dum,struct usb_ep *_ep, +struct dummy_request *req) +{ +bool fifo = req == &dum->fifo_req; + +spin_unlock (&dum->lock); +usb_gadget_giveback_request (_ep, &req->req); +spin_lock (&dum->lock); +if (fifo) + dum->fifo_req_busy =0 ; +} +/* called with spinlock held */ static void nuke (struct dummy *dum,struct dummy_ep *ep) {
@@ -339,9 +360,7 @@ static void nuke(struct dummy *dum, strulist_del_init (&req->queue); req->req.status = -ESHUTDOWN ; -spin_unlock (&dum->lock); -usb_gadget_giveback_request (&ep->ep, &req->req); -spin_lock (&dum->lock); +dummy_giveback (dum, &ep->ep, req); } }
@@ -728,10 +747,11 @@ static int dummy_queue(struct usb_ep *_e/* implement an emulated single-request FIFO */ if (ep->desc && (ep->desc->bEndpointAddress &USB_DIR_IN ) && -list_empty (&dum->fifo_req.queue) && + !dum->fifo_req_busy &&list_empty (&ep->queue) && _req->length <=FIFO_SIZE ) { req = &dum->fifo_req; + dum->fifo_req_busy =1 ; req->req = *_req; req->req.buf = dum->fifo_buf;memcpy (dum->fifo_buf, _req->buf, _req->length);
@@ -785,9 +805,7 @@ static int dummy_dequeue(struct usb_ep *dev_dbg (udc_dev (dum),"dequeued req %p from %s, len %d buf %p\n" , req, _ep->name, _req->length, _req->buf); -spin_unlock (&dum->lock); -usb_gadget_giveback_request (_ep, _req); -spin_lock (&dum->lock); +dummy_giveback (dum, _ep, req); }spin_unlock_irqrestore (&dum->lock, flags);return retval;
@@ -1523,9 +1541,7 @@ top:if (req->req.status != -EINPROGRESS ) {list_del_init (&req->queue); -spin_unlock (&dum->lock); -usb_gadget_giveback_request (&ep->ep, &req->req); -spin_lock (&dum->lock); +dummy_giveback (dum, &ep->ep, req);/* requests might have been unlinked... */ rescan =1 ;
@@ -1910,9 +1926,7 @@ restart:dev_dbg (udc_dev (dum),"stale req = %p\n" , req); -spin_unlock (&dum->lock); -usb_gadget_giveback_request (&ep->ep, &req->req); -spin_lock (&dum->lock); +dummy_giveback (dum, &ep->ep, req); ep->already_seen =0 ; goto restart; }
Greg Kroah-Hartman
maintainerPATCH 146/675 usb: gadget: f_midi: cancel pending IN work before freeing the midi object
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 5650c18d93a1db7e27cb5a40b394747eb4686d5b upstream.
The f_midi driver embeds a work item (midi->work) whose handler, f_midi_in_work(), dereferences the enclosing struct f_midi through container_of(). This work is armed from two sites: f_midi_complete(), on a normal IN-endpoint completion, and f_midi_in_trigger(), on an ALSA rawmidi output-stream start.
Neither f_midi_disable() nor f_midi_unbind() cancels midi->work. f_midi_disable() only disables the endpoints and drains the in_req_fifo; it does not synchronize the work item, and the sound card is released asynchronously to the final free of the midi object.
The midi object is reference-counted (midi->free_ref) and is freed in f_midi_free() only once both the usb_function reference and the rawmidi private_data reference have been dropped. In f_midi_unbind(), f_midi_disable() runs before the sound card is released, so while the USB endpoints are already disabled the rawmidi device is still usable by an open substream. A concurrent userspace write on such a substream can reach f_midi_in_trigger() and queue midi->work again after f_midi_disable() has returned. A work item armed this way may still be pending when the last reference drops and f_midi_free() proceeds to kfree(midi), letting f_midi_in_work() dereference the struct after it has been freed, a use-after-free.
For this reason cancelling midi->work in f_midi_disable() would not be
sufficient: the ALSA trigger path can rearm the work after disable() returns. Cancelling at the refcount-zero free site is the boundary after which neither arming source can survive, because by then both references that keep the midi object alive have been dropped: the USB endpoints are already disabled and the rawmidi device has been released.
Fix this by calling cancel_work_sync(&midi->work) in the refcount-zero block of f_midi_free(), before the embedded work_struct is freed along with the rest of the structure. opts->lock is a sleeping mutex, so calling cancel_work_sync() under it is permitted, and the handler takes midi->transmit_lock rather than opts->lock, so no self-deadlock can occur while it waits for a running instance of the work to finish.
This issue was found by an in-house static analysis tool.
--- drivers/usb/gadget/function/f_midi.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/gadget/function/f_midi.c +1 -0
@@ -1302,6 +1302,7 @@ static void f_midi_free(struct usb_funct opts = container_of(f->fi, struct f_midi_opts, func_inst);mutex_lock (&opts->lock);if (!--midi->free_ref) { +cancel_work_sync (&midi->work);kfree (midi->id);kfifo_free (&midi->in_req_fifo);kfree (midi);
Greg Kroah-Hartman
maintainerPATCH 147/675 usb: gadget: printer: fix infinite loop in printer_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Melbin K Mathew <[email protected]>
commit c2e819be6a5c7f34344926b4bd7e3dfca58cf48a upstream.
printer_read() uses the same variable for the requested copy size and the number of bytes actually copied to user space. copy_to_user() returns the number of bytes not copied, so when it fails to copy anything, the computed copied length becomes zero.
In that case len, buf, current_rx_bytes and current_rx_buf are left unchanged. If RX data is available and the user buffer remains unwritable, the read loop can repeat indefinitely.
Track the copied length separately and return -EFAULT, or the number of bytes already copied, if an iteration makes no progress.
--- drivers/usb/gadget/function/f_printer.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
drivers/usb/gadget/function/f_printer.c +18 -5
@@ -431,7 +431,7 @@ printer_read(struct file *fd, char __use {struct printer_dev *dev = fd->private_data;unsigned long flags; -size_t size; +size_t size, not_copied, copied;size_t bytes_copied;struct usb_request *req;/* This is a pointer to the current USB rx request. */
@@ -524,10 +524,12 @@ printer_read(struct file *fd, char __useelse size = len; - size -=copy_to_user (buf, current_rx_buf, size); - bytes_copied += size; - len -= size; - buf += size; + not_copied =copy_to_user (buf, current_rx_buf, size); + copied = size - not_copied; + + bytes_copied += copied; + len -= copied; + buf += copied;spin_lock_irqsave (&dev->lock, flags);
@@ -542,6 +544,17 @@ printer_read(struct file *fd, char __useif (dev->interface <0 ) goto out_disabled; +if (!copied) { + dev->current_rx_req = current_rx_req; + dev->current_rx_bytes = current_rx_bytes; + dev->current_rx_buf = current_rx_buf; +spin_unlock_irqrestore (&dev->lock, flags); +mutex_unlock (&dev->lock_printer_io); +return bytes_copied ? bytes_copied : -EFAULT ; + } + + size = copied; +/* If we not returning all the data left in this RX request * buffer then adjust the amount of data left in the buffer. * Othewise if we are done with this RX request buffer then
Greg Kroah-Hartman
maintainerPATCH 148/675 USB: gadget: snps-udc: fix device name leak on probe failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 29a142d3e8b35ebc9e0bcc78f4bc26c9b6a9ac0b upstream.
The gadget device name is set by UDC core when registering the gadget and must not be set before to avoid leaking the name in intermediate error paths (e.g. when detecting an older chip revision).
--- drivers/usb/gadget/udc/snps_udc_core.c | 1 - 1 file changed, 1 deletion(-)
drivers/usb/gadget/udc/snps_udc_core.c +0 -1
@@ -3133,7 +3133,6 @@ int udc_probe(struct udc *dev)/* device struct setup */ dev->gadget.ops = &udc_ops; -dev_set_name (&dev->gadget.dev,"gadget" ); dev->gadget.name = name; dev->gadget.max_speed =USB_SPEED_HIGH ;
Greg Kroah-Hartman
maintainerPATCH 149/675 USB: gadget: fsl-udc: fix device name leak on probe failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 6b874d00c466e73c6448a89856407fe46b2f50e4 upstream.
The gadget device name is set by UDC core when registering the gadget and must not be set before to avoid leaking the name in intermediate error paths (e.g. on dma pool creation failure).
--- drivers/usb/gadget/udc/fsl_udc_core.c | 1 - 1 file changed, 1 deletion(-)
drivers/usb/gadget/udc/fsl_udc_core.c +0 -1
@@ -2474,7 +2474,6 @@ static int fsl_udc_probe(struct platform udc_controller->gadget.name = driver_name;/* Setup gadget.dev and register with kernel */ -dev_set_name (&udc_controller->gadget.dev,"gadget" ); udc_controller->gadget.dev.of_node = pdev->dev.of_node;if (!IS_ERR_OR_NULL (udc_controller->transceiver))
Greg Kroah-Hartman
maintainerPATCH 150/675 USB: gadget: fsl-udc: fix dev_printk() device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit c4dd150fceab281496acb3a643ae712aacb74864 upstream.
A change replacing custom printk() macros with dev_printk() incorrectly used the gadget struct device instead of the controller struct device (including for messages printed before the gadget device name has been initialised).
Switch to using the controller platform device with dev_printk() so that the controller device and driver names are included in log messages as expected.
--- drivers/usb/gadget/udc/fsl_udc_core.c | 92 +++++++++++++++------------------- drivers/usb/gadget/udc/fsl_usb2_udc.h | 1 2 files changed, 43 insertions(+), 50 deletions(-)
drivers/usb/gadget/udc/fsl_udc_core.c +42 -50
@@ -184,7 +184,7 @@ __acquires(ep->udc->lock)usb_gadget_unmap_request (&ep->udc->gadget, &req->req,ep_is_in (ep));if (status && (status != -ESHUTDOWN )) -dev_vdbg (&udc->gadget.dev,"complete %s req %p stat %d len %u/%u\n" , +dev_vdbg (udc->dev,"complete %s req %p stat %d len %u/%u\n" , ep->ep.name, &req->req, status, req->req.actual, req->req.length);
@@ -286,7 +286,7 @@ static int dr_controller_setup(struct fs timeout = jiffies +FSL_UDC_RESET_TIMEOUT ;while (fsl_readl (&dr_regs->usbcmd) &USB_CMD_CTRL_RESET ) {if (time_after (jiffies, timeout)) { -dev_err (&udc->gadget.dev,"udc reset timeout!\n" ); +dev_err (udc->dev,"udc reset timeout!\n" );return -ETIMEDOUT ; }cpu_relax ();
@@ -309,7 +309,7 @@ static int dr_controller_setup(struct fs tmp &=USB_EP_LIST_ADDRESS_MASK ;fsl_writel (tmp, &dr_regs->endpointlistaddr); -dev_vdbg (&udc->gadget.dev, +dev_vdbg (udc->dev,"vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x\n" , udc->ep_qh, (int )tmp,fsl_readl (&dr_regs->endpointlistaddr));
@@ -500,7 +500,7 @@ static void struct_ep_qh_setup(struct fs tmp = max_pkt_len <<EP_QUEUE_HEAD_MAX_PKT_LEN_POS ;break ;default : -dev_vdbg (&udc->gadget.dev,"error ep type is %d\n" , ep_type); +dev_vdbg (udc->dev,"error ep type is %d\n" , ep_type);return ; }if (zlt)
@@ -613,7 +613,7 @@ static int fsl_ep_enable(struct usb_ep *spin_unlock_irqrestore (&udc->lock, flags); retval =0 ; -dev_vdbg (&udc->gadget.dev,"enabled %s (ep%d%s) maxpacket %d\n" , +dev_vdbg (udc->dev,"enabled %s (ep%d%s) maxpacket %d\n" , ep->ep.name, ep->ep.desc->bEndpointAddress &0x0f , (desc->bEndpointAddress &USB_DIR_IN ) ?"in" :"out" , max);
@@ -634,13 +634,8 @@ static int fsl_ep_disable(struct usb_epint ep_num; ep = container_of(_ep, struct fsl_ep, ep); -if (!_ep || !ep->ep.desc) { -/* -* dev_vdbg(&udc->gadget.dev, "%s not enabled\n", -* _ep ? ep->ep.name : NULL); -*/ +if (!_ep || !ep->ep.desc)return -EINVAL ; - }/* disable ep on controller */ ep_num =ep_index (ep);
@@ -664,7 +659,7 @@ static int fsl_ep_disable(struct usb_ep ep->stopped =1 ;spin_unlock_irqrestore (&udc->lock, flags); -dev_vdbg (&udc->gadget.dev,"disabled %s OK\n" , _ep->name); +dev_vdbg (udc->dev,"disabled %s OK\n" , _ep->name);return 0 ; }
@@ -724,9 +719,6 @@ static void fsl_queue_td(struct fsl_ep * {u32 temp, bitmask, tmp_stat; -/* dev_vdbg(&udc->gadget.dev, "QH addr Register 0x%8x\n", dr_regs->endpointlistaddr); -dev_vdbg(&udc->gadget.dev, "ep_qh[%d] addr is 0x%8x\n", i, (u32)&(ep->udc->ep_qh[i])); */ - bitmask =ep_is_in (ep) ? (1 << (ep_index (ep) +16 )) : (1 << (ep_index (ep)));
@@ -813,7 +805,7 @@ static struct ep_td_struct *fsl_build_dt *is_last =0 ;if ((*is_last) ==0 ) -dev_vdbg (&udc_controller->gadget.dev,"multi-dtd request!\n" ); +dev_vdbg (udc_controller->dev,"multi-dtd request!\n" );/* Fill in the transfer size; set active bit */ swap_temp = ((*length <<DTD_LENGTH_BIT_POS ) |DTD_STATUS_ACTIVE );
@@ -825,7 +817,7 @@ static struct ep_td_struct *fsl_build_dtmb (); -dev_vdbg (&udc_controller->gadget.dev,"length = %d address= 0x%x\n" , *length, (int )*dma); +dev_vdbg (udc_controller->dev,"length = %d address= 0x%x\n" , *length, (int )*dma);return dtd; }
@@ -876,11 +868,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct/* catch various bogus parameters */ if (!_req || !req->req.complete || !req->req.buf || !list_empty (&req->queue)) { -dev_vdbg (&udc->gadget.dev,"%s, bad params\n" , __func__); +dev_vdbg (udc->dev,"%s, bad params\n" , __func__);return -EINVAL ; }if (unlikely (!ep->ep.desc)) { -dev_vdbg (&udc->gadget.dev,"%s, bad ep\n" , __func__); +dev_vdbg (udc->dev,"%s, bad ep\n" , __func__);return -EINVAL ; }if (usb_endpoint_xfer_isoc (ep->ep.desc)) {
@@ -1040,7 +1032,7 @@ static int fsl_ep_set_halt(struct usb_ep udc->ep0_dir =0 ; } out: -dev_vdbg (&udc->gadget.dev,"%s %s halt stat %d\n" , ep->ep.name, +dev_vdbg (udc->dev,"%s %s halt stat %d\n" , ep->ep.name, value ?"set" :"clear" , status);return status;
@@ -1109,7 +1101,7 @@ static void fsl_ep_fifo_flush(struct usb/* Wait until flush complete */ while (fsl_readl (&dr_regs->endptflush)) {if (time_after (jiffies, timeout)) { -dev_err (&udc_controller->gadget.dev, +dev_err (udc_controller->dev,"ep flush timeout\n" );return ; }
@@ -1182,7 +1174,7 @@ static int fsl_vbus_session(struct usb_g udc = container_of(gadget, struct fsl_udc, gadget);spin_lock_irqsave (&udc->lock, flags); -dev_vdbg (&gadget->dev,"VBUS %s\n" ,str_on_off (is_active)); +dev_vdbg (udc->dev,"VBUS %s\n" ,str_on_off (is_active)); udc->vbus_active = (is_active !=0 );if (can_pullup (udc)) fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@@ -1548,7 +1540,7 @@ static void ep0_req_complete(struct fsl_ udc->ep0_state =WAIT_FOR_SETUP ;break ;case WAIT_FOR_SETUP : -dev_err (&udc->gadget.dev,"Unexpected ep0 packets\n" ); +dev_err (udc->dev,"Unexpected ep0 packets\n" );break ;default :ep0stall (udc);
@@ -1617,7 +1609,7 @@ static int process_ep_req(struct fsl_udc errors =hc32_to_cpu (curr_td->size_ioc_sts);if (errors &DTD_ERROR_MASK ) {if (errors &DTD_STATUS_HALTED ) { -dev_err (&udc->gadget.dev,"dTD error %08x QH=%d\n" , errors, pipe); +dev_err (udc->dev,"dTD error %08x QH=%d\n" , errors, pipe);/* Clear the errors and Halt condition */ tmp =hc32_to_cpu (curr_qh->size_ioc_int_sts); tmp &= ~errors;
@@ -1628,26 +1620,26 @@ static int process_ep_req(struct fsl_udcbreak ; }if (errors &DTD_STATUS_DATA_BUFF_ERR ) { -dev_vdbg (&udc->gadget.dev,"Transfer overflow\n" ); +dev_vdbg (udc->dev,"Transfer overflow\n" ); status = -EPROTO ;break ; }else if (errors &DTD_STATUS_TRANSACTION_ERR ) { -dev_vdbg (&udc->gadget.dev,"ISO error\n" ); +dev_vdbg (udc->dev,"ISO error\n" ); status = -EILSEQ ;break ; }else -dev_err (&udc->gadget.dev, +dev_err (udc->dev,"Unknown error has occurred (0x%x)!\n" , errors); }else if (hc32_to_cpu (curr_td->size_ioc_sts) &DTD_STATUS_ACTIVE ) { -dev_vdbg (&udc->gadget.dev,"Request not complete\n" ); +dev_vdbg (udc->dev,"Request not complete\n" ); status =REQ_UNCOMPLETE ;return status; }else if (remaining_length) {if (direction) { -dev_vdbg (&udc->gadget.dev, +dev_vdbg (udc->dev,"Transmit dTD remaining length not zero\n" ); status = -EPROTO ;break ;
@@ -1655,8 +1647,7 @@ static int process_ep_req(struct fsl_udcbreak ; } }else { -dev_vdbg (&udc->gadget.dev, -"dTD transmitted successful\n" ); +dev_vdbg (udc->dev,"dTD transmitted successful\n" ); }if (j != curr_req->dtd_count -1 )
@@ -1699,7 +1690,7 @@ static void dtd_complete_irq(struct fsl_/* If the ep is configured */ if (!curr_ep->ep.name) { -dev_warn (&udc->gadget.dev,"Invalid EP?\n" ); +dev_warn (udc->dev,"Invalid EP?\n" );continue ; }
@@ -1708,7 +1699,7 @@ static void dtd_complete_irq(struct fsl_ queue) { status =process_ep_req (udc, i, curr_req); -dev_vdbg (&udc->gadget.dev, +dev_vdbg (udc->dev,"status of process_ep_req= %d, ep = %d\n" , status, ep_num);if (status ==REQ_UNCOMPLETE )
@@ -1829,7 +1820,7 @@ static void reset_irq(struct fsl_udc *udwhile (fsl_readl (&dr_regs->endpointprime)) {/* Wait until all endptprime bits cleared */ if (time_after (jiffies, timeout)) { -dev_err (&udc->gadget.dev,"Timeout for reset\n" ); +dev_err (udc->dev,"Timeout for reset\n" );break ; }cpu_relax ();
@@ -1839,7 +1830,7 @@ static void reset_irq(struct fsl_udc *udfsl_writel (0xffffffff , &dr_regs->endptflush);if (fsl_readl (&dr_regs->portsc1) &PORTSCX_PORT_RESET ) { -dev_vdbg (&udc->gadget.dev,"Bus reset\n" ); +dev_vdbg (udc->dev,"Bus reset\n" );/* Bus is reseting */ udc->bus_reset =1 ;/* Reset all the queues, include XD, dTD, EP queue
@@ -1847,7 +1838,7 @@ static void reset_irq(struct fsl_udc *udreset_queues (udc, true); udc->usb_state =USB_STATE_DEFAULT ; }else { -dev_vdbg (&udc->gadget.dev,"Controller reset\n" ); +dev_vdbg (udc->dev,"Controller reset\n" );/* initialize usb hw reg except for regs for EP, not * touch usbintr reg */ dr_controller_setup (udc);
@@ -1881,7 +1872,7 @@ static irqreturn_t fsl_udc_irq(int irq,/* Clear notification bits */ fsl_writel (irq_src, &dr_regs->usbsts); -/* dev_vdbg(&udc->gadget.dev, "irq_src [0x%8x]", irq_src); */ +/* dev_vdbg(udc->dev, "irq_src [0x%8x]", irq_src); */ /* Need to resume? */ if (udc->usb_state ==USB_STATE_SUSPENDED )
@@ -1890,7 +1881,7 @@ static irqreturn_t fsl_udc_irq(int irq,/* USB Interrupt */ if (irq_src &USB_STS_INT ) { -dev_vdbg (&udc->gadget.dev,"Packet int\n" ); +dev_vdbg (udc->dev,"Packet int\n" );/* Setup package, we only support ep0 as control ep */ if (fsl_readl (&dr_regs->endptsetupstat) &EP_SETUP_STATUS_EP0 ) { tripwire_handler(udc, 0,
@@ -1919,7 +1910,7 @@ static irqreturn_t fsl_udc_irq(int irq,/* Reset Received */ if (irq_src &USB_STS_RESET ) { -dev_vdbg (&udc->gadget.dev,"reset int\n" ); +dev_vdbg (udc->dev,"reset int\n" );reset_irq (udc); status =IRQ_HANDLED ; }
@@ -1931,7 +1922,7 @@ static irqreturn_t fsl_udc_irq(int irq, }if (irq_src & (USB_STS_ERR |USB_STS_SYS_ERR )) { -dev_vdbg (&udc->gadget.dev,"Error IRQ %x\n" , irq_src); +dev_vdbg (udc->dev,"Error IRQ %x\n" , irq_src); }spin_unlock_irqrestore (&udc->lock, flags);
@@ -1967,7 +1958,7 @@ static int fsl_udc_start(struct usb_gadg udc_controller->transceiver->otg, &udc_controller->gadget);if (retval <0 ) { -dev_err (&udc_controller->gadget.dev,"can't bind to transceiver\n" ); +dev_err (udc_controller->dev,"can't bind to transceiver\n" ); udc_controller->driver =NULL ;return retval; }
@@ -2252,7 +2243,7 @@ static int struct_udc_setup(struct fsl_u udc->eps =kcalloc (udc->max_ep,sizeof (struct fsl_ep ),GFP_KERNEL );if (!udc->eps) { -dev_err (&udc->gadget.dev,"kmalloc udc endpoint status failed\n" ); +dev_err (udc->dev,"kmalloc udc endpoint status failed\n" ); goto eps_alloc_failed; }
@@ -2267,7 +2258,7 @@ static int struct_udc_setup(struct fsl_u udc->ep_qh =dma_alloc_coherent (&pdev->dev, size, &udc->ep_qh_dma,GFP_KERNEL );if (!udc->ep_qh) { -dev_err (&udc->gadget.dev,"malloc QHs for udc failed\n" ); +dev_err (udc->dev,"malloc QHs for udc failed\n" ); goto ep_queue_alloc_failed; }
@@ -2278,14 +2269,14 @@ static int struct_udc_setup(struct fsl_u udc->status_req =container_of (fsl_alloc_request (NULL ,GFP_KERNEL ), struct fsl_req, req);if (!udc->status_req) { -dev_err (&udc->gadget.dev,"kzalloc for udc status request failed\n" ); +dev_err (udc->dev,"kzalloc for udc status request failed\n" ); goto udc_status_alloc_failed; }/* allocate a small amount of memory to get valid address */ udc->status_req->req.buf =kmalloc (8 ,GFP_KERNEL );if (!udc->status_req->req.buf) { -dev_err (&udc->gadget.dev,"kzalloc for udc request buffer failed\n" ); +dev_err (udc->dev,"kzalloc for udc request buffer failed\n" ); goto udc_req_buf_alloc_failed; }
@@ -2373,6 +2364,7 @@ static int fsl_udc_probe(struct platformif (udc_controller ==NULL )return -ENOMEM ; + udc_controller->dev = &pdev->dev; pdata =dev_get_platdata (&pdev->dev); udc_controller->pdata = pdata;spin_lock_init (&udc_controller->lock);
@@ -2382,7 +2374,7 @@ static int fsl_udc_probe(struct platformif (pdata->operating_mode ==FSL_USB2_DR_OTG ) { udc_controller->transceiver =usb_get_phy (USB_PHY_TYPE_USB2 );if (IS_ERR_OR_NULL (udc_controller->transceiver)) { -dev_err (&udc_controller->gadget.dev,"Can't find OTG driver!\n" ); +dev_err (&pdev->dev,"Can't find OTG driver!\n" ); ret = -ENODEV ; goto err_kfree; }
@@ -2398,7 +2390,7 @@ static int fsl_udc_probe(struct platformif (pdata->operating_mode ==FSL_USB2_DR_DEVICE ) {if (!request_mem_region (res->start,resource_size (res), driver_name)) { -dev_err (&udc_controller->gadget.dev,"request mem region for %s failed\n" , pdev->name); +dev_err (&pdev->dev,"failed to request mem region\n" ); ret = -EBUSY ; goto err_kfree; }
@@ -2429,7 +2421,7 @@ static int fsl_udc_probe(struct platform/* Read Device Controller Capability Parameters register */ dccparams =fsl_readl (&dr_regs->dccparams);if (!(dccparams &DCCPARAMS_DC )) { -dev_err (&udc_controller->gadget.dev,"This SOC doesn't support device role\n" ); +dev_err (&pdev->dev,"This SOC doesn't support device role\n" ); ret = -ENODEV ; goto err_exit; }
@@ -2447,14 +2439,14 @@ static int fsl_udc_probe(struct platform ret =request_irq (udc_controller->irq, fsl_udc_irq,IRQF_SHARED , driver_name, udc_controller);if (ret !=0 ) { -dev_err (&udc_controller->gadget.dev,"cannot request irq %d err %d\n" , +dev_err (&pdev->dev,"cannot request irq %d err %d\n" , udc_controller->irq, ret); goto err_exit; }/* Initialize the udc structure including QH member and other member */ if (struct_udc_setup (udc_controller, pdev)) { -dev_err (&udc_controller->gadget.dev,"Can't initialize udc data structure\n" ); +dev_err (&pdev->dev,"Can't initialize udc data structure\n" ); ret = -ENOMEM ; goto err_free_irq; }
drivers/usb/gadget/udc/fsl_usb2_udc.h +1 -0
@@ -470,6 +470,7 @@ struct fsl_ep {#define EP_DIR_OUT 0struct fsl_udc { +struct device *dev;struct usb_gadget gadget;struct usb_gadget_driver *driver;struct fsl_usb2_platform_data *pdata;
Greg Kroah-Hartman
maintainerPATCH 151/675 usb: gadget: f_ncm: validate datagram bounds in ncm_unwrap_ntb()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sonali Pradhan <[email protected]>
commit 1febec7e47cdcd01f43fb0211094e3010474666e upstream.
When unpacking host-supplied NTBs, ncm_unwrap_ntb() checks datagram length against frame_max but does not verify that the datagram fits within the declared block length. Additionally, when decoding multiple NTBs from a single socket buffer, subsequent block lengths are not checked against the actual remaining buffer data.
With these checks missing, a malicious USB host can specify datagram offsets and lengths that point beyond the block, or supply secondary NTB headers declaring lengths larger than the buffer. skb_put_data() then copies adjacent kernel memory from skb_shared_info into the network skb.
Fix this by verifying that sufficient buffer space remains for the NTB header before parsing, handling zero-length block declarations, ensuring that block lengths never exceed the remaining buffer space, and verifying that each datagram payload stays strictly within the block boundary.
--- drivers/usb/gadget/function/f_ncm.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
drivers/usb/gadget/function/f_ncm.c +13 -4
@@ -1189,6 +1189,10 @@ static int ncm_unwrap_ntb(struct gether frame_max = ncm_opts->max_segment_size; parse_ntb: +if (to_process < (int )opts->nth_size) { +INFO (port->func.config->cdev,"Packet too small for headers\n" ); + goto err; + } tmp = (__le16 *)ntb_ptr;/* dwSignature */
@@ -1209,8 +1213,12 @@ parse_ntb: tmp++;/* skip wSequence */ block_len =get_ncm (&tmp, opts->block_length); +if (block_len ==0 ) + block_len = to_process; +/* (d)wBlockLength */ -if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) { +if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max) || + (block_len > to_process)) {INFO (port->func.config->cdev,"Bad block length: %#X\n" , block_len); goto err; }
@@ -1273,7 +1281,7 @@ parse_ntb: index = index2;/* wDatagramIndex[0] */ if ((index < opts->nth_size) || - (index > block_len - opts->dpe_size)) { + (index > block_len)) {INFO (port->func.config->cdev,"Bad index: %#X\n" , index); goto err;
@@ -1285,7 +1293,8 @@ parse_ntb:* ethernet hdr + crc or larger than max frame size */ if ((dg_len <14 + crc_len) || - (dg_len > frame_max)) { + (dg_len > frame_max) || + (dg_len > block_len - index)) {INFO (port->func.config->cdev,"Bad dgram length: %#X\n" , dg_len); goto err;
@@ -1310,7 +1319,7 @@ parse_ntb: dg_len2 =get_ncm (&tmp, opts->dgram_item_len);/* wDatagramIndex[1] */ -if (index2 > block_len - opts->dpe_size) { +if (index2 > block_len) {INFO (port->func.config->cdev,"Bad index: %#X\n" , index2); goto err;
Greg Kroah-Hartman
maintainerPATCH 152/675 usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 0583f2fbf8f86ae3a0ce054f96783dd83e65d9bb upstream.
The Broadcom BDC UDC driver registers its IRQ handler with devm_request_irq() in bdc_udc_init(), so the IRQ is released by devm only after bdc_remove() returns. devm releases resources in reverse LIFO order, but bdc_remove() runs bdc_udc_exit() and bdc_hw_exit() -> bdc_mem_free() manually before returning: bdc_udc_exit() tears down individual endpoint objects via bdc_free_ep(), while bdc_hw_exit() -> bdc_mem_free() frees and NULLs the DMA-coherent status-report ring (bdc->srr.sr_bds) and kfree()s bdc->bdc_ep_array. Both happen while the IRQ handler (bdc_udc_interrupt, requested with IRQF_SHARED) remains deliverable in the window up to the post-remove devm free_irq().
On receipt of a shared interrupt in that window, bdc_udc_interrupt() dereferences bdc->srr.sr_bds[bdc->srr.dqp_index] (NULL or freed DMA) and dispatches sr_handler callbacks that index into bdc_ep_array, causing a NULL-deref or use-after-free.
The same window affects the delayed_work bdc->func_wake_notify, which is armed from the IRQ handler via bdc_sr_uspc() -> handle_link_state_change() -> schedule_delayed_work() and may self-rearm from its own callback bdc_func_wake_timer(). No cancel exists anywhere in the driver, so a queued work item that fires after bdc_remove() returns and the bdc structure is devm-freed dereferences freed memory.
Replace devm_request_irq() with request_irq() and add an explicit free_irq(bdc->irq, bdc) in bdc_remove(). Clear BDC_GIE before free_irq() to stop the device from asserting interrupts, then free_irq() drains any in-flight handler, then cancel_delayed_work_sync() drains the func_wake_notify delayed work. This ordering ensures the IRQ handler and delayed work cannot interfere with the subsequent endpoint and DMA teardown in bdc_udc_exit() and bdc_hw_exit(). Wire the matching free_irq() into the bdc_udc_init() error path so the IRQ is released on probe failure, and route the bdc_init_ep() failure through err0 instead of returning directly.
This issue was found by an in-house static analysis tool.
--- drivers/usb/gadget/udc/bdc/bdc_core.c | 20 ++++++++++++++++++++ drivers/usb/gadget/udc/bdc/bdc_udc.c | 7 ++++--- 2 files changed, 24 insertions(+), 3 deletions(-)
drivers/usb/gadget/udc/bdc/bdc_core.c +20 -0
@@ -586,9 +586,29 @@ disable_clk:static void bdc_remove (struct platform_device *pdev) {struct bdc *bdc; +unsigned long flags; +u32 temp; bdc =platform_get_drvdata (pdev);dev_dbg (bdc->dev,"%s ()\n" , __func__); +/* +* Disable the device interrupt source before freeing the IRQ: +* clear BDC_GIE so the controller stops asserting interrupts, +* then free_irq drains any in-flight handler. +*/ +spin_lock_irqsave (&bdc->lock, flags); + temp =bdc_readl (bdc->regs,BDC_BDCSC ); + temp &= ~BDC_GIE ; +bdc_writel (bdc->regs,BDC_BDCSC , temp); +spin_unlock_irqrestore (&bdc->lock, flags); +free_irq (bdc->irq, bdc); +/* +* Drain func_wake_notify after free_irq: the IRQ handler arms this +* delayed_work via bdc_sr_uspc -> handle_link_state_change -> +* schedule_delayed_work (self-rearmed in bdc_func_wake_timer), so +* the IRQ must be released first to prevent re-arm after cancel. +*/ +cancel_delayed_work_sync (&bdc->func_wake_notify);bdc_udc_exit (bdc);bdc_hw_exit (bdc);bdc_phy_exit (bdc);
drivers/usb/gadget/udc/bdc/bdc_udc.c +4 -3
@@ -530,8 +530,8 @@ int bdc_udc_init(struct bdc *bdc) bdc->gadget.name =BRCM_BDC_NAME ; - ret =devm_request_irq (bdc->dev, bdc->irq, bdc_udc_interrupt, -IRQF_SHARED ,BRCM_BDC_NAME , bdc); + ret =request_irq (bdc->irq, bdc_udc_interrupt,IRQF_SHARED , +BRCM_BDC_NAME , bdc);if (ret) { dev_err(bdc->dev, "failed to request irq #%d %d\n",
@@ -542,7 +542,7 @@ int bdc_udc_init(struct bdc *bdc) ret =bdc_init_ep (bdc);if (ret) {dev_err (bdc->dev,"bdc init ep fail: %d\n" , ret); -return ret; + goto err0; } ret =usb_add_gadget_udc (bdc->dev, &bdc->gadget);
@@ -571,6 +571,7 @@ int bdc_udc_init(struct bdc *bdc) err1:usb_del_gadget_udc (&bdc->gadget); err0: +free_irq (bdc->irq, bdc);bdc_free_ep (bdc);return ret;
Greg Kroah-Hartman
maintainerPATCH 153/675 usb: gadget: uvc: clamp SEND_RESPONSE length to the response buffer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit b70dc75e85ba968b7b76eebfe5d63000080b875b upstream.
uvc_send_response() builds the UVC control response from a user-supplied struct uvc_request_data:
req->length = min_t(unsigned int, uvc->event_length, data->length); ... memcpy(req->buf, data->data, req->length);
req->length is clamped to uvc->event_length, which is taken from the host control request wLength (up to UVC_MAX_REQUEST_SIZE, 64), and to data->length, which comes from the UVCIOC_SEND_RESPONSE ioctl and is only checked for being negative. The source buffer data->data is only 60 bytes, so a response with uvc->event_length and data->length both greater than 60 makes memcpy() read past the end of data->data.
Clamp req->length to sizeof(data->data) as well.
--- drivers/usb/gadget/function/uvc_v4l2.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/gadget/function/uvc_v4l2.c +2 -0
@@ -200,6 +200,8 @@ uvc_send_response(struct uvc_device *uvcreturn usb_ep_set_halt (cdev->gadget->ep0); req->length = min_t(unsigned int, uvc->event_length, data->length); +if (req->length >sizeof (data->data)) + req->length =sizeof (data->data); req->zero = data->length < uvc->event_length;memcpy (req->buf, data->data, req->length);
Greg Kroah-Hartman
maintainerPATCH 154/675 USB: serial: ftdi_sio: add support for E+H FXA291
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tim Pambor <[email protected]>
commit fad0fd120e29041b3e6cdf41bb12e3184fb524a2 upstream.
The Commubox FXA291 by Endress+Hauser AG is a USB serial converter based on FT232B which is used to communicate with field devices.
It enumerates using the FTDI vendor ID and a custom PID.
usb 1-9: New USB device found, idVendor=0403, idProduct=e510, bcdDevice= 4.00 usb 1-9: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 1-9: Product: FXA291
usb 1-9: Manufacturer: Endress+Hauser
usb 1-9: SerialNumber: 00000000ftdi_sio 1-9:1.0: FTDI USB Serial Device converter detected
usb 1-9: Detected FT232B
usb 1-9: FTDI USB Serial Device converter now attached to ttyUSB0
--- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ 2 files changed, 7 insertions(+)
drivers/usb/serial/ftdi_sio.c +2 -0
@@ -1075,6 +1075,8 @@ static const struct usb_device_id id_tab { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) },/* Abacus Electrics */ { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, +/* Endress+Hauser AG devices */ + { USB_DEVICE(FTDI_VID, FTDI_EH_FXA291_PID) }, { } /* Terminating entry */ };
drivers/usb/serial/ftdi_sio_ids.h +5 -0
@@ -314,6 +314,11 @@#define FTDI_ELV_UIO88_PID 0xFB5F/* USB-I/O Interface (UIO 88) */ /* +* Endress+Hauser AG product ids (FTDI_VID) +*/ +#define FTDI_EH_FXA291_PID 0xE510 + +/* * EVER Eco Pro UPS (http://www.ever.com.pl/) */
Greg Kroah-Hartman
maintainerPATCH 155/675 USB: serial: io_edgeport: cap received transmit credits
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sunho Park <[email protected]>
commit faaddd811c5099f11a5f52e68a6b31a5898cda4f upstream.
The interrupt-status packet reports transmit credits returned by the device. edge_interrupt_callback() adds the 16-bit value to txCredits without checking maxTxCredits.
edge_write() uses txCredits minus the software FIFO count as the amount of data that fits. Since the FIFO is allocated with maxTxCredits bytes, txCredits exceeding maxTxCredits can cause OOB write in ring buffer.
Cap accumulated credits at maxTxCredits. Conforming devices should never hit the cap.
--- drivers/usb/serial/io_edgeport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/serial/io_edgeport.c +2 -1
@@ -646,7 +646,8 @@ static void edge_interrupt_callback(struif (edge_port && edge_port->open) {spin_lock_irqsave (&edge_port->ep_lock, flags); - edge_port->txCredits += txCredits; + edge_port->txCredits =min (edge_port->txCredits + txCredits, + edge_port->maxTxCredits);spin_unlock_irqrestore (&edge_port->ep_lock, flags); dev_dbg(dev, "%s - txcredits for port%d = %d\n",
Greg Kroah-Hartman
maintainerPATCH 156/675 USB: serial: keyspan_pda: fix data loss on receive throttling
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 42a97c0480f96a2977e6d51ce512adc780f1ef5d upstream.
Killing the interrupt-in urb when the line disciple requests throttling may lead to data loss if an ongoing transfer is cancelled.
Instead set a flag to prevent the completion handler from resubmitting the urb until the port is unthrottled.
--- drivers/usb/serial/keyspan_pda.c | 44 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-)
drivers/usb/serial/keyspan_pda.c +35 -9
@@ -35,6 +35,8 @@ struct keyspan_pda_private {struct work_struct unthrottle_work;struct usb_serial *serial;struct usb_serial_port *port; +bool throttled; +bool throttle_req; };static int keyspan_pda_write_start (struct usb_serial_port *port);
@@ -150,6 +152,7 @@ static void keyspan_pda_rx_interrupt(strint retval;int status = urb->status;struct keyspan_pda_private *priv; +bool throttled = false;unsigned long flags; priv =usb_get_serial_port_data (port);
@@ -211,16 +214,24 @@ static void keyspan_pda_rx_interrupt(str } exit: - retval =usb_submit_urb (urb,GFP_ATOMIC ); -if (retval) -dev_err (&port->dev, -"%s - usb_submit_urb failed with result %d\n" , - __func__, retval); +spin_lock_irqsave (&port->lock, flags); +if (priv->throttle_req) { + priv->throttled = true; + throttled = true; + } +spin_unlock_irqrestore (&port->lock, flags); + +if (!throttled) { + retval =usb_submit_urb (urb,GFP_ATOMIC ); +if (retval) +dev_err (&port->dev,"failed to resubmit in urb: %d\n" , retval); + } }static void keyspan_pda_rx_throttle (struct tty_struct *tty) {struct usb_serial_port *port = tty->driver_data; +struct keyspan_pda_private *priv =usb_get_serial_port_data (port);/* * Stop receiving characters. We just turn off the URB request, and
@@ -230,16 +241,29 @@ static void keyspan_pda_rx_throttle(stru* send an XOFF, although it might make sense to foist that off upon * the device too. */ -usb_kill_urb (port->interrupt_in_urb); +spin_lock_irq (&port->lock); + priv->throttle_req = true; +spin_unlock_irq (&port->lock); }static void keyspan_pda_rx_unthrottle (struct tty_struct *tty) {struct usb_serial_port *port = tty->driver_data; +struct keyspan_pda_private *priv =usb_get_serial_port_data (port); +bool throttled; +int ret; + +spin_lock_irq (&port->lock); + throttled = priv->throttled; + priv->throttled = false; + priv->throttle_req = false; +spin_unlock_irq (&port->lock); -/* just restart the receive interrupt URB */ -if (usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL )) -dev_dbg (&port->dev,"usb_submit_urb(read urb) failed\n" ); +if (throttled) { + ret =usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL ); +if (ret) +dev_err (&port->dev,"failed to submit in urb: %d\n" , ret); + } }static speed_t keyspan_pda_setbaud (struct usb_serial *serial,speed_t baud)
@@ -579,6 +603,8 @@ static int keyspan_pda_open(struct tty_sspin_lock_irq (&port->lock); priv->tx_room = rc; + priv->throttled = false; + priv->throttle_req = false;spin_unlock_irq (&port->lock); rc =usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 157/675 USB: serial: option: add TDTECH MT5710-CN
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chukun Pan <[email protected]>
commit 55645e4f3c6022ffb160ad3617d2b624eaa38501 upstream.
Add support for the TDTECH MT5710-CN (5G redcap) module based on the Huawei HiSilicon Balong chip.
T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=3466 ProdID=3301 Rev=ff.ff S: Manufacturer=TD Tech Ltd. S: Product=TDTECH MT571X S: SerialNumber=0123456789ABCDEF C:* #Ifs= 6 Cfg#= 1 Atr=c0 MxPwr= 0mA A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0d Prot=00 I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0d Prot=00 Driver=cdc_ncm E: Ad=82(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=cdc_ncm E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=13 Driver=option E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=12 Driver=option E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=1c Driver=option E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=06 Prot=14 Driver=option E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
Interface: ECM / NCM + DIAG + AT + SERIAL + GPS
--- drivers/usb/serial/option.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/option.c +1 -0
@@ -2497,6 +2497,7 @@ static const struct usb_device_id option .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */ .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) }, /* TDTECH MT5710-CN */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
Greg Kroah-Hartman
maintainerPATCH 158/675 usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chia-Lin Kao (AceLan) <[email protected]>
commit 67c92c6419ea6dbc5b1f3e9691aecea956e3e81c upstream.
Some firmware implementations incorrectly return the same altmode multiple times at different offsets when queried via UCSI_GET_ALTERNATE_MODES. This causes sysfs duplicate filename errors and kernel call traces when the driver attempts to register the same altmode twice:
sysfs: cannot create duplicate filename '/devices/.../typec/port0/port0.0/partner' typec-thunderbolt port0-partner.1: failed to create symlinks typec-thunderbolt port0-partner.1: probe with driver typec-thunderbolt failed with error -17
The matching rules differ by recipient:
- UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
Two altmodes with identical SVID and VDO are byte-for-byte duplicates and the second has no observable function, so drop it.
- UCSI_RECIPIENT_SOP (partner):
The typec class binds each partner altmode to a port altmode of the same SVID via altmode_match()/device_find_child(), which returns the first port altmode with a matching SVID. If the partner advertises more altmodes for SVID X than the port advertises, the surplus partner altmode(s) collapse onto an already-paired port altmode and trigger the
"duplicate filename .../partner" sysfs error during typec_altmode_create_links(). Use the port-side altmode count for SVID X as the authoritative cap and reject any partner altmode that would exceed it. This preserves legitimate multi-Mode partner altmodes (vendor SVIDs that the port really does advertise more than once) while filtering the firmware-generated duplicates that have no port counterpart, and is therefore stricter than a plain SVID+VDO comparison (which still admits the Thunderbolt case where firmware reports the same SVID twice with different VDOs) without being over-broad like a plain SVID match (which would falsely drop legitimate vendor multi-Mode entries).
If a duplicate is detected, skip it and emit a clean warning instead of generating a kernel call trace:
ucsi_acpi USBC000:00: con2: Firmware bug: duplicate partner altmode SVID 0x8087 at offset 1, ignoring. ucsi_acpi USBC000:00: con2: VDO mismatch: 0x8087a043 vs 0x00000001
The duplicate detection logic lives in a reusable helper ucsi_altmode_is_duplicate() and is invoked from ucsi_register_altmodes(). It applies to all three recipient types:
partner (SOP), port (CON), and plug (SOP_P) altmodes.
unchanged: still SVID+VDO exact-dup match.
--- drivers/usb/typec/ucsi/ucsi.c | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+)
drivers/usb/typec/ucsi/ucsi.c +132 -0
@@ -487,6 +487,129 @@ err:return ret; } +static void ucsi_dump_duplicate_altmode (struct ucsi_connector *con, +u8 recipient,u16 svid, +u32 existing_vdo,u32 new_vdo, +int offset) +{ +static const char *const recipient_names[] = { + [UCSI_RECIPIENT_CON ] ="port" , + [UCSI_RECIPIENT_SOP ] ="partner" , + [UCSI_RECIPIENT_SOP_P ] ="plug" , + [UCSI_RECIPIENT_SOP_PP ] ="cable plug prime" , + }; + +dev_warn (con->ucsi->dev, +"con%d: Firmware bug: duplicate %s altmode SVID 0x%04x at offset %d, ignoring but please contact the BIOS vendor to fix this issue.\n" , + con->num, recipient_names[recipient], svid, offset); + +if (existing_vdo != new_vdo) +dev_warn (con->ucsi->dev, +"con%d: VDO mismatch: 0x%08x vs 0x%08x\n" , + con->num, existing_vdo, new_vdo); +} + +/* Count altmodes in @altmodes that advertise @svid. */ +static int ucsi_altmode_count_svid (struct typec_altmode **altmodes,u16 svid) +{ +int count =0 ; +int k; + +for (k =0 ; k <UCSI_MAX_ALTMODES ; k++) { +if (!altmodes[k]) +break ; +if (altmodes[k]->svid == svid) + count++; + } + +return count; +} + +/* +* Check if an altmode is a duplicate. Some firmware implementations +* incorrectly return the same altmode multiple times, causing sysfs errors. +* Returns true if the altmode should be skipped. +* +* The matching rules differ by recipient: +* +* - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug): +* Two altmodes with identical SVID and VDO are byte-for-byte duplicates +* and the second has no observable function. Drop them. +* +* - UCSI_RECIPIENT_SOP (partner): +* The typec class binds each partner altmode to a port altmode of the +* same SVID via altmode_match()/device_find_child(), which returns the +* first port altmode with a matching SVID. If the partner advertises +* more altmodes for SVID X than the port advertises, the surplus +* partner altmode(s) collapse onto an already-paired port altmode and +* trigger a "duplicate filename .../partner" sysfs error during +* typec_altmode_create_links(). Use the port-side altmode count for +* SVID X as the authoritative cap and reject any partner altmode that +* would exceed it. This preserves legitimate multi-Mode partner +* altmodes (e.g. vendor SVIDs that the port really does advertise +* twice) while filtering the firmware-generated duplicates that have +* no port counterpart. +*/ +static bool ucsi_altmode_is_duplicate (struct ucsi_connector *con,u8 recipient, +const struct ucsi_altmode *alt_batch,int batch_idx, +u16 svid,u32 vdo,int offset) +{ +struct typec_altmode **altmodes; +int port_count, partner_count; +int k; + +/* Check for duplicates within the current batch first */ +for (k =0 ; k < batch_idx; k++) { +if (alt_batch[k].svid == svid && alt_batch[k].mid == vdo) { +ucsi_dump_duplicate_altmode (con, recipient, svid, + vdo, vdo, offset); +return true; + } + } + +switch (recipient) { +case UCSI_RECIPIENT_SOP : +/* +* Cap partner altmodes per SVID by the port-side count: +* any further partner altmode for that SVID would alias an +* already-paired port altmode and break typec sysfs. +*/ + port_count =ucsi_altmode_count_svid (con->port_altmode, svid); + partner_count =ucsi_altmode_count_svid (con->partner_altmode, + svid); +if (port_count && partner_count >= port_count) { +ucsi_dump_duplicate_altmode (con, recipient, svid, + con->partner_altmode[partner_count -1 ]->vdo, + vdo, offset); +return true; + } +return false; +case UCSI_RECIPIENT_CON : + altmodes = con->port_altmode; +break ; +case UCSI_RECIPIENT_SOP_P : + altmodes = con->plug_altmode; +break ; +default : +return false; + } + +/* CON and SOP_P: drop only exact SVID+VDO duplicates. */ +for (k =0 ; k <UCSI_MAX_ALTMODES ; k++) { +if (!altmodes[k]) +break ; + +if (altmodes[k]->svid != svid || altmodes[k]->vdo != vdo) +continue ; + +ucsi_dump_duplicate_altmode (con, recipient, svid, + altmodes[k]->vdo, vdo, offset); +return true; + } + +return false; +} +static int ucsi_register_altmodes_nvidia (struct ucsi_connector *con,u8 recipient) {
@@ -611,6 +734,15 @@ static int ucsi_register_altmodes(structif (!alt[j].svid)return 0 ; +/* +* Check for duplicates in current batch and already +* registered altmodes. Skip if duplicate found. +*/ +if (ucsi_altmode_is_duplicate (con, recipient, alt, j, + alt[j].svid, alt[j].mid, + i - num + j)) +continue ; +memset (&desc,0 ,sizeof (desc)); desc.vdo = alt[j].mid; desc.svid = alt[j].svid;
Greg Kroah-Hartman
maintainerPATCH 159/675 usb: typec: ucsi: Add duplicate detection to nvidia registration path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chia-Lin Kao (AceLan) <[email protected]>
commit f1aa17f72f9b9589bd724dc826c5b17d164193d1 upstream.
Extend the duplicate altmode detection to ucsi_register_altmodes_nvidia() which is used when a driver provides the update_altmodes() callback.
This ensures all drivers benefit from duplicate detection, whether they use the standard registration path or the nvidia path with update_altmodes callback.
Without this fix, drivers using the nvidia path (like yoga_c630) would still encounter duplicate altmode registration errors from buggy firmware.
--- drivers/usb/typec/ucsi/ucsi.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/usb/typec/ucsi/ucsi.c +16 -10
@@ -664,19 +664,25 @@ ucsi_register_altmodes_nvidia(struct ucs/* now register altmodes */ for (i =0 ; i < max_altmodes; i++) { -memset (&desc,0 ,sizeof (desc)); -if (multi_dp) { - desc.svid = updated[i].svid; - desc.vdo = updated[i].mid; - }else { - desc.svid = orig[i].svid; - desc.vdo = orig[i].mid; - } - desc.roles =TYPEC_PORT_DRD ; +struct ucsi_altmode *altmode_array = multi_dp ? updated : orig; -if (!desc.svid) +if (!altmode_array[i].svid)return 0 ; +/* +* Check for duplicates in current array and already +* registered altmodes. Skip if duplicate found. +*/ +if (ucsi_altmode_is_duplicate (con, recipient, altmode_array, i, + altmode_array[i].svid, + altmode_array[i].mid, i)) +continue ; + +memset (&desc,0 ,sizeof (desc)); + desc.svid = altmode_array[i].svid; + desc.vdo = altmode_array[i].mid; + desc.roles =TYPEC_PORT_DRD ; + ret =ucsi_register_altmode (con, &desc, recipient);if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 160/675 wifi: mwifiex: fix freeze for 60 seconds caused by request_firmware
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Georgi Valkov <[email protected]>
[ Upstream commit 121a96c5a0db8d18e2ba2cb89660cca8a40508fe ]
Fix regression in rgpower table loading, caused by using request_firmware(): when the requested firmware does not exist, e.g. nxp/rgpower_WW.bin does not exist on OpenWRT builds for WRT3200ACM, request_firmware() falls back to firmware_fallback_sysfs(), which expects the firmware to be provided by user space using SYSFS. No such utility is provided in this configuration, so the entire system locks up for 60 seconds, until the request times out. During this time, no other log messages are observed, and the device does not respond to commands over UART.
The request_firmware() call is performed in the following context:current->comm kworker/1:2 in_task 1 irqs_disabled 0 in_atomic 0
Fixed by using request_firmware_direct(). This prevents fallback to SYSFS, and avoids delay. The rgpower table is optional. The driver falls back to the device tree power table if the firmware is not present.
The error code is printed for debugging and returned to the caller, which only cares for success or failure, so there are no side effects.
--- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +8 -6
@@ -196,6 +196,7 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)struct mwifiex_adapter *adapter = priv->adapter;char rgpower_table_name[30 ];char country_code[3 ]; +int ret;strscpy (country_code, domain_info->country_code,sizeof (country_code));
@@ -214,16 +215,17 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) adapter->rgpower_data =NULL ; } -if ((request_firmware (&adapter->rgpower_data, rgpower_table_name, - adapter->dev))) { + ret =request_firmware_direct (&adapter->rgpower_data, rgpower_table_name, + adapter->dev); + +if (ret) {mwifiex_dbg ( adapter,INFO , -"info: %s: failed to request regulatory power table\n" , - __func__); -return -EIO ; +"info: %s: failed to request regulatory power table: %d\n" , + __func__, ret); } -return 0 ; +return ret; }static int mwifiex_dnld_rgpower_table (struct mwifiex_private *priv)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 161/675 RISC-V: KVM: Serialize virtual interrupt pending state updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xie Bo <[email protected]>
commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream.
KVM RISC-V tracks guest local interrupt state with two bitmaps:
- irqs_pending: interrupts that should be visible to the guest
- irqs_pending_mask: interrupts whose pending state changed
The current code updates those bitmaps with independent atomic bitops and assumes a multiple-producer, single-consumer protocol. That model does not actually hold.
kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest changes guest-visible HVIP state, sync_interrupts() writes both irqs_pending and irqs_pending_mask to reflect the new guest state back into KVM state. As a result, irqs_pending and irqs_pending_mask form a single logical state transition, but they are not updated atomically as a pair.
This allows a race where a newly injected interrupt is lost. For example:
CPU0 CPU1
---- ----
kvm_riscv_vcpu_set_interrupt(VS_SOFT)
set_bit(VS_SOFT, irqs_pending)
kvm_riscv_vcpu_sync_interrupts()
sees guest-cleared HVIP.VSSIP sets irqs_pending_mask clear_bit(IRQ_VS_SOFT, irqs_pending)
set_bit(VS_SOFT, irqs_pending_mask)
kvm_vcpu_kick()
After that interleaving, a later flush can update HVIP without VSSIP even though a new virtual interrupt was injected. In practice, the guest can remain blocked in WFI with work pending.
The same pending/mask protocol is shared by VS soft interrupts, PMU overflow delivery, and AIA high interrupt synchronization, so the race is not limited to one interrupt source.
Fix this by serializing all updates to irqs_pending and irqs_pending_mask with a per-vCPU raw spinlock. This keeps the pending bit and the dirty mask as one state transition across:
- set/unset interrupt
- guest HVIP sync
- interrupt flush to guest CSR state
- vCPU reset
- AIA CSR writes that clear dirty state
Use non-atomic bitmap operations while holding the lock. Hold the lock across the AIA sync, flush, and pending checks as well, so both bitmap words share the same serialization domain.
This intentionally replaces the existing lockless protocol instead of trying to repair it with additional barriers. The problem is not memory ordering on a single field; it is that two separate bitmaps encode one shared state machine while both producers and sync paths can modify them. A per-vCPU raw spinlock keeps the fix small, local, and suitable for backporting.
[ bo: Adapt the AIA and general CSR helpers to their 6.18.y layout. ]
--- arch/riscv/include/asm/kvm_host.h | 10 ++--- arch/riscv/kvm/aia.c | 35 ++++++++++++---- arch/riscv/kvm/vcpu.c | 68 ++++++++++++++++++++++--------- arch/riscv/kvm/vcpu_onereg.c | 8 +++- 4 files changed, 87 insertions(+), 34 deletions(-)
arch/riscv/include/asm/kvm_host.h +5 -5
@@ -220,13 +220,13 @@ struct kvm_vcpu_arch {/* * VCPU interrupts * -* We have a lockless approach for tracking pending VCPU interrupts -* implemented using atomic bitops. The irqs_pending bitmap represent -* pending interrupts whereas irqs_pending_mask represent bits changed -* in irqs_pending. Our approach is modeled around multiple producer -* and single consumer problem where the consumer is the VCPU itself. +* The irqs_pending bitmap represents pending interrupts whereas +* irqs_pending_mask represents bits changed in irqs_pending. Updates +* to these bitmaps are serialized so vcpu interrupt sync/flush cannot +* drop a newly injected interrupt while syncing guest-visible HVIP. */ #define KVM_RISCV_VCPU_NR_IRQS 64 +raw_spinlock_t irqs_pending_lock;DECLARE_BITMAP (irqs_pending,KVM_RISCV_VCPU_NR_IRQS );DECLARE_BITMAP (irqs_pending_mask,KVM_RISCV_VCPU_NR_IRQS );
arch/riscv/kvm/aia.c +28 -7
@@ -50,12 +50,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;unsigned long mask, val; +lockdep_assert_held (&vcpu->arch.irqs_pending_lock); +if (!kvm_riscv_aia_available ())return ; -if (READ_ONCE (vcpu->arch.irqs_pending_mask[1 ])) { - mask =xchg_acquire (&vcpu->arch.irqs_pending_mask[1 ],0 ); - val =READ_ONCE (vcpu->arch.irqs_pending[1 ]) & mask; + mask = vcpu->arch.irqs_pending_mask[1 ]; +if (mask) { + vcpu->arch.irqs_pending_mask[1 ] =0 ; + val = vcpu->arch.irqs_pending[1 ] & mask; csr->hviph &= ~mask; csr->hviph |= val;
@@ -66,6 +69,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) {struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; +lockdep_assert_held (&vcpu->arch.irqs_pending_lock); +if (kvm_riscv_aia_available ()) csr->vsieh =ncsr_read (CSR_VSIEH ); }
@@ -74,13 +79,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)bool kvm_riscv_vcpu_aia_has_interrupts (struct kvm_vcpu *vcpu,u64 mask) {unsigned long seip; +#ifdef CONFIG_32BIT +unsigned long flags; +bool pending; +#endif if (!kvm_riscv_aia_available ())return false;#ifdef CONFIG_32BIT -if (READ_ONCE (vcpu->arch.irqs_pending[1 ]) & - (vcpu->arch.aia_context.guest_csr.vsieh &upper_32_bits (mask))) +raw_spin_lock_irqsave (&vcpu->arch.irqs_pending_lock, flags); + pending = vcpu->arch.irqs_pending[1 ] & + (vcpu->arch.aia_context.guest_csr.vsieh & +upper_32_bits (mask)); +raw_spin_unlock_irqrestore (&vcpu->arch.irqs_pending_lock, flags); + +if (pending)return true;#endif
@@ -198,6 +212,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, unsigned long val) {struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; +#ifdef CONFIG_32BIT +unsigned long flags; +#endif if (reg_num >=sizeof (struct kvm_riscv_aia_csr ) /sizeof (unsigned long ))return -ENOENT ;
@@ -206,8 +223,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, ((unsigned long *)csr)[reg_num] = val;#ifdef CONFIG_32BIT -if (reg_num ==KVM_REG_RISCV_CSR_AIA_REG (siph)) -WRITE_ONCE (vcpu->arch.irqs_pending_mask[1 ],0 ); +if (reg_num ==KVM_REG_RISCV_CSR_AIA_REG (siph)) { +raw_spin_lock_irqsave (&vcpu->arch.irqs_pending_lock, flags); + vcpu->arch.irqs_pending_mask[1 ] =0 ; +raw_spin_unlock_irqrestore (&vcpu->arch.irqs_pending_lock, + flags); + }#endif }
arch/riscv/kvm/vcpu.c +48 -20
164 lines not on this page · raw message
arch/riscv/kvm/vcpu_onereg.c +6 -2
@@ -522,6 +522,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, unsigned long reg_val) {struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; +unsigned long flags;if (reg_num >=sizeof (struct kvm_riscv_csr ) /sizeof (unsigned long ))return -ENOENT ;
@@ -533,8 +534,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, ((unsigned long *)csr)[reg_num] = reg_val; -if (reg_num ==KVM_REG_RISCV_CSR_REG (sip)) -WRITE_ONCE (vcpu->arch.irqs_pending_mask[0 ],0 ); +if (reg_num ==KVM_REG_RISCV_CSR_REG (sip)) { +raw_spin_lock_irqsave (&vcpu->arch.irqs_pending_lock, flags); + vcpu->arch.irqs_pending_mask[0 ] =0 ; +raw_spin_unlock_irqrestore (&vcpu->arch.irqs_pending_lock, flags); + }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 162/675 Revert "drm/amd/display: Add missing kdoc for ALLM parameters"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
This reverts commit 038a0f01dda595dceda8f0c9c5172b1297281929.
--- drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c | 2 -- 1 file changed, 2 deletions(-)
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +0 -2
@@ -447,8 +447,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,* * @stream: contains data we may need to construct VSIF (i.e. timing_3d_format, etc.) * @info_packet: output structure where to store VSIF -* @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated -* @ALLMValue: ALLM bit value to advertise in HF-VSIF */ void mod_build_hf_vsif_infopacket (const struct dc_stream_state *stream,struct dc_info_packet *info_packet)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 163/675 usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xincheng Zhang <[email protected]>
commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream.
The VIA VL805/806 xHCI controller advertises AC64, but fails to handle DMA addresses at or above 0x1000000000. On systems with large amounts of RAM, this can cause USB device failures when the controller is given DMA addresses beyond its usable address width.
Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears the cached AC64 capability and limits DMA to 32 bits, causing unnecessary bouncing for addresses between 4GiB and 64GiB and hiding the controller's real AC64 capability from code that may need to distinguish register access width from usable DMA address width.
Track the usable DMA address width separately from the AC64 capability. Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks reduce it for controllers with narrower DMA support. Set VIA VL805/806 to 36 bits so the DMA API only hands it addresses in the range it can handle while keeping HCCPARAMS1.AC64 visible.
--- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci.c | 15 ++++++++++----- drivers/usb/host/xhci.h | 1 + 3 files changed, 12 insertions(+), 5 deletions(-)
drivers/usb/host/xhci-pci.c +1 -0
@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)if (pdev->vendor ==PCI_VENDOR_ID_VIA && pdev->device ==PCI_DEVICE_ID_VIA_VL805 ) { xhci->quirks |=XHCI_LPM_SUPPORT ; xhci->quirks |=XHCI_TRB_OVERFETCH ; + xhci->dma_mask_bits =36 ; } if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
drivers/usb/host/xhci.c +10 -5
@@ -5459,6 +5459,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)if (xhci->hci_version >0x100 ) xhci->hcc_params2 =readl (&xhci->cap_regs->hcc_params2); + xhci->dma_mask_bits =64 ;/* xhci-plat or xhci-pci might have set max_interrupters already */ if ((!xhci->max_interrupters) || xhci->max_interrupters >HCS_MAX_INTRS (xhci->hcs_params1))
@@ -5505,12 +5506,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)if (xhci->quirks &XHCI_NO_64BIT_SUPPORT ) xhci->hcc_params &= ~BIT (0 ); -/* Set dma_mask and coherent_dma_mask to 64-bits, -* if xHC supports 64-bit addressing */ +/* +* Set dma_mask and coherent_dma_mask to 64-bits if xHC supports +* 64-bit addressing, unless a controller-specific quirk callback +* limits the usable address width. +*/ if (HCC_64BIT_ADDR (xhci->hcc_params) && - !dma_set_mask (dev,DMA_BIT_MASK (64 ))) { -xhci_dbg (xhci,"Enabling 64-bit DMA addresses.\n" ); -dma_set_coherent_mask (dev,DMA_BIT_MASK (64 )); + !dma_set_mask (dev,DMA_BIT_MASK (xhci->dma_mask_bits))) { +xhci_dbg (xhci,"Enabling %u-bit DMA addresses.\n" , + xhci->dma_mask_bits); +dma_set_coherent_mask (dev,DMA_BIT_MASK (xhci->dma_mask_bits)); }else {/* * This is to avoid error in cases where a 32-bit USB
drivers/usb/host/xhci.h +1 -0
@@ -1524,6 +1524,7 @@ struct xhci_hcd {/* imod_interval in ns (I * 250ns) */ u32 imod_interval;u32 page_size; +unsigned int dma_mask_bits;/* MSI-X/MSI vectors */ int nvecs;/* optional clocks */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 164/675 selftests/bpf: Adjust verifier_map_ptr for the maps excl field
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: KP Singh <[email protected]>
commit 38498c0ebacd54dbaac3513a548a13f1a8455c4e upstream.
Adding the u32 excl field at offset 32 of struct bpf_map right after the sha[SHA256_DIGEST_SIZE] hash shifts the ops pointer from offset 32 to 40. Therefore, fix up the test case.
# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr [...]
#637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK #637/7 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK #637/8 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK
[...]
Summary: 2/18 PASSED, 0 SKIPPED, 0 FAILED
--- tools/testing/selftests/bpf/progs/verifier_map_ptr.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
tools/testing/selftests/bpf/progs/verifier_map_ptr.c +5 -3
@@ -70,13 +70,15 @@ __naked void bpf_map_ptr_write_rejected(void) : __clobber_all); } -/* The first element of struct bpf_map is a SHA256 hash of 32 bytes, accessing -* into this array is valid. The opts field is now at offset 33. +/* +* struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable +* byte array), followed by the u32 excl field at offset 32. Reading a u32 at +* offset 33 runs past the end of excl and is rejected. */ SEC("socket") __description("bpf_map_ptr: read non-existent field rejected") __failure -__msg("cannot access ptr member ops with moff 32 in struct bpf_map with off 33 size 4") +__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") __failure_unpriv __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")__flag (BPF_F_ANY_ALIGNMENT )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 165/675 selftests/bpf: Keep verifier_map_ptr exercising ops pointer access
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <[email protected]>
commit 082c412097716b93ff1365689fc4ddcd1ce8296f upstream.
sashiko complained that 38498c0ebacd ("selftests/bpf: Adjust verifier_map_ptr for the map's excl field") would slightly decrease the test coverage given before the test was against the verifier rejecting the ops pointer. Recover the old test with the right offsets and add the existing one as an additional test case.
# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr
[ 1.672932] bpf_testmod: module verification failed: signature and/or required key missing - tainting kernel #637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK #637/7 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected:OK #637/8 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected @unpriv:OK #637/9 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK #637/10 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK #637/11 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r:OK #637/12 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r @unpriv:OK #637/13 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr:OK #637/14 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr @unpriv:OK #637 verifier_map_ptr:OK [...] Summary: 2/20 PASSED, 0 SKIPPED, 0 FAILED
--- .../selftests/bpf/progs/verifier_map_ptr.c | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/progs/verifier_map_ptr.c +30 -4
@@ -72,17 +72,43 @@ __naked void bpf_map_ptr_write_rejected(void)/* * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable -* byte array), followed by the u32 excl field at offset 32. Reading a u32 at -* offset 33 runs past the end of excl and is rejected. +* byte array), the u32 excl field at offset 32, and the ops pointer at offset +* 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer, +* i.e. a partial pointer access, which is rejected. */ SEC("socket") __description("bpf_map_ptr: read non-existent field rejected") __failure -__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") +__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4") __failure_unpriv __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN")__flag (BPF_F_ANY_ALIGNMENT) __naked void read_non_existent_field_rejected(void) +{ + asmvolatile (" \ +r6 = 0; \ +r1 = %[map_array_48b] ll; \ +r6 = *(u32*)(r1 + 41); \ +r0 = 1; \ +exit; \ +" : + : __imm_addr(map_array_48b) + : __clobber_all); +} + +/* +* The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset +* 33 starts inside excl but extends past its end, which the verifier rejects +* as an out-of-bounds scalar access. +*/ +SEC("socket") +__description("bpf_map_ptr: read beyond excl field rejected") +__failure +__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") +__failure_unpriv +__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") +__flag (BPF_F_ANY_ALIGNMENT) +__naked void read_beyond_excl_field_rejected(void) { asm volatile (" \ r6 = 0; \
@@ -105,7 +131,7 @@ __naked void ptr_read_ops_field_accepted(void) asmvolatile (" \ r6 = 0; \ r1 = %[map_array_48b] ll; \ -r6 = *(u64*)(r1 + 0); \ +r6 = *(u64*)(r1 + 40); \ r0 = 1; \ exit; \ " :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 166/675 wifi: ath9k: hif_usb: dont dereference hif_dev after re-arming firmware request
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Yongkang <[email protected]>
[ Upstream commit dad9f96945d77ecd4708f730c06ef54dcd8cc057 ]
ath9k_hif_request_firmware() re-arms an asynchronous firmware load via request_firmware_nowait(), passing hif_dev as the completion context, and then still dereferences hif_dev:
dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", hif_dev->fw_name);
The re-armed callback ath9k_hif_usb_firmware_cb() runs on the "events" workqueue and, when the firmware is missing, walks the retry chain into ath9k_hif_usb_firmware_fail() -> complete_all(&hif_dev->fw_done). That releases the wait_for_completion(&hif_dev->fw_done) in a concurrent ath9k_hif_usb_disconnect(), which then kfree()s hif_dev. The trailing dev_info() in the frame that re-armed the request can therefore read freed memory (hif_dev->udev, the first field of struct hif_device_usb):
BUG: KASAN: slab-use-after-free in ath9k_hif_request_firmware Read of size 8 ... by task kworker/... ath9k_hif_request_firmware ath9k_hif_usb_firmware_cb drivers/net/wireless/ath/ath9k/hif_usb.c:1247 request_firmware_work_func Allocated by ...: ath9k_hif_usb_probe drivers/net/wireless/ath/ath9k/hif_usb.c Freed by ...: ath9k_hif_usb_disconnect -> kfree drivers/net/wireless/ath/ath9k/hif_usb.c
The fw_done barrier only makes disconnect wait for the firmware chain to *terminate*; it does not protect the outer ath9k_hif_request_firmware() frame that re-armed the request and keeps touching hif_dev afterwards.
Drop the post-request dev_info(): it is the only use of hif_dev after the async request is armed, and it is purely informational (the dev_err() on the failure path runs only when request_firmware_nowait() did not arm a callback, so hif_dev is still alive there).
This was first reported by syzbot as a single, non-reproduced crash that was later auto-obsoleted, and was independently rediscovered by the reFuzz fuzzer, which produced a C reproducer (USB-gadget connect/disconnect of an ath9k_htc device whose firmware download fails). The vulnerable code is unchanged and still present in v7.1-rc6, where the slab-use-after-free reproduces under KASAN once the (sub-microsecond) race window is widened.
--- drivers/net/wireless/ath/ath9k/hif_usb.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/net/wireless/ath/ath9k/hif_usb.c +1 -6
@@ -1225,15 +1225,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev, ret =request_firmware_nowait (THIS_MODULE , true, hif_dev->fw_name, &hif_dev->udev->dev,GFP_KERNEL , hif_dev, ath9k_hif_usb_firmware_cb); -if (ret) { +if (ret)dev_err (&hif_dev->udev->dev,"ath9k_htc: Async request for firmware %s failed\n" , hif_dev->fw_name); -return ret; - } - -dev_info (&hif_dev->udev->dev,"ath9k_htc: Firmware %s requested\n" , - hif_dev->fw_name);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 167/675 wifi: ath11k: fix NULL pointer dereference in ath11k_hal_srng_access_begin
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gaole Zhang <[email protected]>
[ Upstream commit e8d85672dd7e2523f774caafba8f858384e18df7 ]
In ATH11K_QMI_EVENT_FW_READY, ATH11K_FLAG_REGISTERED is set unconditionally even when ath11k_core_qmi_firmware_ready() fails. This leaves the driver in an inconsistent state where initialization is considered complete although the firmware ready handling did not finish successfully. During the subsequent SSR, the driver enters the restart path based on this incorrect state and dereferences uninitialized srng members, resulting in a NULL pointer dereference.
Call trace: ath11k_hal_srng_access_begin+0xc/0x60 [ath11k] (P) ath11k_ce_cleanup_pipes+0x17c/0x180 [ath11k] ath11k_core_restart+0x40/0x168 [ath11k]
Fix this by:
- skipping firmware_ready if ATH11K_FLAG_REGISTERED is already set
- setting ATH11K_FLAG_REGISTERED only when firmware_ready succeeds
- setting ATH11K_FLAG_QMI_FAIL and aborting the FW_READY handling on error
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.2.0.c2-00204-QCAMSLSWPLZ-1
--- drivers/net/wireless/ath/ath11k/qmi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath11k/qmi.c +8 -3
@@ -3295,9 +3295,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)clear_bit (ATH11K_FLAG_CRASH_FLUSH , &ab->dev_flags);clear_bit (ATH11K_FLAG_RECOVERY , &ab->dev_flags); -ath11k_core_qmi_firmware_ready (ab); -set_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags); - +if (!test_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags)) { + ret =ath11k_core_qmi_firmware_ready (ab); +if (ret) { +set_bit (ATH11K_FLAG_QMI_FAIL , &ab->dev_flags); +break ; + } +set_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags); + }break ;case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE :break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 168/675 hwmon: (corsair-psu) Stop device IO before calling hid_hw_stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit 9ab8656548cd737b98d0b19c4253aff8d68e97f4 ]
hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within corsairpsu_probe(). If the probe operation fails after "io start" has been initiated, this race condition will result in a uaf vulnerability [1].
CPU0 CPU1
==== ====corsairpsu_probe()
hid_device_io_start()
... unlock driver_input_lock
hid_hw_stop()
kfree(hidraw) __hid_input_report()
... acquire driver_input_lock hid_report_raw_event()
hidraw_report_event()
... access hidraw's list_lock // trigger uaf
Consequently, when corsairpsu_probe() fails and hid_hw_stop() needs to be executed, the io_started flag is first cleared while holding the driver_input_lock to prevent potential race conditions involving input reports.
[1]
BUG: KASAN: slab-use-after-free in rt_spin_lock+0x83/0x400 kernel/locking/spinlock_rt.c:56 Call Trace: hidraw_report_event+0x5d/0x3a0 drivers/hid/hidraw.c:577 hid_report_raw_event+0x311/0x1730 drivers/hid/hid-core.c:2076 __hid_input_report drivers/hid/hid-core.c:2152 [inline] hid_input_report+0x44e/0x580 drivers/hid/hid-core.c:2174 hid_irq_in+0x47e/0x6d0 drivers/hid/usbhid/hid-core.c:286 __usb_hcd_giveback_urb+0x3b3/0x5e0 drivers/usb/core/hcd.c:1657 dummy_timer+0x8a9/0x47d0 drivers/usb/gadget/udc/dummy_hcd.c:2005 Allocated by task 10: hidraw_connect+0x57/0x430 drivers/hid/hidraw.c:606 hid_connect+0x5bf/0x19d0 drivers/hid/hid-core.c:2277 hid_hw_start+0xa8/0x120 drivers/hid/hid-core.c:2387 corsairpsu_probe+0xd9/0x3c0 drivers/hwmon/corsair-psu.c:782 Freed by task 10: hidraw_disconnect+0x4f/0x60 drivers/hid/hidraw.c:662 hid_disconnect drivers/hid/hid-core.c:2362 [inline] hid_hw_stop+0x101/0x1e0 drivers/hid/hid-core.c:2407 corsairpsu_probe+0x327/0x3c0 drivers/hwmon/corsair-psu.c:826
Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().
[groeck: Updated subject and description;
call hid_device_io_stop() only if IO has been started]
--- drivers/hwmon/corsair-psu.c | 1 + 1 file changed, 1 insertion(+)
drivers/hwmon/corsair-psu.c +1 -0
@@ -831,6 +831,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id fail_and_close:hid_hw_close (hdev); +hid_device_io_stop (hdev); fail_and_stop:hid_hw_stop (hdev);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 169/675 hwmon: (corsair-cpro) Stop device IO before calling hid_hw_stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 94c87871b051d7ad758828a805215a2ec194512a ]
Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.
Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().
--- drivers/hwmon/corsair-cpro.c | 1 + 1 file changed, 1 insertion(+)
drivers/hwmon/corsair-cpro.c +1 -0
@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) out_hw_close:hid_hw_close (hdev); +hid_device_io_stop (hdev); out_hw_stop:hid_hw_stop (hdev);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 170/675 hwmon: (gigabyte_waterforce) Stop device IO before calling hid_hw_stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit ff0c5c53d08274e200b48a4d53aa078265e873cb ]
Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.
Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().
--- drivers/hwmon/gigabyte_waterforce.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/gigabyte_waterforce.c +3 -1
@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_idif (IS_ERR (priv->hwmon_dev)) { ret =PTR_ERR (priv->hwmon_dev);hid_err (hdev,"hwmon registration failed with %d\n" , ret); - goto fail_and_close; + goto fail_and_io_stop; }waterforce_debugfs_init (priv);return 0 ; +fail_and_io_stop: +hid_device_io_stop (hdev); fail_and_close:hid_hw_close (hdev); fail_and_stop:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 171/675 hwmon: (nzxt-smart2) Stop device IO before calling hid_hw_stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 59d104b54b0b42e30fd2a68d24ee5c49dcc54d1e ]
Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.
Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().
--- drivers/hwmon/nzxt-smart2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/nzxt-smart2.c +1 -1
@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev, out_hw_close:hid_hw_close (hdev); - +hid_device_io_stop (hdev); out_hw_stop:hid_hw_stop (hdev);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 172/675 hwmon: (nzxt-kraken3) Stop device IO before calling hid_hw_stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit f151d0143ac4e086f92f52328ebdbdc50933d8ef ]
Calling hid_hw_stop() does not stop the device IO.
This results in a race condition between hid_input_report() and the point immediately following the execution of hid_device_io_start() within the driver probe function. If the probe operation fails after "io start" has been initiated, this race condition will result in a UAF vulnerability.
Fix the problem by calling hid_device_io_stop() before calling hid_hw_stop().
--- drivers/hwmon/nzxt-kraken3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/hwmon/nzxt-kraken3.c +4 -2
@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id ret =kraken3_init_device (hdev);if (ret <0 ) {hid_err (hdev,"device init failed with %d\n" , ret); - goto fail_and_close; + goto fail_and_stop_io; } ret =kraken3_get_fw_ver (hdev);
@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *idif (IS_ERR (priv->hwmon_dev)) { ret =PTR_ERR (priv->hwmon_dev);hid_err (hdev,"hwmon registration failed with %d\n" , ret); - goto fail_and_close; + goto fail_and_stop_io; }kraken3_debugfs_init (priv, device_name);return 0 ; +fail_and_stop_io: +hid_device_io_stop (hdev); fail_and_close:hid_hw_close (hdev); fail_and_stop:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 173/675 watchdog: pretimeout: Fix UAF in watchdog_unregister_governor()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 7362ba0f9c96ac3ad6a2ca3995bd9fc9a28a8661 ]
When a watchdog governor is unregistered, it updates existing watchdog devices that were using this governor by falling back to default_gov.
If the governor being unregistered is currently set as default_gov, the default_gov is never cleared. This leads to 2 use-after-free issues:
1. New watchdog devices registered after this point will inherit the dangling default_gov.
2. Existing watchdog devices using the unregistered governor will have their wdd->gov reassigned to the dangling default_gov.
Fix the UAF by clearing default_gov if it matches the governor being unregistered.
--- drivers/watchdog/watchdog_pretimeout.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/watchdog/watchdog_pretimeout.c +2 -0
@@ -167,6 +167,8 @@ void watchdog_unregister_governor(struct watchdog_governor *gov) }spin_lock_irq (&pretimeout_lock); +if (default_gov == gov) + default_gov =NULL ;list_for_each_entry (p, &pretimeout_list, entry)if (p->wdd->gov == gov) p->wdd->gov = default_gov;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 174/675 watchdog: airoha: Prevent division by zero when clock frequency is zero
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wayen Yan <[email protected]>
[ Upstream commit bcfcd7619f277842430d197556463b401b839ee9 ]
clk_get_rate() can return 0 when the clock provider is not properly configured or the clock is unmanaged. The driver uses wdt_freq as a divisor directly in airoha_wdt_probe() to compute max_timeout and in airoha_wdt_get_timeleft() to compute the remaining time, which results in a division by zero.
Add a check for wdt_freq == 0 in probe and return -EINVAL with dev_err_probe() to prevent the division by zero and provide a diagnostic message.
--- drivers/watchdog/airoha_wdt.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/watchdog/airoha_wdt.c +3 -0
@@ -147,6 +147,9 @@ static int airoha_wdt_probe(struct platform_device *pdev)/* Watchdog ticks at half the bus rate */ airoha_wdt->wdt_freq =clk_get_rate (bus_clk) /2 ; +if (!airoha_wdt->wdt_freq) +return dev_err_probe (dev, -EINVAL , +"invalid clock frequency\n" );/* Initialize struct watchdog device */ wdog_dev = &airoha_wdt->wdog_dev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 175/675 wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Morgun <[email protected]>
[ Upstream commit 7f11e70629650ff6ea140984e5ce188b775b2683 ]
When the first entry in msdu_details has a zero buffer address, the code accesses msdu_details[i - 1] with i == 0, causing a buffer underflow.
Fix similarly to ath12k_wifi7_hal_rx_msdu_list_get() by adding a separate check for i == 0 before the main condition to prevent the out-of-bounds access.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/net/wireless/ath/ath11k/dp_rx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/ath11k/dp_rx.c +3 -0
@@ -4609,6 +4609,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar, msdu_details = &msdu_link->msdu_link[0 ];for (i =0 ; i <HAL_RX_NUM_MSDU_DESC ; i++) { +if (!i &&FIELD_GET (BUFFER_ADDR_INFO0_ADDR , + msdu_details[i].buf_addr_info.info0) ==0 ) +break ;if (FIELD_GET (BUFFER_ADDR_INFO0_ADDR , msdu_details[i].buf_addr_info.info0) ==0 ) { msdu_desc_info = &msdu_details[i -1 ].rx_msdu_info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 176/675 wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 0fe8010fc5b147607fc19ba010ba469afc95f35f ]
ath11k_pci_soc_global_reset() tries to reset the device by writing to the PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure that the write gets flushed to the device before the delay.
This may lead to the delay on the host to be insufficient, if the posted write doesn't reach the device before the delay.
So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and before the delay.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/pci.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/ath11k/pci.c +4 -0
@@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) val |=PCIE_SOC_GLOBAL_RESET_V ;ath11k_pcic_write32 (ab,PCIE_SOC_GLOBAL_RESET , val); +/* Flush the posted write to the device */ +ath11k_pcic_read32 (ab,PCIE_SOC_GLOBAL_RESET );/* TODO: exact time to sleep is uncertain */ delay =10 ;
@@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) val &= ~PCIE_SOC_GLOBAL_RESET_V ;ath11k_pcic_write32 (ab,PCIE_SOC_GLOBAL_RESET , val); +/* Flush the posted write to the device */ +ath11k_pcic_read32 (ab,PCIE_SOC_GLOBAL_RESET );mdelay (delay);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 177/675 wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 55f3aa06951cac78b0206bde961c8cf11929a27a ]
ath12k_pci_soc_global_reset() tries to reset the device by writing to the PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure that the write gets flushed to the device before the delay.
This may lead to the delay on the host to be insufficient, if the posted write doesn't reach the device before the delay.
So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and before the delay.
Compile tested only.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
--- drivers/net/wireless/ath/ath12k/pci.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/ath12k/pci.c +4 -0
@@ -240,6 +240,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) val |=PCIE_SOC_GLOBAL_RESET_V ;ath12k_pci_write32 (ab,PCIE_SOC_GLOBAL_RESET , val); +/* Flush the posted write to the device */ +ath12k_pci_read32 (ab,PCIE_SOC_GLOBAL_RESET );/* TODO: exact time to sleep is uncertain */ delay =10 ;
@@ -249,6 +251,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) val &= ~PCIE_SOC_GLOBAL_RESET_V ;ath12k_pci_write32 (ab,PCIE_SOC_GLOBAL_RESET , val); +/* Flush the posted write to the device */ +ath12k_pci_read32 (ab,PCIE_SOC_GLOBAL_RESET );mdelay (delay);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 178/675 firewire: net: Fix fragmented datagram reassembly
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit d52a13adbb8ccbab99cd3bad36804e87d8b5c052 ]
fwnet_frag_new() keeps a sorted list of received fragments for a partial datagram. When a new fragment is adjacent to an existing fragment, the code checks whether the new fragment also closes the gap to the next or previous list entry.
Those neighbor lookups currently assume that the current fragment always has a real next or previous fragment. At a list edge, the next or previous entry is the list head, not a struct fwnet_fragment_info.
The gap checks also compare against the old edge of the current fragment instead of the edge after adding the new fragment. As a result, a fragment that bridges two existing ranges may leave two adjacent ranges unmerged, so fwnet_pd_is_complete() can miss a complete datagram.
Check for the list head before looking up the neighboring fragment, and compare the neighbor against the new fragment's far edge when deciding whether to merge all three ranges.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/firewire/net.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-)
drivers/firewire/net.c +21 -18
@@ -298,31 +298,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(if (fi->offset + fi->len == offset) {/* The new fragment can be tacked on to the end */ /* Did the new fragment plug a hole? */ - fi2 =list_entry (fi->fi_link.next, - struct fwnet_fragment_info, fi_link); -if (fi->offset + fi->len == fi2->offset) { -/* glue fragments together */ - fi->len += len + fi2->len; -list_del (&fi2->fi_link); -kfree (fi2); - }else { - fi->len += len; +if (!list_is_last (&fi->fi_link, &pd->fi_list)) { + fi2 =list_next_entry (fi, fi_link); +if (offset + len == fi2->offset) { +/* glue fragments together */ + fi->len += len + fi2->len; +list_del (&fi2->fi_link); +kfree (fi2); + +return fi; + } } + fi->len += len;return fi; }if (offset + len == fi->offset) {/* The new fragment can be tacked on to the beginning */ /* Did the new fragment plug a hole? */ - fi2 =list_entry (fi->fi_link.prev, - struct fwnet_fragment_info, fi_link); -if (fi2->offset + fi2->len == fi->offset) { -/* glue fragments together */ - fi2->len += fi->len + len; -list_del (&fi->fi_link); -kfree (fi); - -return fi2; +if (!list_is_first (&fi->fi_link, &pd->fi_list)) { + fi2 =list_prev_entry (fi, fi_link); +if (fi2->offset + fi2->len == offset) { +/* glue fragments together */ + fi2->len += fi->len + len; +list_del (&fi->fi_link); +kfree (fi); + +return fi2; + } } fi->offset = offset; fi->len += len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 179/675 wifi: ath6kl: fix OOB read from firmware num_msg in TX complete handler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 3a21c89215cc18f1a97c5e5bfd1da6d4f3d44495 ]
The firmware-controlled num_msg field (u8, 0-255) drives the loop in ath6kl_wmi_tx_complete_event_rx() without validation against the buffer length. This allows out-of-bounds reads of up to 1020 bytes past the WMI event buffer when the firmware sends an inflated num_msg.
Add a check that the buffer is large enough to hold the fixed struct and the num_msg variable-length entries.
--- drivers/net/wireless/ath/ath6kl/wmi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/net/wireless/ath/ath6kl/wmi.c +12 -0
@@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) evt = (struct wmi_tx_complete_event *) datap; +if (len <sizeof (*evt)) { +ath6kl_dbg (ATH6KL_DBG_WMI ,"tx complete: invalid len %d\n" , + len); +return -EINVAL ; + } + +if (len <sizeof (*evt) + evt->num_msg *sizeof (struct tx_complete_msg_v1 )) { +ath6kl_dbg (ATH6KL_DBG_WMI ,"tx complete: invalid len %d for %u msgs\n" , + len, evt->num_msg); +return -EINVAL ; + } +ath6kl_dbg (ATH6KL_DBG_WMI ,"comp: %d %d %d\n" , evt->num_msg, evt->msg_len, evt->msg_type);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 180/675 wifi: ath6kl: fix OOB read from firmware IE lengths in connect event
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 6b47b29730de3232b919d8362749f6814c5f2a33 ]
The firmware-controlled beacon_ie_len, assoc_req_len, and assoc_resp_len fields in ath6kl_wmi_connect_event_rx() are not validated against the buffer length. Their sum (up to 765) can exceed the actual WMI event data, causing out-of-bounds reads during IE parsing and state corruption of wmi->is_wmm_enabled.
Add a check that the total IE length fits within the buffer.
--- drivers/net/wireless/ath/ath6kl/wmi.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/wireless/ath/ath6kl/wmi.c +8 -0
@@ -874,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, ev = (struct wmi_connect_event *) datap; +if (len <sizeof (*ev) + ev->beacon_ie_len + + ev->assoc_req_len + ev->assoc_resp_len) { +ath6kl_dbg (ATH6KL_DBG_WMI , +"connect event: IE lengths %u+%u+%u exceed buffer %d\n" , + ev->beacon_ie_len, ev->assoc_req_len, + ev->assoc_resp_len, len); +return -EINVAL ; + }if (vif->nw_type ==AP_NETWORK ) {/* AP mode start/STA connected event */ struct net_device *dev = vif->ndev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 181/675 wifi: carl9170: bound memcpy length in cmd callback to prevent OOB read
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 4cde55b2feff9504d1f993ab80e84e7ccb62791c ]
When the firmware sends a command response with a length mismatch, carl9170_cmd_callback() logs the mismatch and calls carl9170_restart() but then falls through to memcpy(ar->readbuf, buffer + 4, len - 4). Since len comes from the firmware and can exceed ar->readlen, this copies more data than the readbuf was allocated for.
Bound the memcpy to min(len - 4, ar->readlen) so that the response is still completed -- avoiding repeated restarts from queued garbage -- while preventing an overread past the response buffer.
--- drivers/net/wireless/ath/carl9170/rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/rx.c +2 -1
@@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)spin_lock (&ar->cmd_lock);if (ar->readbuf) {if (len >=4 ) -memcpy (ar->readbuf, buffer +4 , len -4 ); +memcpy (ar->readbuf, buffer +4 , +min_t (u32, len -4 , ar->readlen)); ar->readbuf =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 182/675 wifi: carl9170: fix OOB read from off-by-two in TX status handler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit a3f42f1049ad80c65560d2b078ad426c3134f78d ]
The bounds check in carl9170_tx_process_status() usesi > ((cmd->hdr.len / 2) + 1) which is off by two, allowing 2 extra iterations past valid _tx_status entries when the firmware- controlled hdr.ext exceeds hdr.len/2. Fix by using the correct comparison i >= (cmd->hdr.len / 2).
--- drivers/net/wireless/ath/carl9170/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/tx.c +1 -1
@@ -692,7 +692,7 @@ void carl9170_tx_process_status(struct ar9170 *ar,unsigned int i;for (i =0 ; i < cmd->hdr.ext; i++) { -if (WARN_ON (i > ((cmd->hdr.len /2 ) +1 ))) { +if (WARN_ON (i >= (cmd->hdr.len /2 ))) {print_hex_dump_bytes ("UU:" ,DUMP_PREFIX_NONE , (void *) cmd, cmd->hdr.len +4 );break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 183/675 wifi: carl9170: fix buffer overflow in rx_stream failover path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit a1a21995c2e1cc2ca6b2226cfe4f5f018370182a ]
The failover continuation in carl9170_rx_stream() copies the full tlen from the second USB transfer instead of capping at rx_failover_missing bytes. When both transfers are near maximum size, the total exceeds the 65535-byte failover SKB, triggering skb_over_panic.
Limit the copy size to the missing byte count.
--- drivers/net/wireless/ath/carl9170/rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/carl9170/rx.c +3 -1
@@ -918,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) } } -skb_put_data (ar->rx_failover, tbuf, tlen); +skb_put_data (ar->rx_failover, tbuf, + min_t(unsigned int, tlen, + ar->rx_failover_missing)); ar->rx_failover_missing -= tlen;if (ar->rx_failover_missing <=0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 184/675 btrfs: declare btrfs_ioctl_search_args_v2::buf as __u8
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: You-Kai Zheng <[email protected]>
[ Upstream commit b95181f3929ff98949fa9460ca93eccebbf2d7fc ]
The variable-sized buffer buf in struct btrfs_ioctl_search_args_v2 is declared as __u64[], but it holds a packed byte stream of search results, where all offsets into the buffer are in bytes.
Declaring buf as __u64[] makes it easy for user space to write incorrect pointer arithmetic: adding a byte offset directly to a __u64 pointer scales the offset by 8, landing at byte position offset*8 instead of offset.
This recently caused an infinite loop in btrfs-progs: the accessor read all-zero data from misaddressed items, which fed zeroed search keys back into the ioctl loop and spun forever. The issue was worked around at the time by disabling TREE_SEARCH_V2 entirely in btrfs-progs (d73e69824854:
"btrfs-progs: temporarily disable usage of v2 of search tree ioctl").
The kernel side already treats buf as a byte buffer, so change the declaration to __u8[] to match the actual semantics and prevent similar misuse in user space. The change is ABI compatible: both the structure size and alignment are unchanged.
--- include/uapi/linux/btrfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/uapi/linux/btrfs.h +1 -1
@@ -597,7 +597,7 @@ struct btrfs_ioctl_search_args_v2 {__u64 buf_size;/* in - size of buffer * out - on EOVERFLOW: needed size * to store item */ -__u64 buf[];/* out - found items */ +__u8 buf[];/* out - found items */ };/* With a @src_length of zero, the range from @src_offset->EOF is cloned! */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 185/675 btrfs: fix u32 to s64 type conversion in dirty_metadata_bytes accounting
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chen <[email protected]>
[ Upstream commit 8b5a09ceb61b18b1f0797cd30a549d7dc85d8d50 ]
The percpu_counter dirty_metadata_bytes is updated by negating eb->len and passing it to percpu_counter_add_batch(), whose amount parameter is s64. Since commit 84cda1a6087d ("btrfs: cache folio size and shift in extent_buffer"), eb->len is u32. The u32 result of -eb->len, when widened to the s64 parameter, becomes a large positive value instead of the intended negative value. For eb->len == 16384 the counter adds +4294950912 instead of subtracting 16384.
The counter therefore grows on every metadata writeback instead of shrinking by the extent buffer size, permanently exceeding BTRFS_DIRTY_METADATA_THRESH and causing __btrfs_btree_balance_dirty() to trigger balance_dirty_pages_ratelimited() unconditionally, adding unnecessary writeback pressure.
Cast eb->len to s64 before negation at both call sites so the subtraction is performed in signed 64-bit arithmetic.
--- fs/btrfs/extent_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/btrfs/extent_io.c +2 -2
@@ -1949,7 +1949,7 @@ static noinline_for_stack bool lock_extent_buffer_for_io(struct extent_buffer *ebtrfs_set_header_flag (eb,BTRFS_HEADER_FLAG_WRITTEN );percpu_counter_add_batch (&fs_info->dirty_metadata_bytes, - -eb->len, + -(s64 )eb->len, fs_info->dirty_metadata_batch); ret = true; }else {
@@ -3731,7 +3731,7 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,return ;buffer_tree_clear_mark (eb,PAGECACHE_TAG_DIRTY ); -percpu_counter_add_batch (&fs_info->dirty_metadata_bytes, -eb->len, +percpu_counter_add_batch (&fs_info->dirty_metadata_bytes, -(s64 )eb->len, fs_info->dirty_metadata_batch);for (int i =0 ; i <num_extent_folios (eb); i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 186/675 btrfs: dont propagate EXTENT_FLAG_LOGGING to split extent maps
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Martins <[email protected]>
[ Upstream commit 5eff4d5b17fa1950e80bfd1ba43dc0699e61a644 ]
When btrfs_drop_extent_map_range() splits an extent map, the new split maps inherit the original map's flags through a local 'flags' variable. Commit f86f7a75e2fb ("btrfs: use the flags of an extent map to identify the compression type") changed the EXTENT_FLAG_LOGGING clearing to operate on em->flags instead of that local 'flags' copy, so a split of an extent map that is currently being logged wrongly inherits EXTENT_FLAG_LOGGING.
The flag is then never cleared on the split, and when it is freed while still on the inode's modified_extents list (for example by the extent map shrinker) it trips the WARN_ON(!list_empty(&em->list)) in btrfs_free_extent_map() and leads to a use-after-free.
Clear EXTENT_FLAG_LOGGING from the local 'flags' copy used for the splits and only clear EXTENT_FLAG_PINNED from em->flags, restoring the behaviour prior to f86f7a75e2fb.
--- fs/btrfs/extent_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/btrfs/extent_map.c +2 -2
@@ -854,13 +854,13 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end, goto next; } - flags = em->flags;/* * In case we split the extent map, we want to preserve the * EXTENT_FLAG_LOGGING flag on our extent map, but we don't want * it on the new extent maps. */ - em->flags &= ~(EXTENT_FLAG_PINNED |EXTENT_FLAG_LOGGING ); + flags = em->flags & ~EXTENT_FLAG_LOGGING ; + em->flags &= ~EXTENT_FLAG_PINNED ; modified = !list_empty (&em->list);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 187/675 btrfs: free mapping node on duplicate reloc root insert
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <[email protected]>
[ Upstream commit 6a8269b6459ed870a8156c106a0f597383907872 ]
__add_reloc_root() allocates a mapping_node before inserting it into rc->reloc_root_tree. If rb_simple_insert() finds an existing entry, it returns the existing rb_node and leaves the newly allocated node unlinked.
The error path then returns -EEXIST without freeing the new node. Since the node was never inserted into reloc_root_tree, the later cleanup in put_reloc_control() cannot find it either.
Free the newly allocated node before returning -EEXIST.
The callers currently assert that -EEXIST should not happen, so this is a defensive cleanup for an unexpected duplicate insert path. If the path is ever reached, the local allocation should still be released.
--- fs/btrfs/relocation.c | 1 + 1 file changed, 1 insertion(+)
fs/btrfs/relocation.c +1 -0
@@ -496,6 +496,7 @@ static int __add_reloc_root(struct btrfs_root *root)btrfs_err (fs_info,"Duplicate root found for start=%llu while inserting into relocation tree" , node->bytenr); +kfree (node);return -EEXIST ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 188/675 ASoC: tas2781: bound firmware description string parsing
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit bc889dfcea9294a1eae7f8e2f3573a90764ae4d0 ]
The TAS2781 firmware parser reads several variable-length description strings with strlen() before checking that the string terminator is present inside the firmware blob. A malformed firmware image without a NUL terminator can therefore make the parser walk past the end of the firmware buffer before the later size checks run.
Add a small bounded string-length helper and use it for all description fields that are parsed from the firmware buffer. Keep the existing size checks for the fixed bytes that follow each string.
--- sound/soc/codecs/tas2781-fmwlib.c | 63 ++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-)
sound/soc/codecs/tas2781-fmwlib.c +57 -6
@@ -12,6 +12,7 @@#include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/limits.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h>
@@ -1082,13 +1083,42 @@ static int tasdevice_load_block_kernel(return 0 ; } +static int tasdevice_fw_strnlen (const struct firmware *fmw,int offset) +{ +const u8 *start; +const u8 *nul; +size_t remaining; +size_t len; + +if (offset <0 || offset >= fmw->size) +return -EINVAL ; + + start = fmw->data + offset; + remaining = fmw->size - offset; + nul =memchr (start,'\0' , remaining); +if (!nul) +return -EINVAL ; + + len = nul - start; +if (len >INT_MAX ) +return -EOVERFLOW ; + +return len; +} +static int fw_parse_variable_hdr (struct tasdevice_priv *tas_priv,struct tasdevice_dspfw_hdr *fw_hdr,const struct firmware *fmw,int offset) {const unsigned char *buf = fmw->data; -int len =strlen ((char *)&buf[offset]); +int len; + len =tasdevice_fw_strnlen (fmw, offset); +if (len <0 ) { +dev_err (tas_priv->dev,"%s: Description error\n" , __func__); + offset = len; + goto out; + } len++;if (offset + len +8 > fmw->size) {
@@ -1220,7 +1250,12 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,memcpy (img_data->name, &data[offset],64 ); offset +=64 ; - n =strlen ((char *)&data[offset]); + n =tasdevice_fw_strnlen (fmw, offset); +if (n <0 ) { +dev_err (tas_fmw->dev,"%s: Description error\n" , __func__); + offset = n; + goto out; + } n++;if (offset + n +2 > fmw->size) {dev_err (tas_fmw->dev,"%s: Description error\n" , __func__);
@@ -1293,7 +1328,12 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv, } offset +=64 ; - n =strlen ((char *)&buf[offset]); + n =tasdevice_fw_strnlen (fmw, offset); +if (n <0 ) { +dev_err (tas_priv->dev,"Description err\n" ); + offset = n; + goto out; + }/* skip '\0' and 5 unused bytes */ n +=6 ;if (offset + n > fmw->size) {
@@ -1356,7 +1396,12 @@ static int fw_parse_configuration_data(memcpy (config->name, &data[offset],64 ); offset +=64 ; - n =strlen ((char *)&data[offset]); + n =tasdevice_fw_strnlen (fmw, offset); +if (n <0 ) { +dev_err (tas_priv->dev,"Description err\n" ); + offset = n; + goto out; + } n +=15 ;if (offset + n > fmw->size) {dev_err (tas_priv->dev,"Description err\n" );
@@ -2038,7 +2083,8 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv, {struct tasdevice_calibration *calibration;unsigned char *data = (unsigned char *)fmw->data; -unsigned int i, n; +unsigned int i; +int n;if (offset +2 > fmw->size) {dev_err (tas_priv->dev,"%s: Calibrations error\n" , __func__);
@@ -2070,7 +2116,12 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv, calibration = &(tas_fmw->calibrations[i]); offset +=64 ; - n =strlen ((char *)&data[offset]); + n =tasdevice_fw_strnlen (fmw, offset); +if (n <0 ) { +dev_err (tas_priv->dev,"Description err\n" ); + offset = n; + goto out; + }/* skip '\0' and 2 unused bytes */ n +=3 ;if (offset + n > fmw->size) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 189/675 ASoC: sun4i-codec: Set quirks.playback_only for H616 codec
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai <[email protected]>
[ Upstream commit d9e96f859de3ea3e99bce927a988449a1816483c ]
The H616 codec does not have capture capabilities. Set the .playback_only quirks flag to denote this.
This was somehow missing from the original driver patch, even though the patch prior to it in the series added this quirk.
--- sound/soc/sunxi/sun4i-codec.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/sunxi/sun4i-codec.c +1 -0
@@ -2236,6 +2236,7 @@ static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = { .reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, .has_reset = true, + .playback_only = true, .dma_max_burst = SUN4I_DMA_MAX_BURST, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 190/675 ALSA: hda: cs35l41: validate and free ACPI mute object
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 3b597d24dc0455ae926f1053f97c2725038fc3cd ]
cs35l41_get_acpi_mute_state() evaluates a _DSM method to get the ACPI mute state and reads the first byte from the returned object.
However, the returned ACPI object is owned by the caller and is never freed after use, so each successful query leaks the _DSM result object.
The code also assumes that the returned object is a buffer with at least one byte. A malformed firmware response can return a different object type or an empty buffer, and the direct ret->buffer.pointer dereference can then access an invalid pointer.
Use the typed _DSM helper, validate that the returned buffer contains at least one byte, and free the ACPI object after reading it.
--- sound/hda/codecs/side-codecs/cs35l41_hda.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
sound/hda/codecs/side-codecs/cs35l41_hda.c +10 -1
@@ -1437,10 +1437,19 @@ static int cs35l41_get_acpi_mute_state(struct cs35l41_hda *cs35l41, acpi_handleguid_parse (CS35L41_UUID , &guid);if (cs35l41_dsm_supported (handle,CS35L41_DSM_GET_MUTE )) { - ret =acpi_evaluate_dsm (handle, &guid,0 ,CS35L41_DSM_GET_MUTE ,NULL ); + ret =acpi_evaluate_dsm_typed (handle, &guid,0 , +CS35L41_DSM_GET_MUTE ,NULL , +ACPI_TYPE_BUFFER ); +if (!ret)return -EINVAL ; +if (!ret->buffer.length || !ret->buffer.pointer) { +ACPI_FREE (ret); +return -EINVAL ; + } + mute = *ret->buffer.pointer; +ACPI_FREE (ret);dev_dbg (cs35l41->dev,"CS35L41_DSM_GET_MUTE: %d\n" , mute); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 191/675 ASoC: bt-sco: fix duplicate DAPM widget names for wideband DAI
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit 0b604e886ece11b71c4daaeccc512c784b89b014 ]
The bt-sco-pcm-wb DAI uses the same stream_name strings as bt-sco-pcm ("Playback" and "Capture"). This causes duplicate DAPM AIF widget names within the same component, leading to debugfs warnings:
debugfs: 'Playback' already exists in 'dapm'
debugfs: 'Capture' already exists in 'dapm'
Give the wideband DAI distinct stream names ("WB Playback" and "WB Capture") and add corresponding DAPM AIF widgets and routes for them.
--- sound/soc/codecs/bt-sco.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
sound/soc/codecs/bt-sco.c +8 -2
@@ -17,11 +17,17 @@ static const struct snd_soc_dapm_widget bt_sco_widgets[] = { SND_SOC_NOPM, 0, 0),SND_SOC_DAPM_AIF_OUT ("BT_SCO_TX" ,"Capture" ,0 ,SND_SOC_NOPM ,0 ,0 ), +SND_SOC_DAPM_AIF_IN ("BT_SCO_RX_WB" ,"WB Playback" ,0 , +SND_SOC_NOPM ,0 ,0 ), +SND_SOC_DAPM_AIF_OUT ("BT_SCO_TX_WB" ,"WB Capture" ,0 , + SND_SOC_NOPM, 0, 0), };static const struct snd_soc_dapm_route bt_sco_routes[] = { {"BT_SCO_TX" ,NULL ,"RX" }, {"TX" ,NULL ,"BT_SCO_RX" }, + {"BT_SCO_TX_WB" ,NULL ,"RX" }, + {"TX" ,NULL ,"BT_SCO_RX_WB" }, }; static struct snd_soc_dai_driver bt_sco_dai[] = {
@@ -45,14 +51,14 @@ static struct snd_soc_dai_driver bt_sco_dai[] = { { .name = "bt-sco-pcm-wb", .playback = { - .stream_name = "Playback", + .stream_name = "WB Playback", .channels_min = 1, .channels_max = 1, .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { - .stream_name = "Capture", + .stream_name = "WB Capture", .channels_min = 1, .channels_max = 1, .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 192/675 ASoC: cs35l56: Dont use devres to unregister component
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit bee87cf0f1248c0f20710d7a79df41fe892d9f88 ]
Manually call snd_soc_unregister_component() from cs35l56_remove() instead of using devres cleanup. This ensures that the component is destroyed before cs35l56_remove() starts cleanup of anything the component code could be using.
Devres cleanup happens after the driver remove() callback, so if snd_soc_register_component() is used, it will not be destroyed until after cs35l56_remove() has returned. But there is some cleanup that must be done in cs35l56_remove(), or wrapped in a custom devres cleanup handler to ensure correct ordering. The simplest option is to call snd_soc_unregister_component() at the start of cs35l56_remove().
Stable-dep-of: 93c2a8ea2454 ("ASoC: cs35l56: Fix potential probe() deadlock")
--- sound/soc/codecs/cs35l56.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
sound/soc/codecs/cs35l56.c +5 -3
@@ -1437,9 +1437,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) goto err; } - ret =devm_snd_soc_register_component (cs35l56->base.dev, - &soc_component_dev_cs35l56, - cs35l56_dai,ARRAY_SIZE (cs35l56_dai)); + ret =snd_soc_register_component (cs35l56->base.dev, + &soc_component_dev_cs35l56, + cs35l56_dai,ARRAY_SIZE (cs35l56_dai));if (ret <0 ) {dev_err_probe (cs35l56->base.dev, ret,"Register codec failed\n" ); goto err_remove_wm_adsp;
@@ -1541,6 +1541,8 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE");void cs35l56_remove (struct cs35l56_private *cs35l56) { +snd_soc_unregister_component (cs35l56->base.dev); + cs35l56->base.init_done = false;/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 193/675 ASoC: cs35l56: Fix potential probe() deadlock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit 93c2a8ea2454b7b14eb378a58cad8a83c0ffc903 ]
On I2C/SPI call cs35l56_init() before calling snd_soc_register_component() to prevent the potential for a deadlock on init_completion.
For most buses all the hardware would be ready when probe() returns, but on SoundWire, probe() must return before the SoundWire bus driver will enumerate the device. All access to the registers must be deferred until the driver receives an ATTACHED notification. But anything that could return -EPROBE_DEFER must be called during probe, and that includes snd_soc_register_component(). Because of that, on SoundWire the ASoC component can be created before the registers are accssible, so cs35l56_component_probe() waits for init_completion to signal that the registers are accessible.
On I2C/SPI this 2-stage startup isn't required so their probe() functions simply called cs35l56_common_probe() and then cs35l56_init(). The problem with this was that snd_soc_register_component() was still called early. If this triggered ASoC to create the card, ASoC would call cs35l56_component_probe() which waits on init_completion - but this would be running inside the cs35l56 driver probe() so blocking it from reaching the code that signals init_completion, causing a deadlock.
--- sound/soc/codecs/cs35l56-i2c.c | 4 +--- sound/soc/codecs/cs35l56-spi.c | 4 +--- sound/soc/codecs/cs35l56.c | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-)
sound/soc/codecs/cs35l56-i2c.c +1 -3
@@ -55,9 +55,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)if (ret !=0 )return ret; - ret =cs35l56_init (cs35l56); -if (ret ==0 ) - ret =cs35l56_irq_request (&cs35l56->base, client->irq); + ret =cs35l56_irq_request (&cs35l56->base, client->irq);if (ret <0 )cs35l56_remove (cs35l56);
sound/soc/codecs/cs35l56-spi.c +1 -3
@@ -44,9 +44,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)if (ret !=0 )return ret; - ret =cs35l56_init (cs35l56); -if (ret ==0 ) - ret =cs35l56_irq_request (&cs35l56->base, spi->irq); + ret =cs35l56_irq_request (&cs35l56->base, spi->irq);if (ret <0 )cs35l56_remove (cs35l56);
sound/soc/codecs/cs35l56.c +15 -0
@@ -1437,6 +1437,16 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) goto err; } +/* +* On SoundWire the cs35l56_init() cannot be run until after the +* device has been enumerated by the SoundWire core. +*/ +if (!cs35l56->sdw_peripheral) { + ret =cs35l56_init (cs35l56); +if (ret) + goto err_remove_wm_adsp; + } + ret =snd_soc_register_component (cs35l56->base.dev, &soc_component_dev_cs35l56, cs35l56_dai,ARRAY_SIZE (cs35l56_dai));
@@ -1451,6 +1461,11 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)wm_adsp2_remove (&cs35l56->dsp); err: +if (pm_runtime_enabled (cs35l56->base.dev)) { +pm_runtime_dont_use_autosuspend (cs35l56->base.dev); +pm_runtime_disable (cs35l56->base.dev); + } +gpiod_set_value_cansleep (cs35l56->base.reset_gpio,0 );regulator_bulk_disable (ARRAY_SIZE (cs35l56->supplies), cs35l56->supplies);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 194/675 ASoC: cs35l56: Use complete_all() to signal init_completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit e0bffb63a2eda0af82ed7e6357ac67c2db990c21 ]
In cs35l56_init() use complete_all() to signal init_completion instead of complete().
cs35l56_init() was signaling init_completion using the complete() function. This only releases ONE waiter.
If cs35l56_component_probe() was called multiple times the first time would consume that one signal, then future calls would timeout waiting for the completion. This could happen if:
- The component is probed, removed, then probed again without the cs35l56 module being removed.
- A call to component_probe() returns an error and ASoC calls it again later.
It should use complete_all() so that after it has been signaled it will allow any code that waits on it to continue immediately.
The one case where the driver must wait for initialization to run again is when waiting for a reboot after firmware download, and here the code correctly calls reinit_completion() first.
--- sound/soc/codecs/cs35l56.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/cs35l56.c +1 -1
@@ -1548,7 +1548,7 @@ int cs35l56_init(struct cs35l56_private *cs35l56)return dev_err_probe (cs35l56->base.dev, ret,"Failed to write ASP1_CONTROL3\n" ); cs35l56->base.init_done = true; -complete (&cs35l56->init_completion); +complete_all (&cs35l56->init_completion);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/675 wifi: iwlwifi: mvm: validate SAR GEO response payload size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pagadala Yesu Anjaneyulu <[email protected]>
[ Upstream commit 408d7da38272ce48e2db79b8a9895999f94d7655 ]
The SAR GEO command response is cast to iwl_geo_tx_power_profiles_resp without verifying the payload length. A malformed or unexpected firmware response can lead to reading an invalid structure layout.
Add an explicit size check before accessing the response data and return -EIO when the payload size is wrong.
--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/fw.c +10 -0
@@ -955,12 +955,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)return ret; } +if (IWL_FW_CHECK (mvm, +iwl_rx_packet_payload_len (cmd.resp_pkt) != +sizeof (*resp), +"Wrong size for iwl_geo_tx_power_profiles_resp: %d\n" , +iwl_rx_packet_payload_len (cmd.resp_pkt))) { + ret = -EIO ; + goto out; + } + resp = (void *)cmd.resp_pkt->data; ret =le32_to_cpu (resp->profile_idx);if (WARN_ON (ret >BIOS_GEO_MAX_PROFILE_NUM )) ret = -EIO ; +out:iwl_free_resp (&cmd);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/675 wifi: iwlwifi: fix pointer arithmetic in iwl_add_mcc_to_tas_block_list
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit bc796f84ec9a95b356959ec7caf1d4fce33f3a76 ]
The expression list[*size++] increments the pointer 'size' rather than the u8 value it points to (operator precedence: ++ binds to the pointer before the dereference). As a result the block-list entry is written at the correct index but *size is never incremented, so the caller's count stays at zero and subsequent calls overwrite slot 0 every time.
Change to list[(*size)++] so that the value pointed to by size is incremented after use as the array index.
--- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +1 -1
@@ -483,7 +483,7 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)if (*size >=IWL_WTAS_BLACK_LIST_MAX )return false; - list[*size++] = mcc; + list[(*size)++] = mcc;return true; }IWL_EXPORT_SYMBOL (iwl_add_mcc_to_tas_block_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/675 wifi: iwlwifi: validate payload length in iwl_pnvm_complete_fn
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
[ Upstream commit daec24a5ed5da77a108e246ad77aa8b889911f93 ]
iwl_pnvm_complete_fn() casts pkt->data directly to struct iwl_pnvm_init_complete_ntfy and reads the status field without first verifying that the firmware notification payload is large enough to contain that structure.
Add a WARN_ON_ONCE check against sizeof(*pnvm_ntf) and return early without reading uninitialised memory if the payload is too short.
--- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +8 -1
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* -* Copyright(c) 2020-2025 Intel Corporation +* Copyright(c) 2020-2026 Intel Corporation */ #include "iwl-drv.h"
@@ -12,6 +12,7 @@#include "fw/api/alive.h" #include "fw/uefi.h" #include "fw/img.h" +#include "fw/dbg.h" #define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
@@ -26,6 +27,12 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,struct iwl_trans *trans = (struct iwl_trans *)data;struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; +if (IWL_FW_CHECK (trans, +iwl_rx_packet_payload_len (pkt) <sizeof (*pnvm_ntf), +"Bad notif len: %d\n" , +iwl_rx_packet_payload_len (pkt))) +return true; +IWL_DEBUG_FW (trans,"PNVM complete notification received with status 0x%0x\n" ,le32_to_cpu (pnvm_ntf->status));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 198/675 wifi: iwlwifi: mvm: fix read in wake packet notification handler
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shahar Tzarfati <[email protected]>
[ Upstream commit 9d7657aae8c1579584c67b0b66114a6a98db8b2f ]
In iwl_mvm_wowlan_store_wake_pkt(), packet_len was initialized from notif->wake_packet_length before the explicit check that len >= sizeof(*notif).
Move the assignment of packet_len to after the size check so that notif->wake_packet_length is only accessed once the payload length has been validated.
--- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/intel/iwlwifi/mvm/d3.c +2 -1
@@ -2783,7 +2783,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status, u32 len) { -u32 data_size, packet_len =le32_to_cpu (notif->wake_packet_length); +u32 data_size, packet_len;if (len <sizeof (*notif)) {IWL_ERR (mvm,"Invalid WoWLAN wake packet notification!\n" );
@@ -2802,6 +2802,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,return -EIO ; } + packet_len =le32_to_cpu (notif->wake_packet_length); data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif , wake_packet);/* data_size got the padding from the notification, remove it. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 199/675 usb: atm: ueagle-atm: reject descriptors that confuse probe and disconnect
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Diego Fernando Mancera Gomez <[email protected]>
[ Upstream commit 71132cedd1ecbc4032d76e9928c18a10f7e39b80 ]
uea_probe() distinguishes a pre-firmware device from a post-firmware one using the USB id (UEA_IS_PREFIRM()), and stores a different object as the interface data in each case: a 'struct completion' for a pre-firmware device (to be waited on in .disconnect()), or a 'struct usbatm_data' for a post-firmware one.
uea_disconnect() instead tells the two apart by the number of interfaces of the active configuration (a pre-firmware device exposes a single interface, ADI930 has 2 and eagle has 3), and casts the interface data accordingly.
Because the two handlers use different criteria, a crafted device that advertises a pre-firmware id together with a multi-interface descriptor (or a post-firmware id with a single interface) makes them disagree: the small 'struct completion' stored by uea_probe() is then passed to usbatm_usb_disconnect(), which casts it to 'struct usbatm_data' and takes instance->serialize, reading past the end of the allocation:
BUG: KASAN: slab-out-of-bounds in __mutex_lock+0x152a/0x1b80 Read of size 8 at addr ffff8880470e2c60 by task kworker/1:2/982 ... __mutex_lock+0x152a/0x1b80 usbatm_usb_disconnect+0x70/0x820 uea_disconnect+0x133/0x2c0 usb_unbind_interface+0x1dd/0x9e0 ... which belongs to the cache kmalloc-96 of size 96 The buggy address is located 0 bytes to the right of allocated 96-byte region [ffff8880470e2c00, ffff8880470e2c60)
Reject such inconsistent descriptors in uea_probe() so that both handlers always make the same pre/post-firmware decision.
--- drivers/usb/atm/ueagle-atm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/usb/atm/ueagle-atm.c +17 -0
@@ -2550,6 +2550,7 @@ static struct usbatm_driver uea_usbatm_driver = {static int uea_probe (struct usb_interface *intf,const struct usb_device_id *id) {struct usb_device *usb =interface_to_usbdev (intf); +bool single_iface = usb->config->desc.bNumInterfaces ==1 ;int ret; uea_dbg(usb, "ADSL device found with vid (%#X) pid (%#X) Rev (%#X): %s\n",
@@ -2558,6 +2559,22 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)le16_to_cpu (usb->descriptor.bcdDevice), chip_name[UEA_CHIP_VERSION(id)]); +/* +* uea_probe() decides between the pre-firmware and post-firmware case +* from the USB id and stores a different object as interface data in +* each case: a struct completion for a pre-firmware device, a struct +* usbatm_data for a post-firmware one. uea_disconnect() instead tells +* the two apart by the number of interfaces (a pre-firmware device +* exposes a single interface, ADI930 has 2 and eagle has 3). A crafted +* device advertising a pre-firmware id together with a multi-interface +* descriptor (or the other way around) makes the two disagree, so that +* usbatm_usb_disconnect() treats the small completion object as a +* struct usbatm_data and reads out of bounds. Reject such inconsistent +* descriptors so both paths make the same decision. +*/ +if (UEA_IS_PREFIRM (id) != single_iface) +return -ENODEV ; +usb_reset_device (usb);if (UEA_IS_PREFIRM (id)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 200/675 drivers/virt: pkvm: Fix end calculation in mmio_guard_ioremap_hook()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mostafa Saleh <[email protected]>
[ Upstream commit 62c740f823a8e47ffe56e45a7472c27cf988e2f6 ]
Sashiko (locally) reports a logical issues in mmio_guard_ioremap_hook()
mmio_guard_ioremap_hook() attempts to handle unaligned addresses and sizes. However, aligning the start address before adding the size, might shift the end to the page before.
--- drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +1 -1
@@ -82,8 +82,8 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)return 0 ; + end =PAGE_ALIGN (phys + size); phys =PAGE_ALIGN_DOWN (phys); - end = phys +PAGE_ALIGN (size);while (phys < end) {const int func_id =ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 201/675 hwmon: (asus-ec-sensors) fix looping over banks while reading from EC
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugene Shalygin <[email protected]>
[ Upstream commit e741d13cc2abfc6fccebe2008057aa52e285223e ]
Do not assume there are only bank 0 and bank 1 available, just use '!=' for bank comparison.
--- drivers/hwmon/asus-ec-sensors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/asus-ec-sensors.c +1 -1
@@ -1050,7 +1050,7 @@ static int asus_ec_block_read(const struct device *dev, }for (ireg =0 ; ireg < ec->nr_registers; ireg++) { reg_bank =register_bank (ec->registers[ireg]); -if (reg_bank < bank) { +if (reg_bank != bank) {continue ; } ec_read(register_index(ec->registers[ireg]),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 202/675 hwmon: (asus-ec-sensors) fix EC read intervals
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugene Shalygin <[email protected]>
[ Upstream commit 60710b2af13b81da71b429d3f8b19dd70310729d ]
Take INITIAL_JIFFIES into account when setting up next update time.
--- drivers/hwmon/asus-ec-sensors.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/hwmon/asus-ec-sensors.c +4 -4
@@ -870,7 +870,7 @@ struct ec_sensors_data {/* sorted list of unique register banks */ u8 banks[ASUS_EC_MAX_BANK +1 ];/* in jiffies */ -unsigned long last_updated; +u64 next_update;struct lock_data lock_data;/* number of board EC sensors */ u8 nr_sensors;
@@ -1139,13 +1139,12 @@ static int get_cached_value_or_update(const struct device *dev,int sensor_index, struct ec_sensors_data *state, s32 *value) { - if (time_after(jiffies, state->last_updated + HZ)) { + if (time_after64(get_jiffies_64(), state->next_update)) { if (update_ec_sensors(dev, state)) { dev_err(dev, "update_ec_sensors() failure\n");return -EIO ; } - - state->last_updated = jiffies; + state->next_update =get_jiffies_64 () +HZ ; } *value = state->sensors[sensor_index].cached_value;
@@ -1263,6 +1262,7 @@ static int asus_ec_probe(struct platform_device *pdev)if (!ec_data)return -ENOMEM ; + ec_data->next_update =INITIAL_JIFFIES ;dev_set_drvdata (dev, ec_data); ec_data->board_info = pboard_info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 203/675 hwmon: (asus-ec-sensors) add missed handle for ENOMEM
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eugene Shalygin <[email protected]>
[ Upstream commit 9813c1f49efeadbcb17e4a41972350ac783f9cac ]
Add missing return value check in the setup function.
--- drivers/hwmon/asus-ec-sensors.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/hwmon/asus-ec-sensors.c +5 -3
@@ -1353,9 +1353,11 @@ static int asus_ec_probe(struct platform_device *pdev)if (!nr_count[type])continue ; -asus_ec_hwmon_add_chan_info (asus_ec_hwmon_chan, dev, - nr_count[type], type, - hwmon_attributes[type]); + status =asus_ec_hwmon_add_chan_info (asus_ec_hwmon_chan, dev, + nr_count[type], type, + hwmon_attributes[type]); +if (status) +return status; *ptr_asus_ec_ci++ = asus_ec_hwmon_chan++; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 204/675 smb: client: validate DFS referral PathConsumed
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit f6f5ee2aa33b350c671721b965251c42cebb962e ]
parse_dfs_referrals() validates that the response contains the fixed referral entry array and, on for-next, the per-referral string offsets. However, the response also contains a PathConsumed value that is later used for DFS path parsing.
If a malformed response provides a PathConsumed value larger than the search name, later DFS parsing can advance beyond the end of the path.
Validate PathConsumed against the search name length before storing it in the parsed referral.
--- fs/smb/client/misc.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
fs/smb/client/misc.c +25 -9
@@ -957,6 +957,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,int i, rc =0 ;char *data_end;struct dfs_referral_level_3 *ref; +unsigned int path_consumed; +size_t search_name_len;if (rsp_size <sizeof (*rsp)) { cifs_dbg(VFS | ONCE,
@@ -1004,6 +1006,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, rc = -ENOMEM ; goto parse_DFS_referrals_exit; } + search_name_len =strlen (searchName);/* collect necessary data from referrals */ for (i =0 ; i < *num_of_nodes; i++) {
@@ -1012,21 +1015,34 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,struct dfs_info3_param *node = (*target_nodes)+i; node->flags =le32_to_cpu (rsp->DFSFlags); + path_consumed =le16_to_cpu (rsp->PathConsumed);if (is_unicode) { -__le16 *tmp =kmalloc (strlen (searchName)*2 +2 , -GFP_KERNEL ); -if (tmp ==NULL ) { +size_t search_name_utf16_len = search_name_len *2 +2 ; +__le16 *tmp; + +if (path_consumed > search_name_utf16_len) { + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } + + tmp =kmalloc (search_name_utf16_len,GFP_KERNEL ); +if (!tmp) { rc = -ENOMEM ; goto parse_DFS_referrals_exit; } -cifsConvertToUTF16 ((__le16 *) tmp, searchName, +cifsConvertToUTF16 ((__le16 *)tmp, searchName,PATH_MAX , nls_codepage, remap); - node->path_consumed =cifs_utf16_bytes (tmp, -le16_to_cpu (rsp->PathConsumed), - nls_codepage); + node->path_consumed =cifs_utf16_bytes (tmp, path_consumed, + nls_codepage);kfree (tmp); - }else - node->path_consumed =le16_to_cpu (rsp->PathConsumed); + }else { +if (path_consumed > search_name_len) { + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } + + node->path_consumed = path_consumed; + } node->server_type =le16_to_cpu (ref->ServerType); node->ref_flag =le16_to_cpu (ref->ReferralEntryFlags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 205/675 ovpn: avoid putting unrelated P2P peer on socket release
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <[email protected]>
[ Upstream commit b52c5103f64ee825996ca1ab8df7283cde8c5f86 ]
ovpn_peer_release_p2p() is called when an OVPN UDP socket is being destroyed. It checks the currently published P2P peer and releases it only if that peer still uses the socket being destroyed.
A peer replacement can publish a new peer before the old UDP socket is destroyed. When the old socket destruction path runs afterwards, ovpn_peer_release_p2p() observes the new peer through ovpn->peer. Since the new peer uses a different socket, the function takes the socket mismatch branch.
That branch still calls ovpn_peer_put(peer). At this point, however, peer is the currently published replacement peer, not the peer associated with the socket being destroyed. Dropping its reference can free it while ovpn->peer still points to it, leading to later use-after-free accesses from the peer and socket cleanup paths.
KASAN reports this as a slab-use-after-free on the kmalloc-1k ovpn_peer object. In the reproducer, the object is allocated from ovpn_peer_new() via ovpn_nl_peer_new_doit(), and freed through ovpn_peer_release_rcu() from RCU callback processing. Observed access sites include ovpn_peer_remove(), ovpn_socket_release(), ovpn_nl_peer_del_notify(), and unlock_ovpn().
Fix this by returning from the socket mismatch branch without putting the peer.
--- drivers/net/ovpn/peer.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/ovpn/peer.c +0 -1
@@ -1162,7 +1162,6 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, ovpn_sock =rcu_access_pointer (peer->sock);if (!ovpn_sock || ovpn_sock->sk != sk) {spin_unlock_bh (&ovpn->lock); -ovpn_peer_put (peer);return ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 206/675 selftests/net: ovpn: fix getaddrinfo memory leak in ovpn_parse_remote()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: longlong yan <[email protected]>
[ Upstream commit 0bd9cfebc1c91e1066e56d6261b99691b9df6008 ]
The ovpn_parse_remote() function has two memory management issues:
1. When both 'host' and 'vpnip' are non-NULL, the first getaddrinfo() allocation is leaked because 'result' is overwritten by the second getaddrinfo() call without freeing the first allocation.
2. When both 'host' and 'vpnip' are NULL, 'result' is an uninitialized stack variable passed to freeaddrinfo(), which is undefined behavior.
Fix by initializing 'result' to NULL and calling freeaddrinfo() after the first getaddrinfo() result is consumed.
--- tools/testing/selftests/net/ovpn/ovpn-cli.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/testing/selftests/net/ovpn/ovpn-cli.c +3 -1
@@ -1746,7 +1746,7 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, const char *service, const char *vpnip) { int ret; -struct addrinfo *result; +struct addrinfo *result =NULL ; struct addrinfo hints = { .ai_family = ovpn->sa_family, .ai_socktype = SOCK_DGRAM,
@@ -1770,6 +1770,8 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, }memcpy (&ovpn->remote, result->ai_addr, result->ai_addrlen); +freeaddrinfo (result); + result =NULL ; }if (vpnip) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 207/675 ovpn: fix use after free in unlock_ovpn()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Baffo <[email protected]>
[ Upstream commit e1ad6fe5db719874efa45b2caf9934552e09fc43 ]
unlock_ovpn() iterates over the release_list using llist_for_each_entry() and drops the peer reference inside the loop body via ovpn_peer_put().
If this drops the last reference, the peer is eventually freed. However, llist_for_each_entry() reads peer->release_entry.next in the loop advance expression, which runs after the body. By that time the peer may have already been freed, resulting in a use after free when advancing to the next list entry.
Fix this by using llist_for_each_entry_safe(), which caches the next pointer before executing the loop body.
--- drivers/net/ovpn/peer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ovpn/peer.c +3 -2
@@ -26,11 +26,12 @@ static void unlock_ovpn(struct ovpn_priv *ovpn, struct llist_head *release_list) __releases(&ovpn->lock) { -struct ovpn_peer *peer; +struct ovpn_peer *peer, *next;spin_unlock_bh (&ovpn->lock); -llist_for_each_entry (peer, release_list->first, release_entry) { +llist_for_each_entry_safe (peer, next, release_list->first, + release_entry) {ovpn_socket_release (peer);ovpn_peer_put (peer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 208/675 ovpn: use monotonic clock for peer keepalive timeouts
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Baffo <[email protected]>
[ Upstream commit f7e6287ccd3abeed9e638b581dc3fdf742106ba3 ]
Replace ktime_get_real_seconds() with the monotonic ktime_get_boottime_seconds() to ensure the keepalive mechanism is robust against system clock modifications.
Right now, the driver uses ktime_get_real_seconds() to track peer timeouts, relying on the system wall-clock.
An administrative time adjustment or an NTP sync that steps the clock forward can cause now' to instantly exceed last_recv + timeout'.
When this occurs, the driver artificially expires healthy peers. Depending on the OpenVPN user-space configuration, this triggers a premature tunnel restart (if --keepalive or --ping-restart is used) or a complete disconnection of the client (if --ping-exit is used).
--- drivers/net/ovpn/io.c | 4 ++-- drivers/net/ovpn/peer.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/net/ovpn/io.c +2 -2
@@ -137,7 +137,7 @@ void ovpn_decrypt_post(void *data, int ret) }/* keep track of last received authenticated packet for keepalive */ -WRITE_ONCE (peer->last_recv,ktime_get_real_seconds ()); +WRITE_ONCE (peer->last_recv,ktime_get_boottime_seconds ());rcu_read_lock (); sock =rcu_dereference (peer->sock);
@@ -291,7 +291,7 @@ void ovpn_encrypt_post(void *data, int ret)ovpn_peer_stats_increment_tx (&peer->link_stats, orig_len);/* keep track of last sent packet for keepalive */ -WRITE_ONCE (peer->last_sent,ktime_get_real_seconds ()); +WRITE_ONCE (peer->last_sent,ktime_get_boottime_seconds ());/* skb passed down the stack - don't free it */ skb =NULL ; err_unlock:
drivers/net/ovpn/peer.c +2 -2
@@ -45,7 +45,7 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,*/ void ovpn_peer_keepalive_set (struct ovpn_peer *peer,u32 interval,u32 timeout) { -time64_t now =ktime_get_real_seconds (); +time64_t now =ktime_get_boottime_seconds (); netdev_dbg(peer->ovpn->dev, "scheduling keepalive for peer %u: interval=%u timeout=%u\n",
@@ -1352,7 +1352,7 @@ void ovpn_peer_keepalive_work(struct work_struct *work) { struct ovpn_priv *ovpn = container_of(work, struct ovpn_priv, keepalive_work.work); -time64_t next_run =0 , now =ktime_get_real_seconds (); +time64_t next_run =0 , now =ktime_get_boottime_seconds ();LLIST_HEAD (release_list);spin_lock_bh (&ovpn->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 209/675 hwmon: occ: validate poll response sensor blocks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 70e76e700fc6c46afb4e17aec099a1ea089b4a22 ]
The OCC poll response parser walks a counted list of sensor data blocks. It used the static backing-array capacity as the parse boundary, but a transport response makes only data_length bytes current and valid. A truncated response can therefore make the parser consume a block header or block extent outside the current response.
Use data_length as the parent boundary, prove the fixed poll header and each current block header before reading them, and prove the complete block before advancing. Keep parsed sensor metadata local until the complete response has passed validation, then publish it. Propagate malformed-response errors before publishing the OCC as active.
--- drivers/hwmon/occ/common.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-)
drivers/hwmon/occ/common.c +30 -8
@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ) }/* only need to do this once at startup, as OCC won't change sensors on us */ -static void occ_parse_poll_response (struct occ *occ) +static int occ_parse_poll_response (struct occ *occ) {unsigned int i, old_offset, offset =0 , size =0 ; +u16 data_length;struct occ_sensor *sensor; -struct occ_sensors *sensors = &occ->sensors; +struct occ_sensors parsed = {}; +struct occ_sensors *sensors = &parsed;struct occ_response *resp = &occ->resp;struct occ_poll_response *poll = (struct occ_poll_response *)&resp->data[0 ];struct occ_poll_response_header *header = &poll->header;struct occ_sensor_data_block *block = &poll->block; + data_length =get_unaligned_be16 (&resp->data_length); +if (data_length <sizeof (*header) || data_length >OCC_RESP_DATA_BYTES ) { +dev_err (occ->bus_dev,"invalid OCC poll response length %u\n" , + data_length); +return -EMSGSIZE ; + } +dev_info (occ->bus_dev,"OCC found, code level: %.16s\n" , header->occ_code_level);for (i =0 ; i < header->num_sensor_data_blocks; ++i) { block = (struct occ_sensor_data_block *)((u8 *)block + offset); +if (size +sizeof (*header) +sizeof (block->header) > + data_length) { +dev_err (occ->bus_dev, +"truncated OCC sensor block header\n" ); +return -EMSGSIZE ; + } + old_offset = offset; offset = (block->header.num_sensors * block->header.sensor_length) +sizeof (block->header); - size += offset;/* validate all the length/size fields */ -if ((size +sizeof (*header)) >=OCC_RESP_DATA_BYTES ) { -dev_warn (occ->bus_dev,"exceeded response buffer\n" ); -return ; +if (size +sizeof (*header) + offset > data_length) { +dev_err (occ->bus_dev, +"exceeded OCC poll response length\n" ); +return -EMSGSIZE ; } + size += offset; dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n", old_offset, offset - 1, block->header.eye_catcher,
@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ)dev_dbg (occ->bus_dev,"Max resp size: %u+%zd=%zd\n" , size,sizeof (*header), size +sizeof (*header)); + occ->sensors = parsed; + +return 0 ; }int occ_active (struct occ *occ,bool active)
@@ -1138,10 +1158,12 @@ int occ_active(struct occ *occ, bool active) goto unlock; } - occ->active = true; occ->next_update = jiffies +OCC_UPDATE_FREQUENCY ; -occ_parse_poll_response (occ); + rc =occ_parse_poll_response (occ); +if (rc) + goto unlock; + occ->active = true; rc =occ_setup_sensor_attrs (occ);if (rc) { dev_err(occ->bus_dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 210/675 regulator: mt6358: use regmap helper to read fixed LDO calibration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Golle <[email protected]>
[ Upstream commit 1d26f125501f3fbe6c259ab75bf6516299a0bf0e ]
The "fixed" LDOs with output voltage calibration use mt6358_get_buck_voltage_sel as their get_voltage_sel op, but the MT6358_REG_FIXED and MT6366_REG_FIXED entries do not populate da_vsel_reg/da_vsel_mask. The op therefore reads register 0x0 with a zero mask and shifts the result by ffs(0) - 1 = -1, which is undefined behaviour and gets flagged by UBSAN on every boot on MT6366 boards:
UBSAN: shift-out-of-bounds in drivers/regulator/mt6358-regulator.c:384:38 shift exponent -1 is negative Call trace: mt6358_get_buck_voltage_sel+0xc8/0x120 regulator_get_voltage_rdev+0x70/0x170 set_machine_constraints+0x504/0xc38 regulator_register+0x324/0xc68
Besides the undefined shift, the returned selector is always 0, so the actual calibration offset programmed in <reg>_ANA_CON0 is never reported.
The descriptor already carries the correct vsel_reg/vsel_mask (the ANA_CON0 calibration field), matching the regulator_set_voltage_sel_regmap op already in use. Read the selector back through regulator_get_voltage_sel_regmap instead.
--- drivers/regulator/mt6358-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/regulator/mt6358-regulator.c +1 -1
@@ -492,7 +492,7 @@ static const struct regulator_ops mt6358_volt_fixed_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = mt6358_get_buck_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 211/675 Bluetooth: btusb: validate Realtek vendor event length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit df541cd485ff80a5ddc579d99687bc7506df9851 ]
btusb_recv_event_realtek() reads the event code at data[0] and the Realtek subevent code at data[2] before deciding whether to consume a vendor event as a coredump.
For example, the two-byte event ff 00 contains a complete vendor-event header declaring zero parameters. The old classifier still reads a nonexistent third byte and can misclassify the event as a coredump if the adjacent byte is 0x34.
Require the HCI event header and first parameter to be present before inspecting the Realtek subevent code. Short events continue through the normal HCI receive path, which owns their protocol validation.
--- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +3 -1
@@ -2716,7 +2716,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)static int btusb_recv_event_realtek (struct hci_dev *hdev,struct sk_buff *skb) { -if (skb->data[0 ] ==HCI_VENDOR_PKT && skb->data[2 ] ==RTK_SUB_EVENT_CODE_COREDUMP ) { +if (skb->len >=HCI_EVENT_HDR_SIZE +1 && + skb->data[0 ] ==HCI_VENDOR_PKT && + skb->data[2 ] ==RTK_SUB_EVENT_CODE_COREDUMP ) {struct rtk_dev_coredump_hdr hdr = { .code =RTK_DEVCOREDUMP_CODE_MEMDUMP , };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 212/675 net: phy: marvell: fix return code
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 7d8ca62d6a9ef593780161586b4efc811ac094fe ]
Return the correct error code, not the value written to the register.
--- drivers/net/phy/marvell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/phy/marvell.c +1 -1
@@ -753,7 +753,7 @@ static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes) err =phy_modify (phydev,MII_M1111_PHY_EXT_SR ,MII_M1111_HWCFG_SERIAL_AN_BYPASS , extsr);if (err <0 ) -return extsr; +return err;return phy_modify_paged (phydev,MII_MARVELL_FIBER_PAGE ,MII_BMCR ,BMCR_ANENABLE , bmcr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 213/675 netlink: specs: rt-link: convert bridge port flag attributes to u8
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danielle Ratson <[email protected]>
[ Upstream commit f6e3b21608e974c4aaa4cfd73a239dacf1d8a9a3 ]
A number of IFLA_BRPORT_* attributes are documented in the rt-link spec as having the "flag" type, i.e. a payload-less NLA_FLAG attribute whose meaning is presence-only. This does not match the kernel, which emits these attributes with nla_put_u8() and validates them as NLA_U8 in br_port_policy[]. The values are not mere presence flags but carry a u8 payload (0/1).
Convert these bridge port attributes from "flag" to "u8" so the spec reflects the actual wire format.
--- Documentation/netlink/specs/rt-link.yaml | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-)
Documentation/netlink/specs/rt-link.yaml +20 -20
@@ -1564,31 +1564,31 @@ attribute-sets: type: u32 - name: mode - type: flag + type: u8 - name: guard - type: flag + type: u8 - name: protect - type: flag + type: u8 - name: fast-leave - type: flag + type: u8 - name: learning - type: flag + type: u8 - name: unicast-flood - type: flag + type: u8 - name: proxyarp - type: flag + type: u8 - name: learning-sync - type: flag + type: u8 - name: proxyarp-wifi - type: flag + type: u8 - name: root-id type: binary
@@ -1635,34 +1635,34 @@ attribute-sets: type: pad - name: mcast-flood - type: flag + type: u8 - name: mcast-to-ucast - type: flag + type: u8 - name: vlan-tunnel - type: flag + type: u8 - name: bcast-flood - type: flag + type: u8 - name: group-fwd-mask type: u16 - name: neigh-suppress - type: flag + type: u8 - name: isolated - type: flag + type: u8 - name: backup-port type: u32 - name: mrp-ring-open - type: flag + type: u8 - name: mrp-in-open - type: flag + type: u8 - name: mcast-eht-hosts-limit type: u32
@@ -1671,10 +1671,10 @@ attribute-sets: type: u32 - name: locked - type: flag + type: u8 - name: mab - type: flag + type: u8 - name: mcast-n-groups type: u32
@@ -1683,7 +1683,7 @@ attribute-sets: type: u32 - name: neigh-vlan-suppress - type: flag + type: u8 - name: backup-nhid type: u32
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 214/675 net/packet: avoid fanout hook re-registration after unregister
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
[ Upstream commit 50aff80475abd3533eef4320477037e6fcc6b56e ]
packet_set_ring() temporarily detaches a socket from packet delivery while reconfiguring its ring. It records the previous running state, clears po->num, unregisters the protocol hook when needed, drops po->bind_lock, and later restores po->num and re-registers the hook from the saved was_running value.
That unlocked window can race with NETDEV_UNREGISTER. The notifier can observe the socket as not running, skip __unregister_prot_hook(), and invalidate the per-socket binding by setting po->ifindex to -1 and clearing po->prot_hook.dev. A one-member fanout group can still retain its shared fanout hook device pointer. When packet_set_ring() resumes, re-registering solely from the stale was_running state can re-add the fanout hook after the device has been unregistered.
Treat po->ifindex == -1 as an invalidated binding after reacquiring po->bind_lock. This is distinct from ifindex 0, the normal unbound/wildcard state: ifindex -1 marks an existing device binding that was invalidated when the device was unregistered. Restore po->num as before, but do not re-register the hook if device unregister already detached the socket.
--- net/packet/af_packet.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/packet/af_packet.c +5 -1
@@ -4561,7 +4561,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,spin_lock (&po->bind_lock);WRITE_ONCE (po->num, num); -if (was_running) +/* +* NETDEV_UNREGISTER may have invalidated the binding while bind_lock +* was dropped above. Do not re-add a fanout hook to a dead device. +*/ +if (was_running &&READ_ONCE (po->ifindex) !=-1 )register_prot_hook (sk);spin_unlock (&po->bind_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 215/675 bonding: fix devconf_all NULL dereference when IPv6 is disabled
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaolong Zhang <[email protected]>
[ Upstream commit 1c975de3343cdef506f2eecc833cc1f14b0401c4 ]
When booting with the 'ipv6.disable=1' parameter, the devconf_all is never initialized because inet6_init() exits before addrconf_init() is called which initializes it. bond_send_validate(), however, will still call bond_ns_send_all() even ipv6 is indeed disabled. It will lead to NULL derefence of net->ipv6.devconf_all in ip6_pol_route().
BUG: kernel NULL pointer dereference, address: 000000000000000c [...] Workqueue: bond0 bond_arp_monitor [bonding] RIP: 0010:ip6_pol_route+0x69/0x480 [...] Call Trace: <TASK> ? srso_return_thunk+0x5/0x5f ? __pfx_ip6_pol_route_output+0x10/0x10 fib6_rule_lookup+0xfe/0x260 ? wakeup_preempt+0x8a/0x90 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f ? sched_balance_rq+0x369/0x810 ip6_route_output_flags+0xd7/0x170 bond_ns_send_all+0xde/0x280 [bonding] bond_ab_arp_probe+0x296/0x320 [bonding] ? srso_return_thunk+0x5/0x5f bond_activebackup_arp_mon+0xb4/0x2c0 [bonding] process_one_work+0x196/0x370 worker_thread+0x1af/0x320 ? srso_return_thunk+0x5/0x5f ? __pfx_worker_thread+0x10/0x10 kthread+0xe3/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x199/0x260 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
Fix this by adding ipv6_mod_enabled() condition check in the caller.
--- drivers/net/bonding/bond_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/bonding/bond_main.c +2 -1
@@ -3422,7 +3422,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave) {bond_arp_send_all (bond, slave);#if IS_ENABLED (CONFIG_IPV6 ) -bond_ns_send_all (bond, slave); +if (likely (ipv6_mod_enabled ())) +bond_ns_send_all (bond, slave);#endif }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 216/675 rds: drop incoming messages that cross network namespace boundaries
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Ariel Panzardo <[email protected]>
[ Upstream commit 5521ae71e32a8069ed4ca6e792179dc57bc43ab2 ]
rds_find_bound() looks up the destination socket using a global rhashtable keyed solely on (addr, port, scope_id). Network namespaces are not part of the key, so a sender in netns A can deliver an incoming message (inc) to a socket that lives in a different netns B.
When this happens, inc->i_conn points to an rds_connection whose c_net is netns A, but the receiving rs lives in netns B. Once the child process that created netns A exits, cleanup_net() calls rds_loop_exit_net() -> rds_loop_kill_conns() -> rds_conn_destroy(), freeing that connection. If the survivor socket in netns B still holds the inc, any subsequent dereference of inc->i_conn is a use-after-free.
There are two dangerous sites in rds_clear_recv_queue():
1. inc->i_conn->c_lcong (offset 88 of freed rds_connection, size 200) read via rds_recv_rcvbuf_delta() -- confirmed by KASAN.
2. inc->i_conn->c_trans->inc_free(inc) (function pointer at offset 80) called via rds_inc_put() when the inc refcount reaches zero -- same race window, potential call-through-freed-object primitive.
The bug is reachable from unprivileged user namespaces (CLONE_NEWUSER + CLONE_NEWNET), available since Linux 3.8.
Fix this by rejecting the delivery in rds_recv_incoming() when the socket returned by rds_find_bound() belongs to a different network namespace than the connection that carried the message. Use the existing rds_conn_net() / sock_net() helpers and net_eq() for the comparison.
--- net/rds/recv.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
net/rds/recv.c +15 -0
@@ -366,6 +366,21 @@ void rds_recv_incoming(struct rds_connection *conn, struct in6_addr *saddr, goto out; } +/* +* rds_find_bound() uses a global (netns-agnostic) hash table. +* An RDS connection created in netns A can match a socket bound +* in the init netns, delivering inc cross-netns with inc->i_conn +* pointing into netns A. When cleanup_net() then frees that conn, +* any subsequent dereference of inc->i_conn is a use-after-free. +* Drop the inc if the receiving socket lives in a different netns. +*/ +if (!net_eq (sock_net (rds_rs_to_sk (rs)),rds_conn_net (conn))) { +rds_stats_inc (s_recv_drop_no_sock); +rds_sock_put (rs); + rs =NULL ; + goto out; + } +/* Process extension headers */ rds_recv_incoming_exthdrs (inc, rs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 217/675 gtp: parse extension headers before reading inner protocol
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhixing Chen <[email protected]>
[ Upstream commit 96e37e2f618e931aa97af95e707dcdfb1ec41264 ]
GTPv1-U packets may carry a chain of extension headers before the inner IP packet. The receive path already parses and skips these extension headers, but it currently reads the inner protocol before doing so.
As a result, the first extension header byte is interpreted as the inner IP version. Packets with extension headers are then dropped before PDP lookup.
Parse the extension header chain before calling gtp_inner_proto(), so the inner protocol is read from the actual inner IP header.
--- drivers/net/gtp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/gtp.c +6 -6
@@ -826,13 +826,17 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)if (!pskb_may_pull (skb, hdrlen))return -1 ; + gtp1 = (struct gtp1_header *)(skb->data +sizeof (struct udphdr )); + +if (gtp1->flags >P1_F_EXTHDR && +gtp_parse_exthdrs (skb, &hdrlen) <0 ) +return -1 ; +if (gtp_inner_proto (skb, hdrlen, &inner_proto) <0 ) {netdev_dbg (gtp->dev,"GTP packet does not encapsulate an IP packet\n" );return -1 ; } - gtp1 = (struct gtp1_header *)(skb->data +sizeof (struct udphdr )); - pctx =gtp1_pdp_find (gtp,ntohl (gtp1->tid),gtp_proto_to_family (inner_proto));if (!pctx) {
@@ -840,10 +844,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)return 1 ; } -if (gtp1->flags >P1_F_EXTHDR && -gtp_parse_exthdrs (skb, &hdrlen) <0 ) -return -1 ; -return gtp_rx (pctx, skb, hdrlen, gtp->role, inner_proto); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 218/675 rxrpc: fix io_thread race in rxrpc_wake_up_io_thread()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
[ Upstream commit 745fb794c3e933c023af9dbb5876a5e16ad2dc71 ]
rxrpc_wake_up_io_thread() checks local->io_thread before waking it, but then reloads the pointer for wake_up_process().
local->io_thread is cleared with WRITE_ONCE() when the I/O thread exits, so the second load can see NULL even if the first load did not.
Take a READ_ONCE() snapshot and use it for both the NULL check and the wake_up_process() call, as rxrpc_encap_rcv() already does.
--- net/rxrpc/ar-internal.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/rxrpc/ar-internal.h +4 -2
@@ -1266,9 +1266,11 @@ int rxrpc_io_thread(void *data);void rxrpc_post_response (struct rxrpc_connection *conn,struct sk_buff *skb);static inline void rxrpc_wake_up_io_thread (struct rxrpc_local *local) { -if (!local->io_thread) +struct task_struct *io_thread =READ_ONCE (local->io_thread); + +if (!io_thread)return ; -wake_up_process (READ_ONCE (local->io_thread)); +wake_up_process (io_thread); }static inline bool rxrpc_protocol_error (struct sk_buff *skb,enum rxrpc_abort_reason why)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 219/675 dpaa2-switch: put MAC endpoint device on disconnect
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 4c1eabbef7a1707635652e956e39db1269c3af2b ]
fsl_mc_get_endpoint() returns the MAC endpoint device with a reference taken through device_find_child(). The switch port connect path stores that device in mac->mc_dev and keeps it for the lifetime of the connected MAC object.
However, the disconnect path only closes the MAC and frees the dpaa2_mac object. It does not drop the endpoint device reference stored in mac->mc_dev, so every successful connect leaks that device reference when the MAC is later disconnected.
Drop the endpoint device reference before freeing the dpaa2_mac object.
--- drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +1 -0
@@ -1511,6 +1511,7 @@ static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)dpaa2_mac_disconnect (mac);dpaa2_mac_close (mac); +put_device (&mac->mc_dev->dev);kfree (mac); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 220/675 net: airoha: Fix potential use-after-free in airoha_ppe_deinit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wayen Yan <[email protected]>
[ Upstream commit 2484568a335cd7bda951c75b3a7d95ea36161ae7 ]
airoha_ppe_deinit() replaces the NPU pointer with NULL via rcu_replace_pointer() but does not wait for existing RCU readers to exit before calling ppe_deinit() and airoha_npu_put(). This can cause a use-after-free if a reader in an RCU read-side critical section still holds a reference to the NPU when it is freed.
The init path (airoha_ppe_init) already calls synchronize_rcu() after rcu_assign_pointer(), but the deinit path introduced in commit 6abcf751bc08 ("net: airoha: Fix schedule while atomic in airoha_ppe_deinit()") omitted the matching barrier when switching from rcu_read_lock()/rcu_dereference() to rcu_replace_pointer().
Add synchronize_rcu() before ppe_deinit() to ensure all existing RCU readers have completed before the NPU resources are released.
--- drivers/net/ethernet/airoha/airoha_ppe.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/airoha/airoha_ppe.c +1 -0
@@ -1575,6 +1575,7 @@ void airoha_ppe_deinit(struct airoha_eth *eth) npu =rcu_replace_pointer (eth->npu,NULL ,lockdep_is_held (&flow_offload_mutex));if (npu) { +synchronize_rcu (); npu->ops.ppe_deinit (npu);airoha_npu_put (npu); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 221/675 dpaa2-eth: put MAC endpoint device on disconnect
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit b4b201cc93ff70150853aba03e14d314d1980ca0 ]
fsl_mc_get_endpoint() returns the MAC endpoint device with a reference taken through device_find_child(). The Ethernet connect path stores that device in mac->mc_dev and keeps it for the lifetime of the connected MAC object.
However, the disconnect path only disconnects and closes the MAC before freeing the dpaa2_mac object. It does not drop the endpoint device reference stored in mac->mc_dev, so every successful connect leaks that device reference when the MAC is later disconnected.
Drop the endpoint device reference after closing the MAC and before freeing the dpaa2_mac object.
--- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +1 -0
@@ -4732,6 +4732,7 @@ static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)dpaa2_mac_disconnect (mac);dpaa2_mac_close (mac); +put_device (&mac->mc_dev->dev);kfree (mac); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 222/675 net: airoha: Fix DMA direction for NPU mailbox buffer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wayen Yan <[email protected]>
[ Upstream commit 6f884eb87a79e0c482baef2ad96c96b81d024235 ]
airoha_npu_send_msg() always maps the mailbox buffer with DMA_TO_DEVICE, but some callers expect the NPU to write response data back into the same buffer:
- airoha_npu_wlan_msg_get() (NPU_OP_GET): NPU writes response into the buffer, then the caller reads it via memcpy()
- airoha_npu_ppe_stats_setup() (NPU_OP_SET): NPU writes back npu_stats_addr field in the response
On non-cache-coherent architectures like EN7581 (Cortex-A53 without hardware cache coherency for NPU DMA), DMA_TO_DEVICE unmap is a no-op — it does not invalidate the CPU cache. If the NPU-written cache line is still present in the CPU cache when the caller reads the buffer, the CPU observes stale data instead of the NPU response.
This is a timing-sensitive bug: small mailbox buffers (~24 bytes) typically fit in a single cache line and may survive in the cache until the caller reads them, producing silent data corruption rather than a crash. The bug is more likely to trigger when the caller reads the response immediately after dma_unmap_single() without intervening cache-evicting operations.
Fix by using DMA_BIDIRECTIONAL for both map and unmap, which ensures dma_unmap_single() invalidates the CPU cache on non-coherent systems. The mailbox buffers are small so there is no performance concern.
--- drivers/net/ethernet/airoha/airoha_npu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/airoha/airoha_npu.c +2 -2
@@ -154,7 +154,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,dma_addr_t dma_addr;int ret; - dma_addr =dma_map_single (npu->dev, p, size,DMA_TO_DEVICE ); + dma_addr =dma_map_single (npu->dev, p, size,DMA_BIDIRECTIONAL ); ret =dma_mapping_error (npu->dev, dma_addr);if (ret)return ret;
@@ -177,7 +177,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,spin_unlock_bh (&npu->cores[core].lock); -dma_unmap_single (npu->dev, dma_addr, size,DMA_TO_DEVICE ); +dma_unmap_single (npu->dev, dma_addr, size,DMA_BIDIRECTIONAL );return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 223/675 iommu/amd: Wait for completion instead of returning early in iommu_completion_wait()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Feng <[email protected]>
[ Upstream commit 1e75a8255f11c81fb07e81e5029cfd75804350a0 ]
need_sync is a per-IOMMU flag shared by all domains and devices behind that IOMMU. It is set whenever a command is queued with sync == true and cleared when a completion-wait (CWAIT) command is queued. However, a cleared need_sync only means that a covering CWAIT has been queued, not that all previously queued commands have actually completed in hardware.
iommu_completion_wait() read need_sync locklessly and returned early when it was false. This breaks the "block until all previously queued commands have completed" contract in a multi-CPU scenario:
CPU2: queue inv-B => need_sync = true
CPU1: queue CWAIT(N); need_sync = false; then wait_on_sem(N)
CPU2: read need_sync == false => return 0 (no wait!)
CPU2 returns without waiting for any sequence number even though its inv-B may not have completed yet (CWAIT(N), queued after inv-B, has not been signaled). CPU2 then proceeds to, for example, free page-table pages while the IOMMU can still walk stale translations, opening a use-after-free window. This is a logical race in the meaning of the flag, not a memory-visibility issue, so barriers alone do not help.
Fix it without losing the optimization of avoiding redundant CWAIT
commands: take iommu->lock before testing need_sync, and when it is false do not return early but wait for the last allocated sequence number (cmd_sem_val). Since need_sync == false implies no sync command was queued after the last CWAIT, that CWAIT is FIFO-ordered after every not-yet-completed command, so waiting for its sequence number guarantees all prior commands (possibly queued by another CPU) have completed. The common path with pending work is unchanged and no extra hardware command is issued.
--- drivers/iommu/amd/iommu.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/iommu/amd/iommu.c +16 -6
@@ -1408,11 +1408,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu)int ret;u64 data; -if (!iommu->need_sync) -return 0 ; -raw_spin_lock_irqsave (&iommu->lock, flags); +if (!iommu->need_sync) { +/* +* No command has been queued since the last completion-wait. +* A concurrent CPU may have already queued that CWAIT and +* cleared need_sync; need_sync == false only means a covering +* CWAIT is queued, not that all prior commands have completed. +* Wait for the last allocated sequence number so that any +* command queued before this call (possibly on another CPU) +* is guaranteed to have completed before returning. +*/ + data = iommu->cmd_sem_val; +raw_spin_unlock_irqrestore (&iommu->lock, flags); +return wait_on_sem (iommu, data); + } + data =get_cmdsem_val (iommu);build_completion_wait (&cmd, iommu, data);
@@ -1422,9 +1434,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)if (ret)return ret; - ret =wait_on_sem (iommu, data); - -return ret; +return wait_on_sem (iommu, data); }static void domain_flush_complete (struct protection_domain *domain)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 224/675 wifi: mac80211: tear down new links on vif update error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 952c02b33f56207a160421bcd61e7ac53c9c59ae ]
When ieee80211_vif_update_links() adds new links it allocates a link container for each and calls ieee80211_link_init() (which registers the per-link debugfs files with file->private_data pointing into the container) and ieee80211_link_setup(). If the subsequent drv_change_vif_links() fails, the error path restores the old pointers and jumps to 'free', which frees the new containers but never removes their debugfs entries or stops the links. The debugfs files survive with file->private_data dangling at the freed container, so a later open()+read() (e.g. link-1/txpower) dereferences freed memory in ieee80211_if_read_link(), a use-after-free.
The removal path already dismantles links correctly via ieee80211_tear_down_links(), which removes each link's keys and debugfs entries and calls ieee80211_link_stop(); the add path on the error branch does not. Commit be1ba9ed221f ("wifi: mac80211: avoid weird state in error path") hardened this same error path for the link-removal case (new_links == 0) but left the newly-added links' teardown unaddressed.
drv_change_vif_links() can fail at runtime on MLO drivers (internal allocation / queue / firmware command failures).
Remove the new links' debugfs entries and stop them before freeing.
BUG: KASAN: slab-use-after-free in ieee80211_if_read_link (net/mac80211/debugfs_netdev.c:127) Read of size 8 at addr ffff888011290000 by task exploit/145 Call Trace: ... ieee80211_if_read_link (net/mac80211/debugfs_netdev.c:127) short_proxy_read (fs/debugfs/file.c:373) vfs_read (fs/read_write.c:572) ksys_read (fs/read_write.c:716) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) ... Oops: general protection fault, probably for non-canonical address 0xdffffc000000000a RIP: 0010:ieee80211_if_read_link (net/mac80211/debugfs_netdev.c:127) Kernel panic - not syncing: Fatal exception
--- net/mac80211/link.c | 4 ++++ 1 file changed, 4 insertions(+)
net/mac80211/link.c +4 -0
@@ -382,6 +382,10 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,memcpy (sdata->link, old_data,sizeof (old_data));memcpy (sdata->vif.link_conf, old,sizeof (old));ieee80211_set_vif_links_bitmaps (sdata, old_links, dormant_links); +for_each_set_bit (link_id, &add,IEEE80211_MLD_MAX_NUM_LINKS ) { +ieee80211_link_debugfs_remove (&links[link_id]->data); +ieee80211_link_stop (&links[link_id]->data); + }/* and free (only) the newly allocated links */ memset (to_free,0 ,sizeof (links)); goto free;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 225/675 nfp: Check resource mutex allocation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit a61b4db34a753bdf5c9e77a7f3d3dddd41dcfacc ]
nfp_cpp_resource_find() allocates a CPP mutex handle for the matching resource-table entry and then reports success. nfp_resource_try_acquire() immediately passes that handle to nfp_cpp_mutex_trylock().
However, nfp_cpp_mutex_alloc() returns NULL on failure. If that happens for a matching table entry, the resource lookup still returns success and the following trylock dereferences a NULL mutex pointer while opening the resource.
nfp_resource_acquire() already treats failure to allocate the table mutex as -ENOMEM. Do the same for the resource mutex and fail the lookup before publishing the rest of the resource handle.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +3 -0
@@ -96,6 +96,9 @@ static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) res->mutex =nfp_cpp_mutex_alloc (cpp,NFP_RESOURCE_TBL_TARGET , addr, key); +if (!res->mutex) +return -ENOMEM ; + res->cpp_id =NFP_CPP_ID (entry.region.cpp_target, entry.region.cpp_action, entry.region.cpp_token);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 226/675 wan: wanxl: Only reset hardware after BAR mapping
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 91957b89da995607cb654b1f9a3c126ddbaee10f ]
wanxl_pci_init_one() stores the freshly allocated card in driver data before the PLX BAR is mapped. Several early probe failures then unwind through wanxl_pci_remove_one(), including failure to allocate the coherent status area or to restore the DMA mask.
wanxl_pci_remove_one() unconditionally calls wanxl_reset(), and wanxl_reset() dereferences card->plx. On those early failures card->plx is still NULL, so the error path can dereference a NULL MMIO pointer.
Only issue the hardware reset once the BAR mapping exists. The remaining cleanup in wanxl_pci_remove_one() already checks whether later resources were allocated.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/net/wan/wanxl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wan/wanxl.c +2 -1
@@ -514,7 +514,8 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev)if (card->irq)free_irq (card->irq, card); -wanxl_reset (card); +if (card->plx) +wanxl_reset (card);for (i =0 ; i <RX_QUEUE_LENGTH ; i++)if (card->rx_skbs[i]) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 227/675 vhost-net: fix TX stall when vhost owns virtio-net header
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Enrico Zanda <[email protected]>
[ Upstream commit 3c0d10f233f19153f81fef685b5c6716776a5af3 ]
When vhost owns the virtio-net header, i.e. when VHOST_NET_F_VIRTIO_NET_HDR is negotiated, sock_hlen is 0, meaning that no header will be forwarded to the TAP device.
In the current vhost_net_build_xdp() implementation,
when sock_hlen == 0, the gso pointer can point at the start of the Ethernet frame instead of a virtio-net header.
This results in a wrong interpretation of the destination MAC address bytes as struct virtio_net_hdr fields.
This can, for some MAC addresses, trigger -EINVAL and return early before the TX descriptor is completed, which can stall vhost-net TX.
Before 97b2409f28e0, the gso pointer was set to the zeroed padding area, using it as a synthetic virtio-net header. Restore that behavior.
--- drivers/vhost/net.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/vhost/net.c +5 -3
@@ -724,10 +724,12 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, goto err; } - gso = buf + pad - sock_hlen; - -if (!sock_hlen) +if (!sock_hlen) {memset (buf,0 , pad); + gso = buf; + }else { + gso = buf + pad - sock_hlen; + }if ((gso->flags &VIRTIO_NET_HDR_F_NEEDS_CSUM ) && vhost16_to_cpu(vq, gso->csum_start) +
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 228/675 wifi: mwifiex: bound uAP association event IEs to the event buffer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: HE WEI (ギカク) <[email protected]>
[ Upstream commit f0858bfc7d3cab411a447b88e3ef970e575032c9 ]
mwifiex_process_uap_event() handles EVENT_UAP_STA_ASSOC by exposing the (re)association request IEs that the firmware copies into the event:
sinfo->assoc_req_ies = &event->data[len]; len = (u8 *)sinfo->assoc_req_ies - (u8 *)&event->frame_control; sinfo->assoc_req_ies_len = le16_to_cpu(event->len) - (u16)len;
event->len is supplied by the device firmware and is never validated, and the subtraction is unchecked. assoc_req_ies points into adapter->event_body[MAX_EVENT_SIZE], a fixed-size array embedded in the kmalloc()'d struct mwifiex_adapter.
On the ap_11n_enabled path mwifiex_set_sta_ht_cap() walks these IEs with cfg80211_find_ie(), whose for_each_element() loop dereferences each element header. A firmware-reported event->len larger than the bytes actually received makes assoc_req_ies_len describe IEs that extend past event_body, so the walk reads out of the adapter slab object, a slab-out-of-bounds read (KASAN: slab-out-of-bounds in cfg80211_find_ie). An event->len smaller than the header instead makes the int subtraction negative, which wraps to a huge size_t when stored in assoc_req_ies_len. The same length is handed to cfg80211_new_sta(), so a more modest over-claim can also copy stale event_body bytes into the NL80211_CMD_NEW_STATION notification.
A malicious or malfunctioning mwifiex device (USB/SDIO/PCIe) can deliver such an event while the interface is in AP/uAP mode.
Validate event->len before use: reject a length that underflows the header or that would place the IEs outside the event_body[] buffer the event was copied into. event->len here is struct mwifiex_assoc_event.len, a payload field internal to this event, not the transport frame length, so it is validated in this handler rather than at the generic MWIFIEX_TYPE_EVENT receive path, which only sees the event cause and the transport frame length. The bound is against event_body[MAX_EVENT_SIZE] rather than the actually-received length because the transports store the event differently (USB and SDIO leave the 4-byte event header in event_skb, PCIe strips it via skb_pull), whereas event_body is the single fixed buffer all of them copy the event into. This is the event-path analogue of the receive-path bounds checks added in commit 119585281617 ("wifi: mwifiex: Fix OOB and integer underflow when rx packets").
--- .../net/wireless/marvell/mwifiex/uap_event.c | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/mwifiex/uap_event.c +22 -2
@@ -123,11 +123,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) len =ETH_ALEN ;if (len !=-1 ) { +u16 evt_len =le16_to_cpu (event->len); + sinfo->assoc_req_ies = &event->data[len]; len = (u8 *)sinfo->assoc_req_ies - (u8 *)&event->frame_control; - sinfo->assoc_req_ies_len = -le16_to_cpu (event->len) - (u16 )len; + +/* +* event->len is reported by the device firmware +* and is not otherwise validated. Reject a +* length that underflows the header, or that +* would place the association request IEs +* outside the fixed-size event_body[] buffer the +* event was copied into; otherwise the IE walk +* in mwifiex_set_sta_ht_cap() reads past +* event_body and out of the adapter slab object. +*/ +if (evt_len < len || + (u8 *)&event->frame_control + evt_len > + adapter->event_body +MAX_EVENT_SIZE ) { +mwifiex_dbg (adapter,ERROR , +"invalid STA assoc event length\n" ); +kfree (sinfo); +return -1 ; + } + sinfo->assoc_req_ies_len = evt_len - (u16 )len; } } cfg80211_new_sta(priv->netdev, event->sta_addr, sinfo,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 229/675 iommu/amd: Bound the early ACPI HID map
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit fb80117fddb5b477218dc99bb53911b72c3847f8 ]
The ivrs_acpihid command-line parser appends entries to a fixed four-element early_acpihid_map array. Unlike the sibling IOAPIC and HPET parsers, it does not reject a fifth entry before incrementing the map size.
Check the capacity at the common found label before parsing the HID and UID or writing the entry.
--- drivers/iommu/amd/init.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/iommu/amd/init.c +6 -0
@@ -3860,6 +3860,12 @@ static int __init parse_ivrs_acpihid(char *str)return 1 ; found: +if (early_acpihid_map_size ==EARLY_MAP_SIZE ) { +pr_err ("Early ACPI HID map overflow - ignoring ivrs_acpihid%s\n" , + str); +return 1 ; + } + p = acpiid; hid =strsep (&p,":" ); uid = p;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 230/675 iommu/intel: Fix out-of-bounds memset in dmar_latency_disable()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit 754f8efe45f87e3a9c6871b645b2f9d46d1b407b ]
dmar_latency_disable() intends to zero out only the single latency_statistic entry for the given type, but the memset size was computed as sizeof(*lstat) * DMAR_LATENCY_NUM, which clears the entire array starting from &lstat[type].
When type > 0, this writes beyond the end of the allocated array, corrupting adjacent memory.
Fix by using sizeof(*lstat) to clear only the target entry.
--- drivers/iommu/intel/perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/intel/perf.c +1 -1
@@ -63,7 +63,7 @@ void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)return ;spin_lock_irqsave (&latency_lock, flags); -memset (&lstat[type],0 ,sizeof (*lstat) *DMAR_LATENCY_NUM ); +memset (&lstat[type],0 ,sizeof (*lstat));spin_unlock_irqrestore (&latency_lock, flags); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 231/675 wifi: mac80211: recalculate TIM when a station enters power save
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Pope <[email protected]>
[ Upstream commit a007a384c9eb17610f53a53e2f59944c31f1565a ]
When an AP buffers frames for a station on its per-station TXQs and the station subsequently enters power save, sta_ps_start() records the buffered TIDs in txq_buffered_tids but does not update the TIM. The station's TIM bit is only ever set when a further frame is buffered while the station is already asleep (ieee80211_tx_h_unicast_ps_buf() -> sta_info_recalc_tim()).
If no further downlink frame arrives for that station the beacon TIM never advertises the buffered traffic. A station relying on the TIM then remains in doze indefinitely on top of a non-empty queue. Its TXQs were removed from the scheduler's active list at PS entry, nothing pages it, and the flow deadlocks until an unrelated event wakes the station.
Recalculate the TIM at the end of sta_ps_start(), so traffic already buffered at PS entry is advertised immediately. sta_info_recalc_tim() already consults txq_buffered_tids, which is updated above, and is safe in this context (it is already called from equivalent paths such as the tx handlers and ieee80211_handle_filtered_frame()).
--- net/mac80211/rx.c | 2 ++ 1 file changed, 2 insertions(+)
net/mac80211/rx.c +2 -0
@@ -1612,6 +1612,8 @@ static void sta_ps_start(struct sta_info *sta)else clear_bit (tid, &sta->txq_buffered_tids); } + +sta_info_recalc_tim (sta); }static void sta_ps_end (struct sta_info *sta)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 232/675 pds_core: reject component parameter in legacy firmware update
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit 7be2552e601c247a328a5aba6fc06ac844b94a16 ]
The legacy firmware update path does not support per-component updates. If a user specifies a component parameter with devlink flash, reject the request with -EOPNOTSUPP rather than silently ignoring the component parameter and flashing the entire firmware image.
--- drivers/net/ethernet/amd/pds_core/devlink.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/ethernet/amd/pds_core/devlink.c +6 -0
@@ -89,6 +89,12 @@ int pdsc_dl_flash_update(struct devlink *dl, {struct pdsc *pdsc =devlink_priv (dl); +if (params->component) { +NL_SET_ERR_MSG_MOD (extack, +"Component update not supported by this device" ); +return -EOPNOTSUPP ; + } +return pdsc_firmware_update (pdsc, params->fw, extack); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 233/675 arm64: Correct value returned by ESR_ELx_FSC_ADDRSZ_nL()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Price <[email protected]>
[ Upstream commit b877075d0baa22c225842c2f19e3ea0a9cbcbe39 ]
Address size fault, level -1 is encoded as 0b101001 or 0x29 according to the Arm ARM. Correct the value to match the spec. This also matches the offset of "level -1 address size fault" in the fault_info array in fault.c.
--- arch/arm64/include/asm/esr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/include/asm/esr.h +1 -1
@@ -130,7 +130,7 @@* Annoyingly, the negative levels for Address size faults aren't laid out * contiguously (or in the desired order) */ -#define ESR_ELx_FSC_ADDRSZ_nL (n) ((n) == -1 ? 0x25 : 0x2C) +#define ESR_ELx_FSC_ADDRSZ_nL (n) ((n) == -1 ? 0x29 : 0x2C)#define ESR_ELx_FSC_ADDRSZ_L (n) ((n) < 0 ? ESR_ELx_FSC_ADDRSZ_nL(n) : \ (ESR_ELx_FSC_ADDRSZ + (n)))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 234/675 amd-xgbe: fix MAC_AUTO_SW handling in CL37 AN
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prashanth Kumar KR <[email protected]>
[ Upstream commit 4bf22afe53a1de4b44b04cf677fd5199089cbdff ]
MAC_AUTO_SW (VR_MII_DIG_CTRL1 bit 9) enables automatic XPCS speed mode switching after CL37 auto-negotiation and is only meaningful in SGMII MAC mode. The original code unconditionally set this bit on every call to xgbe_an37_set(), including when called from xgbe_an37_disable() with enable=false. This left MAC_AUTO_SW=1 after AN was disabled, causing the XPCS to autonomously switch speed from stale AN state during subsequent mode changes, breaking SGMII speed negotiation on 1G copper SFP modules.
Patrick: This was breaking negotiation for all 1G SFP modules, not just copper modules.
--- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +8 -3
@@ -267,9 +267,14 @@ static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,XMDIO_WRITE (pdata,MDIO_MMD_VEND2 ,MDIO_CTRL1 , reg); - reg =XMDIO_READ (pdata,MDIO_MMD_VEND2 ,MDIO_PCS_DIG_CTRL ); - reg |=XGBE_VEND2_MAC_AUTO_SW ; -XMDIO_WRITE (pdata,MDIO_MMD_VEND2 ,MDIO_PCS_DIG_CTRL , reg); +if (pdata->an_mode ==XGBE_AN_MODE_CL37_SGMII ) { + reg =XMDIO_READ (pdata,MDIO_MMD_VEND2 ,MDIO_PCS_DIG_CTRL ); +if (enable) + reg |=XGBE_VEND2_MAC_AUTO_SW ; +else + reg &= ~XGBE_VEND2_MAC_AUTO_SW ; +XMDIO_WRITE (pdata,MDIO_MMD_VEND2 ,MDIO_PCS_DIG_CTRL , reg); + } }static void xgbe_an37_restart (struct xgbe_prv_data *pdata)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 235/675 soreuseport: Clear sk_reuseport_cb before failure in sk_clone().
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 98da8ce87dd561f08fbe44f75865edc5d9b2ba5f ]
When sk_clone() fails, sk_destruct() is called for the new socket.
If the parent socket has sk->sk_reuseport_cb, the child will call reuseport_detach_sock() for the reuseport group.
Let's clear sk->sk_reuseport_cb before any failure path in sk_clone().
Note that this was not a problem before the cited commit because reuseport_detach_sock() did nothing if the socket was not found in the reuseport array.
--- net/core/sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/sock.c +2 -2
@@ -2525,6 +2525,8 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)cgroup_sk_clone (&newsk->sk_cgrp_data); +RCU_INIT_POINTER (newsk->sk_reuseport_cb,NULL ); +rcu_read_lock (); filter =rcu_dereference (sk->sk_filter);if (filter !=NULL )
@@ -2547,8 +2549,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) goto free; } -RCU_INIT_POINTER (newsk->sk_reuseport_cb,NULL ); -if (bpf_sk_storage_clone (sk, newsk)) goto free;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 236/675 net: Call net_enable_timestamp() before failure in sk_clone().
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit d50557779257a00162411e3048d82971ff1f644c ]
When sk_clone() fails, sk_destruct() is called for the new socket.
If the parent socket has SK_FLAGS_TIMESTAMP in sk->sk_flags, net_disable_timestamp() is called for the child socket even though net_enable_timestamp() is not called for it.
Let's call net_enable_timestamp() before any failure path in sk_clone().
--- net/core/sock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/core/sock.c +3 -3
@@ -2527,6 +2527,9 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)RCU_INIT_POINTER (newsk->sk_reuseport_cb,NULL ); +if (sock_needs_netstamp (sk) && newsk->sk_flags &SK_FLAGS_TIMESTAMP ) +net_enable_timestamp (); +rcu_read_lock (); filter =rcu_dereference (sk->sk_filter);if (filter !=NULL )
@@ -2575,9 +2578,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)if (newsk->sk_prot->sockets_allocated)sk_sockets_allocated_inc (newsk); - -if (sock_needs_netstamp (sk) && newsk->sk_flags &SK_FLAGS_TIMESTAMP ) -net_enable_timestamp (); out:return newsk; free:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 237/675 net: txgbe: fix FDIR filter leak on remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit ecaa37826340520664a4e5522f803ff48fc3f564 ]
Perfect FDIR filters can be added while the interface is down and are kept on the software list for later restore. unregister_netdev() only calls ndo_stop when the device is up, so txgbe_fdir_filter_exit() in txgbe_close() is skipped in that case and the filters are leaked on driver remove. Free the filter list from txgbe_remove() as well.
--- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +1 -0
@@ -956,6 +956,7 @@ static void txgbe_remove(struct pci_dev *pdev) netdev = wx->netdev;wx_disable_sriov (wx);unregister_netdev (netdev); +txgbe_fdir_filter_exit (wx);txgbe_remove_phy (txgbe);wx_free_isb_resources (wx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 238/675 sctp: fix auth_chunk_list capacity check in sctp_auth_ep_add_chunkid
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: HanQuan <[email protected]>
[ Upstream commit ff04b26794a16a8a879eb4fd2c02c2d6b03850e9 ]
sctp_auth_ep_add_chunkid() uses SCTP_NUM_CHUNK_TYPES (20) as the capacity limit for ep->auth_chunk_list, allowing it to hold up to 20 chunk entries (param_hdr.length up to 24). However, the copy destination asoc->c.auth_chunks in struct sctp_cookie is only SCTP_AUTH_MAX_CHUNKS (16) entries (20 bytes). When more than 16 chunks are added, sctp_association_init() memcpy overflows the destination by up to 4 bytes.
Fix by using SCTP_AUTH_MAX_CHUNKS as the capacity limit, matching the destination capacity.
--- net/sctp/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sctp/auth.c +1 -1
@@ -672,7 +672,7 @@ int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id)/* Check if we can add this chunk to the array */ param_len =ntohs (p->param_hdr.length); nchunks = param_len -sizeof (struct sctp_paramhdr ); -if (nchunks ==SCTP_NUM_CHUNK_TYPES ) +if (nchunks ==SCTP_AUTH_MAX_CHUNKS )return -EINVAL ; p->chunks[nchunks] = chunk_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 239/675 pds_core: fix deadlock between reset thread and remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit ab0eec0ff0a421737a37f510ceab5c6ea59cd05a ]
pci_reset_function() acquires device_lock before performing the reset. pdsc_remove() is called by the PCI core with device_lock already held. If pdsc_pci_reset_thread() is running when pdsc_remove() is called, destroy_workqueue() will block waiting for the work to complete, while the work is blocked waiting for device_lock - deadlock.
Use pci_try_reset_function() which uses pci_dev_trylock() internally. This acquires both the device lock and the PCI config access lock without blocking - if either lock is contended, it returns -EAGAIN immediately. This avoids the deadlock while also ensuring proper config space access serialization during the reset.
The pci_dev_get/put calls are also removed as they were unnecessary - the driver-owned workqueue is destroyed in pdsc_remove(), guaranteeing the work completes before remove returns. The PCI core holds its reference to pci_dev throughout the entire unbind sequence.
--- drivers/net/ethernet/amd/pds_core/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ethernet/amd/pds_core/core.c +4 -3
@@ -603,9 +603,10 @@ void pdsc_pci_reset_thread(struct work_struct *work) struct pdsc *pdsc = container_of(work, struct pdsc, pci_reset_work);struct pci_dev *pdev = pdsc->pdev; -pci_dev_get (pdev); -pci_reset_function (pdev); -pci_dev_put (pdev); +/* Use try variant to avoid deadlock with pdsc_remove(). +* If lock is contended, the watchdog timer will retry. +*/ +pci_try_reset_function (pdev); }static void pdsc_check_pci_health (struct pdsc *pdsc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 240/675 pds_core: fix use-after-free on workqueue during remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit 0ad134881508c36b65c1a8864f8bec53adbd3327 ]
In pdsc_remove(), the workqueue is destroyed before pdsc_teardown() is called. This ordering allows two paths to queue work on the destroyed workqueue:
1. If pdsc_teardown() -> pdsc_devcmd_reset() times out, the error path in pdsc_devcmd_locked() queues health_work.
2. A NotifyQ event can trigger the ISR and queue work before free_irq() is called in pdsc_teardown().
Fix by moving destroy_workqueue() after pdsc_teardown() so the workqueue outlives every queuer; destroy_workqueue() then flushes any work still pending.
Draining the queued work also requires ordering the teardown so the resources that work touches are freed last:
- In pdsc_qcq_free(), after freeing the interrupt, cancel_work_sync()
the queue's work and only then clear qcq->intx, so
pdsc_process_adminq()'s read of qcq->intx for interrupt-credit
return cannot race with the clear.- Free adminqcq before notifyqcq: the shared adminq ISR is released when adminqcq is freed, and the adminq work accesses notifyqcq, so both must be stopped before notifyqcq is freed.
--- drivers/net/ethernet/amd/pds_core/core.c | 14 ++++++++++---- drivers/net/ethernet/amd/pds_core/main.c | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-)
drivers/net/ethernet/amd/pds_core/core.c +10 -4
@@ -110,7 +110,6 @@ static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq)return ;pdsc_intr_free (pdsc, qcq->intx); - qcq->intx =PDS_CORE_INTR_INDEX_NOT_ASSIGNED ; }static int pdsc_qcq_intr_alloc (struct pdsc *pdsc,struct pdsc_qcq *qcq)
@@ -145,6 +144,12 @@ void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq)pdsc_qcq_intr_free (pdsc, qcq); +/* Drain any work queued by ISR before it was freed above */ +if (qcq->work.func) +cancel_work_sync (&qcq->work); + + qcq->intx =PDS_CORE_INTR_INDEX_NOT_ASSIGNED ; +if (qcq->q_base)dma_free_coherent (dev, qcq->q_size, qcq->q_base, qcq->q_base_pa);
@@ -304,8 +309,11 @@ int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index,static void pdsc_core_uninit (struct pdsc *pdsc) { -pdsc_qcq_free (pdsc, &pdsc->notifyqcq); +/* Free adminqcq first: its work accesses notifyqcq, so we must +* disable its IRQ and drain its work before freeing notifyqcq. +*/ pdsc_qcq_free (pdsc, &pdsc->adminqcq); +pdsc_qcq_free (pdsc, &pdsc->notifyqcq);if (pdsc->kern_dbpage) {iounmap (pdsc->kern_dbpage);
@@ -478,8 +486,6 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) {if (!pdsc->pdev->is_virtfn)pdsc_devcmd_reset (pdsc); -if (pdsc->adminqcq.work.func) -cancel_work_sync (&pdsc->adminqcq.work);pdsc_core_uninit (pdsc);
drivers/net/ethernet/amd/pds_core/main.c +3 -2
@@ -436,8 +436,6 @@ static void pdsc_remove(struct pci_dev *pdev)pdsc_auxbus_dev_del (pdsc, pdsc, &pdsc->padev);timer_shutdown_sync (&pdsc->wdtimer); -if (pdsc->wq) -destroy_workqueue (pdsc->wq);mutex_lock (&pdsc->config_lock);set_bit (PDSC_S_STOPPING_DRIVER , &pdsc->state);
@@ -445,6 +443,9 @@ static void pdsc_remove(struct pci_dev *pdev)pdsc_stop (pdsc);pdsc_teardown (pdsc,PDSC_TEARDOWN_REMOVING );mutex_unlock (&pdsc->config_lock); + +if (pdsc->wq) +destroy_workqueue (pdsc->wq);mutex_destroy (&pdsc->config_lock);mutex_destroy (&pdsc->devcmd_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 241/675 pds_core: yield the CPU while waiting for the adminq to drain
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit a11f0b8a204296fe7db9eaec53441012222cb004 ]
pdsc_adminq_wait_and_dec_once_unused() busy-waits for adminq_refcnt to drop to one:
while (!refcount_dec_if_one(&pdsc->adminq_refcnt)) cpu_relax();
The refcount is held by pdsc_adminq_post() for the duration of an in-flight command, which can wait up to devcmd_timeout seconds (PDS_CORE_DEVCMD_TIMEOUT is 5) for the hardware to complete. cpu_relax() is not a reschedule point, so on a non-preemptible kernel this loop can spin on the CPU for several seconds, starving other tasks on that core.
Add cond_resched() to the loop so the waiter yields to other runnable tasks while it polls, keeping cpu_relax() as the busy-wait hint between checks.
--- drivers/net/ethernet/amd/pds_core/core.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/amd/pds_core/core.c +1 -0
@@ -536,6 +536,7 @@ static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)dev_dbg_ratelimited (pdsc->dev,"%s: adminq in use\n" , __func__);cpu_relax (); +cond_resched (); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 242/675 pds_core: order completion reads after the ownership check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit dd6b1cc748cd28147c113f9daa76393916ad9494 ]
pdsc_process_adminq() and pdsc_process_notifyq() decide a completion is valid from its ownership field - the color bit for the adminq, the event id for the notifyq - then read the rest of the descriptor, with no barrier in between.
On a weakly ordered architecture the CPU may read the payload first. Add dma_rmb() between the ownership read and the payload reads.
--- drivers/net/ethernet/amd/pds_core/adminq.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/net/ethernet/amd/pds_core/adminq.c +11 -1
@@ -18,7 +18,13 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq) comp = cq_info->comp; eid =le64_to_cpu (comp->event.eid);while (eid > pdsc->last_eid) { -u16 ecode =le16_to_cpu (comp->event.ecode); +u16 ecode; + +/* Order the payload read after the event id, the field the +* driver uses to detect a new completion. +*/ +dma_rmb (); + ecode =le16_to_cpu (comp->event.ecode);switch (ecode) {case PDS_EVENT_LINK_CHANGE :
@@ -101,6 +107,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)spin_lock_irqsave (&pdsc->adminq_lock, irqflags); comp = cq->info[cq->tail_idx].comp;while (pdsc_color_match (comp->color, cq->done_color)) { +/* Order the payload reads after the color bit, the field the +* driver uses to detect a new completion. +*/ +dma_rmb (); q_info = &q->info[q->tail_idx]; q->tail_idx = (q->tail_idx +1 ) & (q->num_descs -1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 243/675 pds_core: fix auxiliary device add/del races
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit bfa33cd513c7ceb93c5a4c30e5662acd73c0a916 ]
Two paths add or delete the same slot (pf->vfs[vf_id].padev): a VF's pdsc_reset_done() and the PF's devlink enable_vnet/disable_vnet handler. They serialize on config_lock, but neither guards the slot under it correctly.
add() registers and stores a new auxiliary device without first checking the slot, so a second add of an already-populated slot leaks the first device. del() makes that check outside config_lock, so two concurrent dels can both pass it; the first clears the slot, and the second dereferences a NULL pointer.
Check and update the slot under config_lock in both paths.
--- drivers/net/ethernet/amd/pds_core/auxbus.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/net/ethernet/amd/pds_core/auxbus.c +14 -3
@@ -177,17 +177,21 @@ void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, {struct pds_auxiliary_dev *padev; -if (!*pd_ptr) -return ; -mutex_lock (&pf->config_lock); +/* A concurrent del may have already torn this device down and +* cleared it. +*/ padev = *pd_ptr; +if (!padev) + goto out_unlock; +pds_client_unregister (pf, padev->client_id);auxiliary_device_delete (&padev->aux_dev);auxiliary_device_uninit (&padev->aux_dev); *pd_ptr =NULL ; +out_unlock:mutex_unlock (&pf->config_lock); }
@@ -210,6 +214,13 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,mutex_lock (&pf->config_lock); +/* Nothing to do if the aux device is already present. This also +* guards against a second add overwriting *pd_ptr and leaking the +* first, symmetric with the check in pdsc_auxbus_dev_del(). +*/ +if (*pd_ptr) + goto out_unlock; + mask =BIT_ULL (PDSC_S_FW_DEAD ) |BIT_ULL (PDSC_S_STOPPING_DRIVER );if (cf->state & mask) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 244/675 pds_core: check for workqueue allocation failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit 3a660ca49e2c3807bffe0519db3cff677a5906e0 ]
pdsc_init_pf() does not check whether create_singlethread_workqueue() succeeded.
Fail probe on failure. The workqueue is set up before the timer and mutexes, so its failure path must unwind only the earlier setup.
--- drivers/net/ethernet/amd/pds_core/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/ethernet/amd/pds_core/main.c +7 -2
@@ -239,6 +239,10 @@ static int pdsc_init_pf(struct pdsc *pdsc)/* General workqueue and timer, but don't start timer yet */ snprintf (wq_name,sizeof (wq_name),"%s.%d" ,PDS_CORE_DRV_NAME , pdsc->uid); pdsc->wq =create_singlethread_workqueue (wq_name); +if (!pdsc->wq) { + err = -ENOMEM ; + goto err_out_unmap_bars; + }INIT_WORK (&pdsc->health_work, pdsc_health_thread);INIT_WORK (&pdsc->pci_reset_work, pdsc_pci_reset_thread);timer_setup (&pdsc->wdtimer, pdsc_wdtimer_cb,0 );
@@ -254,7 +258,7 @@ static int pdsc_init_pf(struct pdsc *pdsc) err =pdsc_setup (pdsc,PDSC_SETUP_INIT );if (err) {mutex_unlock (&pdsc->config_lock); - goto err_out_unmap_bars; + goto err_out_shutdown_timer; } err =pdsc_start (pdsc);
@@ -306,13 +310,14 @@ static int pdsc_init_pf(struct pdsc *pdsc)pdsc_stop (pdsc); err_out_teardown:pdsc_teardown (pdsc,PDSC_TEARDOWN_REMOVING ); -err_out_unmap_bars: +err_out_shutdown_timer:timer_shutdown_sync (&pdsc->wdtimer);if (pdsc->wq)destroy_workqueue (pdsc->wq);mutex_destroy (&pdsc->config_lock);mutex_destroy (&pdsc->devcmd_lock);pci_free_irq_vectors (pdsc->pdev); +err_out_unmap_bars:pdsc_unmap_bars (pdsc); err_out_release_regions:pci_release_regions (pdsc->pdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 245/675 sctp: validate stream count in sctp_process_strreset_inreq()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
[ Upstream commit 18ae07691d43183d270de8be9dc8e027906015d9 ]
When processing a RESET_IN_REQUEST from a peer, sctp_process_strreset_inreq() derives the stream count from the parameter length but does not check whether the resulting RESET_OUT_REQUEST would exceed SCTP_MAX_CHUNK_LEN.
The OUT request header (sctp_strreset_outreq, 16 bytes) is 8 bytes larger than the IN request header (sctp_strreset_inreq, 8 bytes). Generally, the IP payload is bounded to 65535 bytes, so the stream list cannot be large enough to trigger the overflow. However, on interfaces with MTU > 65535 (e.g., loopback with IPv6 jumbograms), a stream list that fits within the incoming IN parameter can cause a __u16 overflow in sctp_make_strreset_req() when computing the OUT request size, leading to an undersized skb allocation and a kernel BUG:
net/core/skbuff.c:207 skb_panic
net/core/skbuff.c:2625 skb_put
net/sctp/sm_make_chunk.c:1535 sctp_addto_chunk net/sctp/sm_make_chunk.c:3695 sctp_make_strreset_req
net/sctp/stream.c:655 sctp_process_strreset_inreq
The local setsockopt path validates the generated reset request size. However, for an incoming-only reset, it accounts for the smaller IN request even though the peer must generate an OUT request with the same stream list. Such a request cannot be completed successfully by the peer.
Reject peer IN requests whose corresponding OUT request would exceed SCTP_MAX_CHUNK_LEN. Also tighten the local check so it does not send an IN request that would require an oversized OUT request from the peer.
--- net/sctp/stream.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/sctp/stream.c +5 -1
@@ -308,7 +308,8 @@ int sctp_send_reset_streams(struct sctp_association *asoc, goto out; param_len += str_nums *sizeof (__u16) + -sizeof (struct sctp_strreset_inreq ); + (out ?sizeof (struct sctp_strreset_inreq ) + :sizeof (struct sctp_strreset_outreq )); } if (param_len > SCTP_MAX_CHUNK_LEN -
@@ -639,6 +640,9 @@ struct sctp_chunk *sctp_process_strreset_inreq( nums = (ntohs (param.p->length) -sizeof (*inreq)) /sizeof (__u16); str_p = inreq->list_of_streams; +if (nums *sizeof (__u16) +sizeof (struct sctp_strreset_outreq ) > +SCTP_MAX_CHUNK_LEN -sizeof (struct sctp_reconf_chunk )) + goto out;for (i =0 ; i < nums; i++) {if (ntohs (str_p[i]) >= stream->outcnt) { result =SCTP_STRRESET_ERR_WRONG_SSN ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 246/675 net: mctp i3c: clean up notifier and buses if driver register fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit 03d1057305ef17ac3f5936ac1580bc9a1a826e14 ]
mctp_i3c_mod_init() registers the I3C bus notifier and then walks the existing buses with i3c_for_each_bus_locked(mctp_i3c_bus_add_new, NULL) before registering the I3C device driver. If i3c_driver_register() fails, the function returns the error directly, leaving the notifier registered and every mctp_i3c_bus object created for the existing buses allocated. The notifier is left pointing into the module that failed to load and the bus list is leaked.
Mirror the module exit path on this failure: unregister the notifier and tear down the buses that were added before returning the error.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/net/mctp/mctp-i3c.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/net/mctp/mctp-i3c.c +7 -4
@@ -731,18 +731,21 @@ static __init int mctp_i3c_mod_init(void)int rc; rc =i3c_register_notifier (&mctp_i3c_notifier); -if (rc <0 ) { -i3c_driver_unregister (&mctp_i3c_driver); +if (rc <0 )return rc; - }i3c_for_each_bus_locked (mctp_i3c_bus_add_new,NULL ); rc =i3c_driver_register (&mctp_i3c_driver);if (rc <0 ) -return rc; + goto err_unregister_notifier;return 0 ; + +err_unregister_notifier: +i3c_unregister_notifier (&mctp_i3c_notifier); +mctp_i3c_bus_remove_all (); +return rc; } static __exit void mctp_i3c_mod_exit(void)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 247/675 tls: device: push pending open record on splice EOF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rishikesh Jethwani <[email protected]>
[ Upstream commit eaa39f9f8ac8c1d032cd26b9cd572804e9d7683f ]
On kTLS device-offload sockets, sendfile() with count > EOF can reach ->splice_eof() with a fully assembled but still-open TLS record left pending. tls_device_splice_eof() only flushes partially sent records, so an abrupt close() can drop the final record and the peer receives a short file.
Fix tls_device_splice_eof() to also push pending open records. This matches the software path, where splice EOF already flushes pending open records.
--- net/tls/tls_device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/tls/tls_device.c +4 -2
@@ -594,13 +594,15 @@ void tls_device_splice_eof(struct socket *sock)struct tls_context *tls_ctx =tls_get_ctx (sk);struct iov_iter iter = {}; -if (!tls_is_partially_sent_record (tls_ctx)) +if (!tls_is_partially_sent_record (tls_ctx) && + !tls_is_pending_open_record (tls_ctx))return ;mutex_lock (&tls_ctx->tx_lock);lock_sock (sk); -if (tls_is_partially_sent_record (tls_ctx)) { +if (tls_is_partially_sent_record (tls_ctx) || +tls_is_pending_open_record (tls_ctx)) {iov_iter_bvec (&iter,ITER_SOURCE ,NULL ,0 ,0 );tls_push_data (sk, &iter,0 ,0 ,TLS_RECORD_TYPE_DATA ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 248/675 selftests: af_unix: add USER_NS config
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit f8b1abed736111f914b2c567d9a3db1f71e788e8 ]
This is required to use unshare(CLONE_NEWUSER).
This has not been seen on NIPA before, because the 'af_unix' tests are executed with the 'net' ones, merging their config files. USER_NS is present in tools/testing/selftests/net/config.
This issue is visible when only the af_unix config is used on top of the default one. This is the recommended way to execute selftest targets.
--- tools/testing/selftests/net/af_unix/config | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/net/af_unix/config +1 -0
@@ -1,3 +1,4 @@ CONFIG_AF_UNIX_OOB=y CONFIG_UNIX=y CONFIG_UNIX_DIAG=m +CONFIG_USER_NS=y
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 249/675 selftests: openvswitch: add config file
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 441a820ccef9af80a9ac5a4c85b9c396e595967c ]
The kselftests doc mentions that a config file should be present "if a test needs specific kernel config options enabled". This selftest requires some kernel config, but no config file was provided.
We could say that a sub-target could use the parent's config file, but the kselftests doc doesn't mention anything about that. Plus the net/openvswitch target is the only net target without a config file.
Here is a new config file, which is a trimmed version of the net one, with hopefully the minimal required kconfig on top of 'make defconfig'.
The Fixes tag points to the introduction of the net/openvswitch target, just to help validating this target on stable kernels.
--- tools/testing/selftests/net/openvswitch/config | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tools/testing/selftests/net/openvswitch/config
tools/testing/selftests/net/openvswitch/config new file +16 -0
@@ -0,0 +1,16 @@ +CONFIG_GENEVE=m +CONFIG_INET_DIAG=y +CONFIG_IPV6=y +CONFIG_NETFILTER=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_OVS=y +CONFIG_OPENVSWITCH=m +CONFIG_OPENVSWITCH_GENEVE=m +CONFIG_OPENVSWITCH_GRE=m +CONFIG_OPENVSWITCH_VXLAN=m +CONFIG_PSAMPLE=m +CONFIG_VETH=y +CONFIG_VLAN_8021Q=y +CONFIG_VXLAN=m
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 250/675 selftests: ovpn: add IPV6 and VETH configs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 90c792681a3732caaf7bf5bc435877736baf591a ]
They are required to run the selftests:
- Tests are executed in v4 and v6.
- Virtual Ethernet are used between the different netns.
This has not been seen on NIPA before, because the 'ovpn' tests are executed with the 'tcp_ao' ones, merging their config files. These two kernel config are present in tools/testing/selftests/net/tcp_ao/config.
This issue is visible when only the ovpn config is used on top of the default one. This is the recommended way to execute selftest targets.
--- tools/testing/selftests/net/ovpn/config | 2 ++ 1 file changed, 2 insertions(+)
tools/testing/selftests/net/ovpn/config +2 -0
@@ -4,7 +4,9 @@ CONFIG_CRYPTO_CHACHA20POLY1305=y CONFIG_CRYPTO_GCM=y CONFIG_DST_CACHE=y CONFIG_INET=y +CONFIG_IPV6=y CONFIG_NET=y CONFIG_NET_UDP_TUNNEL=y CONFIG_OVPN=m CONFIG_STREAM_PARSER=y +CONFIG_VETH=y
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 251/675 selftests: ovpn: increase timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 61ac7049aaa86ae044e8a5b94d852218163d5bf8 ]
The default timeout is 45 seconds, that's too low for a few ovpn tests.
Indeed, these tests can take up to 50 seconds with some debug kernel config on NIPA. Set a timeout to 90 seconds, just to be on the safe side.
Note that the Fixes tag here points to the introduction of the ovpn tests because I don't know when they started to take more than 45 seconds. That's OK because a timeout of 1.5 minutes is not exaggerated.
--- tools/testing/selftests/net/ovpn/settings | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/testing/selftests/net/ovpn/settings
tools/testing/selftests/net/ovpn/settings new file +1 -0
@@ -0,0 +1 @@ +timeout=90
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 252/675 selftests: drv-net: increase timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 3529d75d67411497341cd804a045185d6035dff2 ]
The default timeout is 45 seconds, that's too low for the xdp.py test.
Indeed, this test can take up to 3 minutes with some debug kernel config on NIPA. Set a timeout to 6 minutes, just to be on the safe side.
Note that the Fixes tag here points to the introduction of the xdp.py test because I don't know when this test started to take more than 45 seconds. That's OK because a timeout of 6 minutes is not exaggerated.
--- tools/testing/selftests/drivers/net/settings | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/testing/selftests/drivers/net/settings
tools/testing/selftests/drivers/net/settings new file +1 -0
@@ -0,0 +1 @@ +timeout=360
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 253/675 gtp: check skb_pull_data() return in gtp1u_send_echo_resp()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit cd170f051dba9ac146fabcd1b91726487c0cb9fa ]
gtp1u_send_echo_resp() ignores skb_pull_data()'s return value. Its caller gtp1u_udp_encap_recv() only guarantees 16 bytes (udphdr + gtp1_header), but the pull requests 20 (gtp1_header_long + udphdr). For a 16-19 byte echo request the pull fails and returns NULL without advancing skb->data; execution continues, and the following skb_push() plus the IP header pushed by iptunnel_xmit() move skb->data below skb->head, tripping skb_under_panic().
Fix it by dropping the packet when skb_pull_data() fails.
skbuff: skb_under_panic: ...
kernel BUG at net/core/skbuff.c:214!
Call Trace: skb_push (net/core/skbuff.c:2648) iptunnel_xmit (net/ipv4/ip_tunnel_core.c:82) gtp_encap_recv (drivers/net/gtp.c:701 drivers/net/gtp.c:808 drivers/net/gtp.c:920) udp_queue_rcv_one_skb (net/ipv4/udp.c:2388) ... Kernel panic - not syncing: Fatal exception in interrupt
--- drivers/net/gtp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/gtp.c +3 -2
@@ -669,8 +669,9 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)return -1 ;/* pull GTP and UDP headers */ -skb_pull_data (skb, -sizeof (struct gtp1_header_long ) +sizeof (struct udphdr )); +if (!skb_pull_data (skb,sizeof (struct gtp1_header_long ) + +sizeof (struct udphdr ))) +return -1 ; gtp_pkt =skb_push (skb,sizeof (struct gtp1u_packet ));memset (gtp_pkt,0 ,sizeof (struct gtp1u_packet ));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 254/675 nexthop: initialize extack in nh_res_bucket_migrate()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
[ Upstream commit 6347c5314cee49f364aaf2e40ff15415a57a116e ]
nh_res_bucket_migrate() passes an uninitialized netlink_ext_ack to call_nexthop_res_bucket_notifiers(). When nh_notifier_res_bucket_info_init() fails (e.g. the kzalloc returns -ENOMEM), the error is propagated back before any notifier sets extack._msg, and the error path formats the stale pointer with pr_err_ratelimited("%s\n", extack._msg). With CONFIG_INIT_STACK_NONE this dereferences uninitialized stack memory:
Oops: general protection fault, probably for non-canonical address ... KASAN: maybe wild-memory-access in range [...] RIP: 0010:string (lib/vsprintf.c:730) vsnprintf (lib/vsprintf.c:2945) _printk (kernel/printk/printk.c:2504) nh_res_bucket_migrate (net/ipv4/nexthop.c:1816) nh_res_table_upkeep (net/ipv4/nexthop.c:1866) rtm_new_nexthop (net/ipv4/nexthop.c:3323) rtnetlink_rcv_msg (net/core/rtnetlink.c:7076) netlink_sendmsg (net/netlink/af_netlink.c:1900) Kernel panic - not syncing: Fatal exception
Zero-initialize extack so _msg is NULL on error paths that never set it.
--- net/ipv4/nexthop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/nexthop.c +1 -1
@@ -1791,8 +1791,8 @@ static bool nh_res_bucket_migrate(struct nh_res_table *res_table, bool notify_nl, bool force) {struct nh_res_bucket *bucket = &res_table->nh_buckets[bucket_index]; +struct netlink_ext_ack extack = {};struct nh_grp_entry *new_nhge; -struct netlink_ext_ack extack;int err; new_nhge = list_first_entry_or_null(&res_table->uw_nh_entries,
Signature · 1 line
2.53.0