6.18.44-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 126/396 x86/boot: Add volatile, clobbers and zero-length test in memcmp()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mauricio Faria de Oliveira <[email protected]>
[ Upstream commit a8c171c107c0b61a5e7e10cedab0fb72aeaf640d ]
Add the volatile qualifier and clobbers parameter to prevent bugs with instruction reordering and optimization.
Also add TEST for the zero-length case to set ZF, as, if the count register is zero, the REPE prefix does not run the CMPSB instruction, leaving the ZF flag undetermined.
[ bp: Add a comment about the len==0 case. ]
--- arch/x86/boot/string.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/x86/boot/string.c +9 -2
@@ -32,8 +32,15 @@int memcmp (const void *s1,const void *s2,size_t len) {bool diff; - asm("repe cmpsb" - :"=@ccnz" (diff),"+D" (s1),"+S" (s2),"+c" (len)); + +/* +* Make sure ZF is properly set in the len==0 case because in it, +* RCX==0 and the REPE; CMPSB won't get executed. +*/ + asmvolatile ("test %3, %3\n\t" +"repe cmpsb" + :"=@ccnz" (diff),"+D" (s1),"+S" (s2),"+c" (len) + : :"cc" ,"memory" );return diff; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 127/396 net: phylink: put link_gpio if phylink_create fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Marangi <[email protected]>
[ Upstream commit 0fe1e3e8f3380d7862296a73b528d164e96c76b8 ]
In phylink_create() if phylink_register_sfp() returns an error, link_gpio obtained by phylink_parse_fixedlink() is never released. While this is a very unlikely scenario, it's worth to fix/handle this.
This was present from the very first implementation of phylink but got relevant only with the introduction of ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network devices and sfp cages") where additional function were added after phylink_parse_fixedlink() making the release of link_gpio needed if such additional function errored out.
While at it, restructure the exit condition of phylink_create() with the goto pattern to reduce code duplication on handling error conditions.
--- drivers/net/phy/phylink.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
drivers/net/phy/phylink.c +15 -14
@@ -1861,8 +1861,8 @@ struct phylink *phylink_create(struct phylink_config *config, }else if (config->type ==PHYLINK_DEV ) { pl->dev = config->dev; }else { -kfree (pl); -return ERR_PTR (-EINVAL ); + ret = -EINVAL ; + goto free_pl; } pl->mac_supports_eee_ops =phylink_mac_implements_lpi (mac_ops);
@@ -1895,28 +1895,29 @@ struct phylink *phylink_create(struct phylink_config *config,phylink_validate (pl, pl->supported, &pl->link_config); ret =phylink_parse_mode (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto free_pl;if (pl->cfg_link_an_mode ==MLO_AN_FIXED ) { ret =phylink_parse_fixedlink (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio; } pl->req_link_an_mode = pl->cfg_link_an_mode; ret =phylink_register_sfp (pl, fwnode); -if (ret <0 ) { -kfree (pl); -return ERR_PTR (ret); - } +if (ret <0 ) + goto release_link_gpio;return pl; + +release_link_gpio: +if (pl->link_gpio) +gpiod_put (pl->link_gpio); +free_pl: +kfree (pl); +return ERR_PTR (ret); }EXPORT_SYMBOL_GPL (phylink_create);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 128/396 scsi: target: iblock: Fix wrong PR ops NULL check for PREEMPT/RELEASE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: TanZheng <[email protected]>
[ Upstream commit 9c33222bd387312874fbe36ca8002e5c945b9653 ]
In the iblock_execute_pr_out() function, PRO_PREEMPT, PRO_PREEMPT_AND_ABORT, and PRO_RELEASE all perform callback capability checks through ops->pr_clear. The error check allows unimplemented hooks to pass through the gate, resulting dereferencing a NULL function pointer.
Check whether the hooks that need to be called are supported.
--- drivers/target/target_core_iblock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/target/target_core_iblock.c +3 -3
@@ -902,7 +902,7 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,break ;case PRO_PREEMPT :case PRO_PREEMPT_AND_ABORT : -if (!ops->pr_clear) { +if (!ops->pr_preempt) {pr_err ("block_device does not support pr_preempt.\n" );return TCM_UNSUPPORTED_SCSI_OPCODE ; }
@@ -912,8 +912,8 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key, sa == PRO_PREEMPT_AND_ABORT);break ;case PRO_RELEASE : -if (!ops->pr_clear) { -pr_err ("block_device does not support pr_pclear.\n" ); +if (!ops->pr_release) { +pr_err ("block_device does not support pr_release.\n" );return TCM_UNSUPPORTED_SCSI_OPCODE ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 129/396 scsi: ufs: core: Cancel RTC work in active-active suspend
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 f71b4a30983b846b4075bf544e835121e70e6a43 ]
UFS RTC support schedules ufs_rtc_update_work to periodically update the device RTC. The work can issue query commands and access the UFS host controller.
A previous change moved the RTC work cancellation before the PRE_CHANGE vendor suspend callback to close a race in the common suspend path. However, the active-active path jumps directly to vops_suspend after flushing exception handling work and therefore bypasses the cancellation.
If the RTC work runs while the vendor suspend callback is gating or otherwise changing hardware state, it can access the controller during suspend and trigger an SError.
Cancel the RTC work before entering the vendor suspend callback in the active-active path. Since this path now cancels the work, move the RTC work scheduling outside the device and link state restoration block in the resume path. This restarts RTC updates after an active-active suspend and resume cycle.
--- drivers/ufs/core/ufshcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/ufs/core/ufshcd.c +4 -2
@@ -9873,6 +9873,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state == UIC_LINK_ACTIVE_STATE) {ufshcd_disable_auto_bkops (hba);flush_work (&hba->eeh_work); +cancel_delayed_work_sync (&hba->ufs_rtc_update_work); goto vops_suspend; }
@@ -10082,10 +10083,11 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_old_link_state;ufshcd_set_timestamp_attr (hba); -schedule_delayed_work (&hba->ufs_rtc_update_work, -msecs_to_jiffies (UFS_RTC_UPDATE_INTERVAL_MS )); } +schedule_delayed_work (&hba->ufs_rtc_update_work, +msecs_to_jiffies (UFS_RTC_UPDATE_INTERVAL_MS )); +if (ufshcd_keep_autobkops_enabled_except_suspend (hba))ufshcd_enable_auto_bkops (hba);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 130/396 scsi: ufs: core: Avoid IRQ thread wakeup during active UIC command
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Wang <[email protected]>
[ Upstream commit 6475cfb81fc4f6175b6d15d1c205a5168dc10b46 ]
Only return IRQ_WAKE_THREAD when MCQ and ESI are not enabled and no UIC command is active. The default UIC command timeout is 500ms, Using threaded IRQs during an active UIC command increases the risk of timeout due to possible preemption by other system IRQs.
Stable-dep-of: 8a309036f557 ("scsi: ufs: core: Revert "Delegate the interrupt service routine to a threaded IRQ handler"")
--- drivers/ufs/core/ufshcd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/ufs/core/ufshcd.c +6 -2
@@ -7190,8 +7190,12 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)struct ufs_hba *hba = __hba;u32 intr_status, enabled_intr_status; -/* Move interrupt handling to thread when MCQ & ESI are not enabled */ -if (!hba->mcq_enabled || !hba->mcq_esi_enabled) +/* +* Handle interrupt in thread if MCQ or ESI is disabled, +* and no active UIC command. +*/ +if ((!hba->mcq_enabled || !hba->mcq_esi_enabled) && + !hba->active_uic_cmd)return IRQ_WAKE_THREAD ; intr_status =ufshcd_readl (hba,REG_INTERRUPT_STATUS );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 131/396 scsi: ufs: core: Revert "Delegate the interrupt service routine to a threaded IRQ handler"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <[email protected]>
[ Upstream commit 8a309036f557d3ff4efb2beea5132ba91172d934 ]
There have been multiple reports of performance regressions caused by commit 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler"). Hence this revert.
This patch reverts most of the following commits:
* 3c7ac40d7322 ("scsi: ufs: core: Delegate the interrupt service routine to a threaded IRQ handler")
* 6475cfb81fc4 ("scsi: ufs: core: Avoid IRQ thread wakeup during active UIC command")
This patch preserves the following commits:
* 034d319c8899 ("scsi: ufs: core: Fix interrupt handling for MCQ Mode")
* eabcac808ca3 ("scsi: ufs: core: Fix IRQ lock inversion for the SCSI host lock")
--- drivers/ufs/core/ufshcd.c | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-)
drivers/ufs/core/ufshcd.c +3 -36
@@ -7128,7 +7128,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) }/** -* ufshcd_threaded_intr - Threaded interrupt service routine +* ufshcd_intr - Main interrupt service routine * @irq: irq number * @__hba: pointer to adapter instance *
@@ -7136,7 +7136,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)* IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ -static irqreturn_t ufshcd_threaded_intr (int irq,void *__hba) +static irqreturn_t ufshcd_intr (int irq,void *__hba) {u32 last_intr_status, intr_status, enabled_intr_status =0 ;irqreturn_t retval =IRQ_NONE ;
@@ -7175,38 +7175,6 @@ static irqreturn_t ufshcd_threaded_intr(int irq, void *__hba)return retval; } -/** -* ufshcd_intr - Main interrupt service routine -* @irq: irq number -* @__hba: pointer to adapter instance -* -* Return: -* IRQ_HANDLED - If interrupt is valid -* IRQ_WAKE_THREAD - If handling is moved to threaded handled -* IRQ_NONE - If invalid interrupt -*/ -static irqreturn_t ufshcd_intr (int irq,void *__hba) -{ -struct ufs_hba *hba = __hba; -u32 intr_status, enabled_intr_status; - -/* -* Handle interrupt in thread if MCQ or ESI is disabled, -* and no active UIC command. -*/ -if ((!hba->mcq_enabled || !hba->mcq_esi_enabled) && - !hba->active_uic_cmd) -return IRQ_WAKE_THREAD ; - - intr_status =ufshcd_readl (hba,REG_INTERRUPT_STATUS ); - enabled_intr_status = intr_status &ufshcd_readl (hba,REG_INTERRUPT_ENABLE ); - -ufshcd_writel (hba, intr_status,REG_INTERRUPT_STATUS ); - -/* Directly handle interrupts since MCQ ESI handlers does the hard job */ -return ufshcd_sl_intr (hba, enabled_intr_status); -} -static int ufshcd_clear_tm_cmd (struct ufs_hba *hba,int tag) {int err =0 ;
@@ -10835,8 +10803,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)ufshcd_readl (hba,REG_INTERRUPT_ENABLE );/* IRQ registration */ - err =devm_request_threaded_irq (dev, irq, ufshcd_intr, ufshcd_threaded_intr, -IRQF_ONESHOT |IRQF_SHARED ,UFSHCD , hba); + err =devm_request_irq (dev, irq, ufshcd_intr,IRQF_SHARED ,UFSHCD , hba);if (err) {dev_err (hba->dev,"request irq failed\n" ); goto out_disable;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 132/396 scsi: zfcp: Fix memory leak during adapter release by destroying gid_pn_req
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Block <[email protected]>
[ Upstream commit b601fa590e667bd9643feed8c869b6b3e418480d ]
When releasing an adapter we don't free the mempool 'gid_pn_req' that is allocated during the enqueue. This leaks memory:
unreferenced object 0xd8d29297de700 (size 256):
comm "(udev-worker)", pid 2105, jiffies 4294945794
hex dump (first 32 bytes):
00 00 00 00 de ad 4e ad ff ff ff ff 00 00 00 00 ......N.........
ff ff ff ff ff ff ff ff 00 0d c4 5f 67 9d 99 e0 ..........._g...
backtrace (crc 4a5b5da2):
[<000dc45f64da418c>] kmemleak_alloc+0x6c/0xa0
[<000dc45f62b430aa>] __kmalloc_cache_node_noprof+0x36a/0x4d0
[<000dc45f629a535a>] mempool_create_node_noprof+0xaa/0x150
[<000dc45ee2c065e6>] zfcp_allocate_low_mem_buffers+0x96/0x370 [zfcp]
[<000dc45ee2c070f8>] zfcp_adapter_enqueue+0x598/0xd40 [zfcp]
[<000dc45ee2c08eb0>] zfcp_ccw_set_online+0x160/0x210 [zfcp]
[<000dc45f643d4762>] ccw_device_set_online+0x232/0xd80
[<000dc45f643d53d4>] online_store_recog_and_online+0x124/0x390
[<000dc45f643d8238>] online_store+0x298/0x5b0
[<000dc45f62eb0a04>] kernfs_fop_write_iter+0x2c4/0x480
[<000dc45f62c81150>] new_sync_write+0x370/0x4b0
[<000dc45f62c87abe>] vfs_write+0x43e/0x5b0
[<000dc45f62c87ff4>] ksys_write+0x114/0x1f0
[<000dc45f621c4a16>] do_syscall+0x2f6/0x430
[<000dc45f64d9d5d8>] __do_syscall+0xc8/0x1c0
[<000dc45f64dc2224>] system_call+0x74/0xa0Fix this by destroying the mempool during the adapter's release.
--- drivers/s390/scsi/zfcp_aux.c | 1 + 1 file changed, 1 insertion(+)
drivers/s390/scsi/zfcp_aux.c +1 -0
@@ -254,6 +254,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)static void zfcp_free_low_mem_buffers (struct zfcp_adapter *adapter) {mempool_destroy (adapter->pool.erp_req); +mempool_destroy (adapter->pool.gid_pn_req);mempool_destroy (adapter->pool.scsi_req);mempool_destroy (adapter->pool.scsi_abort);mempool_destroy (adapter->pool.qtcb_pool);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 133/396 scsi: target: Clear cmd_cnt when initial counter enrollment fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit a8ddfd2425bbbafadae8700d63ed8a61a4109878 ]
When target_get_sess_cmd() fails during session shutdown because percpu_ref_tryget_live() returns false, the command keeps the se_cmd->cmd_cnt pointer that __target_init_cmd() assigned earlier without owning a reference. Final release through target_release_cmd_kref() then issues an unmatched percpu_ref_put().
Commit 8e288be8606a ("scsi: target: Pass in cmd counter to use during cmd setup") moved the cmd_cnt assignment ahead of the reference acquisition. Clear se_cmd->cmd_cnt whenever the initial target_get_sess_cmd() fails in target_init_cmd() and target_submit_tmr(), so release performs exactly one matching put per acquired reference.
--- drivers/target/target_core_transport.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/target/target_core_transport.c +10 -2
@@ -1691,6 +1691,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, u32 data_length, int task_attr, int data_dir, int flags) { struct se_portal_group *se_tpg; +int ret; se_tpg = se_sess->se_tpg;BUG_ON (!se_tpg);
@@ -1720,7 +1721,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,* necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ -return target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF ); + ret =target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF ); +if (ret) + se_cmd->cmd_cnt =NULL ; + +return ret; }EXPORT_SYMBOL_GPL (target_init_cmd);
@@ -1996,8 +2001,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,* allocation failure. */ ret =core_tmr_alloc_req (se_cmd, fabric_tmr_ptr, tm_type, gfp); -if (ret <0 ) +if (ret <0 ) { + se_cmd->cmd_cnt =NULL ;return -ENOMEM ; + }if (tm_type ==TMR_ABORT_TASK ) se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2005,6 +2012,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,/* See target_submit_cmd for commentary */ ret =target_get_sess_cmd (se_cmd, flags &TARGET_SCF_ACK_KREF );if (ret) { + se_cmd->cmd_cnt =NULL ;core_tmr_release_req (se_cmd->se_tmr_req);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 134/396 net: sxgbe: free TX rings on RX allocation failure
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 c870f7e2890b9f78ac84515a9809cc5c183c975e ]
When RX descriptor ring allocation fails, init_dma_desc_rings() only frees the partially allocated RX rings and returns. The TX rings that were allocated earlier in the same function are leaked.
Rearrange error labels to clean up TX rings upon RX failures.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -5
@@ -599,14 +599,13 @@ static int init_dma_desc_rings(struct net_device *netd)return 0 ; -txalloc_err: -while (queue_num--) -free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize); -return ret; - rxalloc_err:while (queue_num--)free_rx_ring (priv->device, priv->rxq[queue_num], rx_rsize); + queue_num =SXGBE_TX_QUEUES ; +txalloc_err: +while (queue_num--) +free_tx_ring (priv->device, priv->txq[queue_num], tx_rsize);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 135/396 net: sxgbe: check descriptor ring allocation failures
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 51b093a7ba27476e1f639455f005e8d2e75390e4 ]
sxgbe_open() ignores the return value of init_dma_desc_rings() and continues to program DMA with invalid ring addresses when allocation fails. Check the return value and disconnect the PHY on failure.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +4 -1
@@ -1080,7 +1080,9 @@ static int sxgbe_open(struct net_device *dev) priv->dma_buf_sz =SXGBE_ALIGN (DMA_BUFFER_SIZE ); priv->tx_tc =TC_DEFAULT ; priv->rx_tc =TC_DEFAULT ; -init_dma_desc_rings (dev); + ret =init_dma_desc_rings (dev); +if (ret) + goto init_phy_error;/* DMA initialization and SW reset */ ret =sxgbe_init_dma_engine (priv);
@@ -1189,6 +1191,7 @@ static int sxgbe_open(struct net_device *dev) init_error:free_dma_desc_resources (priv); +init_phy_error:if (dev->phydev)phy_disconnect (dev->phydev); phy_error:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 136/396 can: isotp: check register_netdevice_notifier() error in module init
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Minhong He <[email protected]>
[ Upstream commit ef09a13c5afac41a3c4b5f22b8572820d9e7518c ]
Register the netdevice notifier before can_proto_register() and check the return value. If protocol registration fails, unregister the notifier before returning the error.
Align isotp_module_init() with the reordering already done for raw.c (commit c28b3bffe49e ("can: raw: process optimization in raw_init()")) and bcm.c (commit edd1a7e42f1d ("can: bcm: registration process optimization in bcm_module_init()")).
--- net/can/isotp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/can/isotp.c +9 -4
@@ -1888,13 +1888,18 @@ static __init int isotp_module_init(void)pr_info ("can: isotp protocol (max_pdu_size %d)\n" , max_pdu_size); + err =register_netdevice_notifier (&canisotp_notifier); +if (err) +return err; + err =can_proto_register (&isotp_can_proto); -if (err <0 ) +if (err <0 ) {pr_err ("can: registration of isotp protocol failed %pe\n" ,ERR_PTR (err)); -else -register_netdevice_notifier (&canisotp_notifier); +unregister_netdevice_notifier (&canisotp_notifier); +return err; + } -return err; +return 0 ; } static __exit void isotp_module_exit(void)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 137/396 drm/i915/dp: Ignore the sinks DSC max FRL rate without a PCON DSC encoder
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Kaplan <[email protected]>
[ Upstream commit 8891e39e89042e285fd82fdde325d1311ec750a1 ]
intel_dp_hdmi_sink_max_frl() limits the sink's max FRL rate by its DSC max FRL rate whenever the sink supports DSC 1.2. However, the DSC max FRL rate (HF-VSDB DSC_Max_FRL_Rate) only applies to compressed video transport, which requires a DSC 1.2 encoder in the PCON (configured via intel_dp_pcon_dsc_configure()). Without such an encoder the HDMI link always carries uncompressed video, for which the regular Max_FRL_Rate is the correct limit.
Applying the DSC limit unconditionally trains the FRL link at a lower rate than both the PCON and the sink support.
E.g. an LG OLED G4 (Max_FRL_Rate 48 Gbps, DSC_Max_FRL_Rate 24 Gbps) behind a Synaptics VMM7100 PCON (PCON max FRL bw 48 Gbps, no DSC encoder):
Sink max rate from EDID = 24 Gbps
FRL trained with : 24 Gbps
while Windows/macOS train the same hardware at 40/48 Gbps. The too low FRL rate needlessly constrains the formats available to the sink.
Only apply the sink's DSC max FRL rate if the PCON has a DSC 1.2 encoder, matching the gate in intel_dp_pcon_dsc_configure(). PCONs with a DSC encoder keep the current conservative behavior, since the link is trained once and compressed transport may be used for any subsequent mode.
With this the setup above trains at 48 Gbps.
Tested on PTL (xe) with the above PCON/sink combo.
--- drivers/gpu/drm/i915/display/intel_dp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_dp.c +8 -1
@@ -3859,7 +3859,14 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) rate_per_lane = info->hdmi.max_frl_rate_per_lane; max_frl_rate = max_lanes * rate_per_lane; -if (info->hdmi.dsc_cap.v_1p2) { +/* +* The sink's DSC max FRL rate only applies to compressed video +* transport, which requires a DSC 1.2 encoder in the PCON. Without +* one the HDMI link always carries uncompressed video, for which +* the regular max FRL rate is the limit. +*/ +if (drm_dp_pcon_enc_is_dsc_1_2 (intel_dp->pcon_dsc_dpcd) && + info->hdmi.dsc_cap.v_1p2) { max_dsc_lanes = info->hdmi.dsc_cap.max_lanes; dsc_rate_per_lane = info->hdmi.dsc_cap.max_frl_rate_per_lane;if (max_dsc_lanes && dsc_rate_per_lane)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 138/396 fprobe: Fix module reference count leak on error in register_fprobe()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 8cf2f40ceb85047ad8a84dffae3bebc9fed18216 ]
In register_fprobe(), get_ips_from_filter() resolves target function addresses and increments module reference counts via try_module_get() for symbols in kernel modules. If get_ips_from_filter() fails on the second pass and returns an error, register_fprobe() returned directly without releasing module references acquired up to that point.
Fix this by ensuring the cleanup loop executing module_put() runs even when get_ips_from_filter() returns a negative error.
--- kernel/trace/fprobe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/trace/fprobe.c +2 -4
@@ -868,10 +868,8 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilterreturn -ENOMEM ; ret =get_ips_from_filter (filter, notfilter, addrs, mods, num); -if (ret <0 ) -return ret; - - ret =register_fprobe_ips (fp, addrs, ret); +if (ret >=0 ) + ret =register_fprobe_ips (fp, addrs, ret);for (int i =0 ; i < num; i++) {if (mods[i])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 139/396 tracing/mmiotrace: Reset dropped_count in mmio_reset_data()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit c786d2bdf1f3964deee192ad942dee2a741c1e2c ]
mmio_reset_data() is called during tracer initialization, reset, and start. While it resets overrun_detected and prev_overruns, it neglects to reset dropped_count. Consequently, dropped event counts from prior tracing sessions persist in dropped_count and corrupt overrun reports in subsequent runs.
Fix this by explicitly calling atomic_set(&dropped_count, 0) in mmio_reset_data().
--- kernel/trace/trace_mmiotrace.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace_mmiotrace.c +1 -0
@@ -29,6 +29,7 @@ static void mmio_reset_data(struct trace_array *tr) { overrun_detected = false; prev_overruns =0 ; +atomic_set (&dropped_count,0 );tracing_reset_online_cpus (&tr->array_buffer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 140/396 tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit 12b80cdbc54cf615b4717a4e8180063408091ea2 ]
mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.
Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().
--- kernel/trace/trace_mmiotrace.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +10 -2
@@ -294,11 +294,15 @@ device_initcall(init_mmio_trace);static void __trace_mmiotrace_rw (struct trace_array *tr,struct mmiotrace_rw *rw) { -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_rw *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_RW ,sizeof (*entry), trace_ctx);
@@ -321,11 +325,15 @@ void mmio_trace_rw(struct mmiotrace_rw *rw)static void __trace_mmiotrace_map (struct trace_array *tr,struct mmiotrace_map *map) { -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_map *entry;unsigned int trace_ctx; +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; trace_ctx =tracing_gen_ctx_flags (0 ); event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_MAP ,sizeof (*entry), trace_ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 141/396 riscv: drop __init from vec_check_unaligned_access_speed_all_cpus
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anirudh Srinivasan <[email protected]>
[ Upstream commit f51fed61eea0daba2f95f1a6074085e4cd513c7b ]
This function runs within a kthread and need not necessarily finish before system finishes boot and free_initmem() unmaps the .init.text section. This function makes calls to SBI for probing unaligned access speed, and if this is slow for some reason (say some debug prints were added to SBI), the kthread can still be running at this point and result in an instruction page fault when trying to fetch from the freed region.
[ 25.642087] Unable to handle kernel paging request at virtual address ffffffff80a04ef8 [ 25.646694] Current vec_check_unali pgtable: 4K pagesize, 48-bit VAs, pgdp=0x00004000316e9000 [ 25.653170] [ffffffff80a04ef8] pgd=000010004be7e401, p4d=000010004be7e401, pud=000010004be7e001, pmd=000010000c3000e3 [ 25.661244] Oops [#1] [ 25.662997] Modules linked in: [ 25.665357] CPU: 3 UID: 0 PID: 42 Comm: vec_check_unali Not tainted 7.0.0-tt-blackhole-asrinivasan-00007-g30ff73f18211 #570 PREEMPTLAZY [ 25.674669] Hardware name: Tenstorrent Blackhole (DT) [ 25.678545] epc : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.683458] ra : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.688372] epc : ffffffff80a04ef8 ra : ffffffff80a04ef8 sp : ffff8f8000203e20 [ 25.693874] gp : ffffffff814dc168 tp : ffffaf8001ad9900 t0 : 0000000000000000 [ 25.699401] t1 : fffffffffffffff0 t2 : ffffaf8001ad9a10 s0 : ffff8f8000203e30 [ 25.704912] s1 : ffffaf80018dc780 a0 : 0000000000000000 a1 : 0000000000000002 [ 25.710407] a2 : 00000000000001f0 a3 : 0000000000000018 a4 : 0000000000000000 [ 25.715917] a5 : 0000000000000000 a6 : ffffaf8001c03d98 a7 : ffffaf8001c03e30 [ 25.721419] s2 : ffff8f8000023c98 s3 : ffffaf8001aa1240 s4 : ffffffff80a04ee0 [ 25.726937] s5 : 0000000000000000 s6 : 0000000000000000 s7 : 0000000000000000 [ 25.732450] s8 : 0000000000000000 s9 : 0000000000000000 s10: 0000000000000000 [ 25.737944] s11: 0000000000000000 t3 : 0000000000000002 t4 : 0000000000000402 [ 25.743481] t5 : 0000000000000040 t6 : 0000000000000004 ssp : 0000000000000000 [ 25.749024] status: 0000000200000120 badaddr: ffffffff80a04ef8 cause: 000000000000000c [ 25.755060] [<ffffffff80a04ef8>] vec_check_unaligned_access_speed_all_cpus+0x18/0x2c [ 25.760964] [<ffffffff80047a10>] kthread+0xd8/0xfc [ 25.764660] [<ffffffff80010c48>] ret_from_fork_kernel+0x18/0x1c4 [ 25.769220] [<ffffffff80895fe6>] ret_from_fork_kernel_asm+0x16/0x18 [ 25.774018] Code: cccc cccc cccc cccc cccc cccc cccc cccc cccc cccc (cccc) cccc
Drop __init from its signature so that this doesn't happen.
--- arch/riscv/kernel/unaligned_access_speed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/kernel/unaligned_access_speed.c +2 -2
@@ -376,7 +376,7 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus }/* Measure unaligned access speed on all CPUs present at boot in parallel. */ -static int __init vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) +static int vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) {schedule_on_each_cpu (check_vector_unaligned_access);riscv_hwprobe_complete_async_probe ();
@@ -384,7 +384,7 @@ static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __alway return 0; }#else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */ -static int __init vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) +static int vec_check_unaligned_access_speed_all_cpus (void *unused__always_unused ) {return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 142/396 accel/qaic: use sizeof(*trans_hdr) for transaction length check
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
[ Upstream commit d6c075f797a672a6e3bd2fd44aee713801698ec2 ]
In encode_message() the per-transaction lower-bound check compares trans_hdr->len against sizeof(trans_hdr), i.e. the size of the pointer, instead of sizeof(*trans_hdr), the size of struct qaic_manage_trans_hdr.
Every other length check in this file (encode_message() at the loop guard, decode_message(), etc.) correctly uses sizeof(*trans_hdr), so this is an inconsistency. On 64-bit builds the pointer and the struct are both 8 bytes, so the check is correct by coincidence and there is no behavioural change. On 32-bit builds the pointer is 4 bytes, which weakens the minimum-length check below the 8-byte header size.
Use sizeof(*trans_hdr) so the check validates against the actual transaction header size on all builds.
--- drivers/accel/qaic/qaic_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/accel/qaic/qaic_control.c +1 -1
@@ -782,7 +782,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,break ; } trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len); -if (trans_hdr->len <sizeof (trans_hdr) || +if (trans_hdr->len <sizeof (*trans_hdr) ||size_add (user_len, trans_hdr->len) > user_msg->len) { ret = -EINVAL ;break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 143/396 riscv: mm: Fix out-of-bounds page-table walk during memory hot-remove
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit a0188cc133696627857d16054e43f9ebc7efc821 ]
remove_pud_mapping() and remove_p4d_mapping() obtain a child table base with pud_offset(p4dp, 0) and p4d_offset(pgd, 0), then add the index for addr.
RISC-V folds page-table levels at runtime. When a level is folded, its offset helper returns the parent entry itself, but the index can still be nonzero. Adding it walks past the parent table. Sv48 folds P4D, while Sv39 folds both P4D and PUD, so memory hot-remove can descend into unrelated memory and pass an invalid page to __free_pages(). This can trigger:
kernel BUG at include/linux/mm.h:1810!
VM_BUG_ON_PAGE(page_ref_count(page) == 0)
arch_remove_memory+0x1e/0x5c try_remove_memory+0x15e/0x200 remove_memory+0x24/0x3c
Only add the index when the corresponding page-table level is enabled, matching p4d_offset() and pud_offset().
--- arch/riscv/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/riscv/mm/init.c +2 -2
@@ -1738,7 +1738,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, unfor (; addr < end; addr = next) { next =pud_addr_end (addr, end); - pudp = pud_base +pud_index (addr); + pudp = pgtable_l4_enabled ? pud_base +pud_index (addr) : pud_base; pud =pudp_get (pudp);if (!pud_present (pud))continue ;
@@ -1769,7 +1769,7 @@ static void __meminit remove_p4d_mapping(p4d_t *p4d_base, unsigned long addr, unfor (; addr < end; addr = next) { next =p4d_addr_end (addr, end); - p4dp = p4d_base +p4d_index (addr); + p4dp = pgtable_l5_enabled ? p4d_base +p4d_index (addr) : p4d_base; p4d =p4dp_get (p4dp);if (!p4d_present (p4d))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 144/396 net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend
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 b4ce102b2cd88424c5860fbbb20b9eb343a93bf4 ]
bus->read() returns a negative errno on failure, but mt7530_regmap_read() assigns it to a u16, truncating e.g. -ETIMEDOUT into 0xff92, and returns success. The garbage word is then consumed as register data, and read-modify-write cycles write it back to the switch. Check both reads and propagate their errors.
The same defect existed in mt7530_mii_read() since the driver was introduced and moved into the regmap backend unchanged.
--- drivers/net/dsa/mt7530-mdio.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/dsa/mt7530-mdio.c +9 -2
@@ -55,8 +55,15 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)if (ret <0 )return ret; - lo = bus->read (bus, priv->mdiodev->addr, r); - hi = bus->read (bus, priv->mdiodev->addr,0x10 ); + ret = bus->read (bus, priv->mdiodev->addr, r); +if (ret <0 ) +return ret; + lo = ret; + + ret = bus->read (bus, priv->mdiodev->addr,0x10 ); +if (ret <0 ) +return ret; + hi = ret; *val = (hi <<16 ) | (lo &0xffff );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 145/396 net: dsa: mt7530: error out on failed reads in MT7531 PHY polling
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 77a9ebe8818cf6dd1699bd6728cb5d66307801d7 ]
The MT7531 indirect PHY access functions poll MT7531_PHY_IAC through a helper which returns 0 when the underlying read fails, so a failed bus transaction clears MT7531_PHY_ACS_ST and the access carries on, returning garbage PHY register data to phylib.
Poll using regmap_read_poll_timeout(), which stops on read errors and propagates them. These functions hold the MDIO bus lock across the whole sequence, so the unlocked regmap accesses remain correct. Remove the now-unused _mt7530_unlocked_read().
--- drivers/net/dsa/mt7530.c | 58 ++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 38 deletions(-)
drivers/net/dsa/mt7530.c +20 -38
@@ -188,12 +188,6 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)mt7530_mutex_unlock (priv); } -static u32 -_mt7530_unlocked_read (struct mt7530_dummy_poll *p) -{ -return mt7530_mii_read (p->priv, p->reg); -} -static u32 _mt7530_read (struct mt7530_dummy_poll *p) {
@@ -546,16 +540,13 @@ static int mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad, int regnum) { - struct mt7530_dummy_poll p; u32 reg, val;int ret; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -565,8 +556,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | regnum;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -576,8 +567,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad);mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -594,16 +585,13 @@ static int mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad, int regnum, u16 data) { - struct mt7530_dummy_poll p; u32 val, reg;int ret; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -613,8 +601,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | regnum;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -624,8 +612,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,MT7531_MDIO_DEV_ADDR (devad) | data;mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -640,16 +628,13 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,static int mt7531_ind_c22_phy_read (struct mt7530_priv *priv,int port,int regnum) { -struct mt7530_dummy_poll p;int ret;u32 val; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -660,8 +645,8 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)mt7530_mii_write (priv,MT7531_PHY_IAC , val |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, val, - !(val &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , val, + !(val &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -678,16 +663,13 @@ static int mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum, u16 data) { - struct mt7530_dummy_poll p; int ret;u32 reg; -INIT_MT7530_DUMMY_POLL (&p, priv,MT7531_PHY_IAC ); -mt7530_mutex_lock (priv); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, reg, - !(reg &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , reg, + !(reg &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
@@ -698,8 +680,8 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,mt7530_mii_write (priv,MT7531_PHY_IAC , reg |MT7531_PHY_ACS_ST ); - ret =readx_poll_timeout (_mt7530_unlocked_read, &p, reg, - !(reg &MT7531_PHY_ACS_ST ),20 ,100000 ); + ret =regmap_read_poll_timeout (priv->regmap,MT7531_PHY_IAC , reg, + !(reg &MT7531_PHY_ACS_ST ),20 ,100000 );if (ret <0 ) {dev_err (priv->dev,"poll timeout\n" ); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 146/396 ptp: netc: fix potential interrupt storm caused by incorrect unbind order
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <[email protected]>
[ Upstream commit 54ad7ea45d63146a8e3c57375f8a269d4cf7ecea ]
In netc_timer_remove(), hardware interrupts are disabled by clearing TMR_TEMASK before ptp_clock_unregister() is called. This may cause a race condition during driver unbind that could leave hardware interrupts active. For example, a concurrent PTP_CLK_REQ_EXTTS ioctl can re-enable TMR_TEMASK after it has been cleared, leaving a pending hardware interrupt when the driver unbinds.
Since the NETC Timer does not support PCIe FLR, hardware state is not reset during probe. When the driver is rebound and the IRQ is registered, the pending interrupt fires immediately. At that point priv->tmr_emask is still zero, so netc_timer_isr() does not clear the interrupt status and unconditionally returns IRQ_HANDLED, resulting in an uninterruptible infinite interrupt storm.
Fix this in several ways. First, request the IRQ with IRQF_NO_AUTOEN so it is not enabled when request_irq() runs, and clear TMR_TEMASK in netc_timer_init() before enabling it. The IRQ is only enabled at the end of probe once the timer has been reprogrammed and the PTP clock has been registered. This ensures a stale pending interrupt from a previous unbind or an unclean shutdown cannot be delivered before the driver is fully initialized.
Second, in netc_timer_remove() call disable_irq() before ptp_clock_unregister() and move the TMR_TEMASK/TMR_CTRL clearing after it. disable_irq() masks the line and waits for any in-flight netc_timer_isr() to finish, so no ISR can dereference priv->clock after ptp_clock_unregister() has freed it. Unregistering the PTP clock before clearing the mask also guarantees that no in-flight or concurrent ioctl can re-enable hardware interrupts.
Finally, return IRQ_NONE from netc_timer_isr() when the masked event status is zero, so the kernel's spurious interrupt detection can disable a stuck line instead of looping forever.
--- drivers/ptp/ptp_netc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/ptp/ptp_netc.c +12 -3
@@ -769,6 +769,7 @@ static void netc_timer_init(struct netc_timer *priv)TMR_CTRL_TE |TMR_CTRL_FS ;netc_timer_wr (priv,NETC_TMR_CTRL , tmr_ctrl);netc_timer_wr (priv,NETC_TMR_PRSC , priv->oclk_prsc); +netc_timer_wr (priv,NETC_TMR_TEMASK ,0 );/* Disable FIPER by default */ fiper_ctrl =netc_timer_rd (priv,NETC_TMR_FIPER_CTRL );
@@ -901,6 +902,11 @@ static irqreturn_t netc_timer_isr(int irq, void *data)/* Clear interrupts status */ netc_timer_wr (priv,NETC_TMR_TEVENT , tmr_event); +if (!tmr_event) { +spin_unlock (&priv->lock); +return IRQ_NONE ; + } +if (tmr_event &TMR_TEVENT_ALMEN (0 ))netc_timer_alarm_write (priv,NETC_TMR_DEFAULT_ALARM ,0 );
@@ -936,7 +942,8 @@ static int netc_timer_init_msix_irq(struct netc_timer *priv) } priv->irq =pci_irq_vector (pdev,0 ); - err =request_irq (priv->irq, netc_timer_isr,0 , priv->irq_name, priv); + err =request_irq (priv->irq, netc_timer_isr,IRQF_NO_AUTOEN , + priv->irq_name, priv);if (err) {dev_err (&pdev->dev,"request_irq() failed\n" );pci_free_irq_vectors (pdev);
@@ -951,7 +958,6 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv) {struct pci_dev *pdev = priv->pdev; -disable_irq (priv->irq);free_irq (priv->irq, priv);pci_free_irq_vectors (pdev); }
@@ -1005,6 +1011,8 @@ static int netc_timer_probe(struct pci_dev *pdev, goto free_msix_irq; } +enable_irq (priv->irq); +return 0 ; free_msix_irq:
@@ -1019,9 +1027,10 @@ static void netc_timer_remove(struct pci_dev *pdev) {struct netc_timer *priv =pci_get_drvdata (pdev); +disable_irq (priv->irq); +ptp_clock_unregister (priv->clock);netc_timer_wr (priv,NETC_TMR_TEMASK ,0 );netc_timer_wr (priv,NETC_TMR_CTRL ,0 ); -ptp_clock_unregister (priv->clock);netc_timer_free_msix_irq (priv);netc_timer_pci_remove (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 147/396 net: libwx: fix FDIR ATR queue mismatch for software VLAN packets
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiawen Wu <[email protected]>
[ Upstream commit 732ed8f75ce583d115716f668dc80d730f3ad610 ]
When TX VLAN hardware offload is disabled, VLAN tags are embedded in the packet payload (software VLAN). Previously, the driver failed to set the WX_TX_FLAGS_SW_VLAN flag for these packets during transmission.
This missing flag caused the txgbe FDIR ATR logic to fall through to the default hash calculation path. This resulted in asymmetric hash values for Tx and Rx flows, preventing return packets from being steered to the same queue as the transmit packets.
Fix this by detecting software VLANs via eth_type_vlan(skb->protocol) and setting WX_TX_FLAGS_SW_VLAN. This ensures the ATR feature selects the correct hashing algorithm to maintain Tx/Rx queue symmetry.
--- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/wangxun/libwx/wx_lib.c +2 -0
@@ -1549,6 +1549,8 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb,if (skb_vlan_tag_present (skb)) { tx_flags |=skb_vlan_tag_get (skb) <<WX_TX_FLAGS_VLAN_SHIFT ; tx_flags |=WX_TX_FLAGS_HW_VLAN ; + }else if (eth_type_vlan (skb->protocol)) { + tx_flags |=WX_TX_FLAGS_SW_VLAN ; } if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 148/396 octeontx2-pf: Set correct sequence for carrier off and tx queue stop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suman Ghosh <[email protected]>
[ Upstream commit 16809472409d998afcda402e32b8229b389337c4 ]
During link down event, we were doing netif_tx_stop_all_queues() first and then netif_carrier_off(). This can cause a potential race since carrier is still on during down event. This patch reverse the calling order to fix the issue.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -1
@@ -889,8 +889,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)netif_carrier_on (netdev);netif_tx_start_all_queues (netdev); }else { -netif_tx_stop_all_queues (netdev);netif_carrier_off (netdev); +netif_tx_stop_all_queues (netdev); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 149/396 sched/deadline: Use revised wakeup rule only for running dl_server
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriele Monaco <[email protected]>
[ Upstream commit 1842bf97af109f5ebf830175c9725bf81ebb78b1 ]
Commit 14a857056466 ("sched/deadline: Use revised wakeup rule for dl_server") applies the revised wakeup rule to any server, as a result servers that are not running (dl_defer_running == 0) and start with a deadline overflow get enqueued and can boost tasks as if they were running, invalidating the defer rule and the documented state model.
Apply the revised wakeup rule only for deferrable servers that are marked as running.
--- kernel/sched/deadline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched/deadline.c +2 -1
@@ -1036,7 +1036,8 @@ static void update_dl_entity(struct sched_dl_entity *dl_se)if (dl_time_before (dl_se->deadline,rq_clock (rq)) ||dl_entity_overflow (dl_se,rq_clock (rq))) { -if (unlikely ((!dl_is_implicit (dl_se) || dl_se->dl_defer) && +if (unlikely ((!dl_is_implicit (dl_se) || + (dl_se->dl_defer && dl_se->dl_defer_running)) && !dl_time_before (dl_se->deadline,rq_clock (rq)) && !is_dl_boosted (dl_se))) {update_dl_revised_wakeup (dl_se, rq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 150/396 spi: spi-nxp-fspi: add per-SoC SDR/DTR clock rate limits for all supported SoCs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haibo Chen <[email protected]>
[ Upstream commit 9c19d60fea9f46ed0c3394653ef4941f1a459968 ]
The commit f43579ef3500 ("spi: spi-nxp-fspi: limit the clock rate for different sample clock source selection") introduced a global 166MHz cap for DTR mode (RXCLKSRC=3), based on the i.MX8MN datasheet timing specification (Section 3.9.9, page 65).
After reviewing the FlexSPI timing parameters in the datasheets for all supported SoCs, the following corrections and additions are needed:
1. SDR mode (RXCLKSRC=0) limits vary per SoC:
- i.MX8MN/MM/MP/95: 66MHz (IMX8MNCEC §3.9.9, IMX8MMCEC §3.9.10,
IMX8MPCEC, IMX95CEC Rev.8 §4.11.7)
- i.MX8QXP/QM/DXL/ULP: 60MHz (IMX8QXPCEC, IMX8QMCEC, IMX8DXLCEC,
IMX8ULPCEC §7.3.1 ND mode)- LX2160A: 100MHz (LX2160ACEC FlexSPI timing parameters)
2. DTR mode (RXCLKSRC=3) limits vary per SoC:
- i.MX8MN/MM/MP/ULP: 166MHz
- i.MX8QXP/QM/DXL: 200MHz (same FlexSPI IP across this family)
- i.MX95: 200MHz (IMX95CEC §4.11.7.3.2.3 Table 106)
- LX2160A: DTR disabled (FSPI_QUIRK_DISABLE_DTR)
Update related platform data with correct speed limation according to datasheet.
--- drivers/spi/spi-nxp-fspi.c | 83 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-)
drivers/spi/spi-nxp-fspi.c +80 -3
@@ -340,6 +340,18 @@ struct nxp_fspi_devtype_data {unsigned int quirks;unsigned int lut_num;bool little_endian; +/* +* The max clock rate (Hz) that FlexSPI can output to the device +* in SDR mode (RXCLKSRC=0). Defaults to 66MHz if zero. +* Some SoCs (e.g. LX2160A) support up to 100MHz in SDR mode. +*/ +unsigned long max_sdr_rate; +/* +* The max clock rate (Hz) that FlexSPI can output to the device +* in DTR mode (RXCLKSRC=3). Defaults to 166MHz if zero. +* Some SoCs (e.g. i.MX95, i.MX8QM, i.MX8DXL) support up to 200MHz. +*/ +unsigned long max_dtr_rate; };static struct nxp_fspi_devtype_data lx2160a_data = {
@@ -349,6 +361,10 @@ static struct nxp_fspi_devtype_data lx2160a_data = { .quirks = FSPI_QUIRK_DISABLE_DTR, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* LX2160ACEC: SDR RXCLKSRC=0 max 100MHz, DTR disabled via quirk. +*/ + .max_sdr_rate = 100000000, };static struct nxp_fspi_devtype_data imx8mm_data = {
@@ -358,6 +374,21 @@ static struct nxp_fspi_devtype_data imx8mm_data = { .quirks = 0, .lut_num = 32, .little_endian = true, /* little-endian */ + /* IMX8MMCEC §3.9.10: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */ + .max_sdr_rate = 66000000, + .max_dtr_rate = 166000000, +}; + +static struct nxp_fspi_devtype_data imx8mp_data = { + .rxfifo =SZ_512 ,/* (64 * 64 bits) */ + .txfifo =SZ_1K ,/* (128 * 64 bits) */ + .ahb_buf_size =SZ_2K ,/* (256 * 64 bits) */ + .quirks =0 , + .lut_num =32 , + .little_endian = true,/* little-endian */ +/* IMX8MPCEC: SDR RXCLKSRC=0 max 66MHz, DDR RXCLKSRC=3 max 166MHz */ + .max_sdr_rate =66000000 , + .max_dtr_rate =166000000 , };static struct nxp_fspi_devtype_data imx8qxp_data = {
@@ -367,6 +398,12 @@ static struct nxp_fspi_devtype_data imx8qxp_data = { .quirks = 0, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* IMX8QXPCEC: SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 200MHz. +* i.MX8QM and i.MX8DXL share the same FlexSPI IP and limits. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 200000000, };static struct nxp_fspi_devtype_data imx8dxl_data = {
@@ -376,6 +413,12 @@ static struct nxp_fspi_devtype_data imx8dxl_data = { .quirks = FSPI_QUIRK_USE_IP_ONLY, .lut_num = 32, .little_endian = true, /* little-endian */ +/* +* IMX8DXLCEC (i.MX 8XLite): SDR RXCLKSRC=0 max 60MHz, +* DDR RXCLKSRC=3 max 200MHz. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 200000000, };static struct nxp_fspi_devtype_data imx8ulp_data = {
@@ -385,6 +428,29 @@ static struct nxp_fspi_devtype_data imx8ulp_data = { .quirks = 0, .lut_num = 16, .little_endian = true, /* little-endian */ +/* +* IMX8ULPCEC §7.3.1, Normal Drive (ND, 1.0V) mode: +* SDR RXCLKSRC=0 max 60MHz, DDR RXCLKSRC=3 max 166MHz. +* Note: Overdrive (OD, 1.05V) allows up to 180MHz DTR +* but is not the default use case. +*/ + .max_sdr_rate = 60000000, + .max_dtr_rate = 166000000, +}; + +static struct nxp_fspi_devtype_data imx95_data = { + .rxfifo =SZ_512 ,/* (64 * 64 bits) */ + .txfifo =SZ_1K ,/* (128 * 64 bits) */ + .ahb_buf_size =SZ_2K ,/* (256 * 64 bits) */ + .quirks =0 , + .lut_num =32 , + .little_endian = true,/* little-endian */ +/* +* IMX95CEC Rev.8 §4.11.7: SDR RXCLKSRC=0 max 66MHz, +* DDR RXCLKSRC=3 max 200MHz (Nominal/Overdrive mode). +*/ + .max_sdr_rate =66000000 , + .max_dtr_rate =200000000 , };struct nxp_fspi {
@@ -691,10 +757,20 @@ static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f, reg =fspi_readl (f, f->iobase +FSPI_MCR0 );if (op_is_dtr) { reg |=FSPI_MCR0_RXCLKSRC (3 ); - f->max_rate =166000000 ; +/* +* Use the SoC-specific DTR max rate if provided, otherwise +* fall back to 166MHz (limit from IMX8MN datasheet §3.9.9). +*/ + f->max_rate = f->devtype_data->max_dtr_rate ? + f->devtype_data->max_dtr_rate :166000000 ; }else {/*select mode 0 */ reg &= ~FSPI_MCR0_RXCLKSRC (3 ); - f->max_rate =66000000 ; +/* +* Use the SoC-specific SDR max rate if provided, otherwise +* fall back to 66MHz (limit from IMX8MN datasheet §3.9.9). +*/ + f->max_rate = f->devtype_data->max_sdr_rate ? + f->devtype_data->max_sdr_rate :66000000 ; }fspi_writel (f, reg, f->iobase +FSPI_MCR0 ); }
@@ -1446,10 +1522,11 @@ static const struct dev_pm_ops nxp_fspi_pm_ops = {static const struct of_device_id nxp_fspi_dt_ids[] = { { .compatible ="nxp,lx2160a-fspi" , .data = (void *)&lx2160a_data, }, { .compatible ="nxp,imx8mm-fspi" , .data = (void *)&imx8mm_data, }, - { .compatible ="nxp,imx8mp-fspi" , .data = (void *)&imx8mm_data, }, + { .compatible ="nxp,imx8mp-fspi" , .data = (void *)&imx8mp_data, }, { .compatible ="nxp,imx8qxp-fspi" , .data = (void *)&imx8qxp_data, }, { .compatible ="nxp,imx8dxl-fspi" , .data = (void *)&imx8dxl_data, }, { .compatible ="nxp,imx8ulp-fspi" , .data = (void *)&imx8ulp_data, }, + { .compatible ="nxp,imx95-fspi" , .data = (void *)&imx95_data, }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, nxp_fspi_dt_ids);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 151/396 qede: sync udp_tunnel ports outside qede_lock in the recovery path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Denis V. Lunev <[email protected]>
[ Upstream commit 451c9075d6c53f2438d110addbeeeea6fac18567 ]
A TX timeout on a qede NIC that has VXLAN/GENEVE tunnel ports configured wedges the rtnetlink control plane of the whole machine:
NETDEV WATCHDOG: ens6f1 (qede): transmit queue 2 timed out 10226 ms [qede_tx_timeout:586(ens6f1)]TX timeout on queue 2! [qede_recovery_handler:2665(ens6f0)]Starting a recovery process
The recovery path deadlocks on the driver's own mutex:
qede_sp_task
rtnl_lock()
mutex_lock(&edev->qede_lock) <- taken
qede_recovery_handler
qede_load
udp_tunnel_nic_reset_ntf
__udp_tunnel_nic_device_sync
info->sync_table == qede_udp_tunnel_sync
mutex_lock(&edev->qede_lock) <- same task: deadlockThe mutex is not recursive, so the kworker blocks on itself with rtnl_lock held, and neither lock is ever released. Every task that calls rtnl_lock() afterwards (ip, ovs-vswitchd, lldpad, IPv6 addrconf, sshd) blocks forever while the node still answers ping. In a vmcore from an affected production node rtnl_mutex.owner decodes to the very kworker blocked at the innermost mutex_lock() above.
Re-sync the tunnel ports from qede_sp_task() after the internal lock is dropped, still under rtnl_lock as the udp_tunnel API requires. This mirrors qede_open(), which calls udp_tunnel_nic_reset_ntf() under rtnl without the internal lock.
qede_recovery_handler() now returns whether it has successfully reloaded an open device, and the caller re-syncs the ports only in that case. This keeps the old gating exactly: a device that was down or a failed recovery returns false, as those paths never reached the udp_tunnel_nic_reset_ntf() call before either.
This was the only user of the qede_lock()/qede_unlock() helpers, so remove them.
--- drivers/net/ethernet/qlogic/qede/qede_main.c | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/net/ethernet/qlogic/qede/qede_main.c +22 -22
@@ -107,7 +107,7 @@ static void qede_remove(struct pci_dev *pdev);static void qede_shutdown (struct pci_dev *pdev);static void qede_link_update (void *dev,struct qed_link_output *link);static void qede_schedule_recovery_handler (void *dev); -static void qede_recovery_handler (struct qede_dev *edev); +static bool qede_recovery_handler (struct qede_dev *edev);static void qede_schedule_hw_err_handler (void *dev,enum qed_hw_err_type err_type);static void qede_get_eth_tlv_data (void *edev,void *data);
@@ -1065,21 +1065,6 @@ void __qede_unlock(struct qede_dev *edev)mutex_unlock (&edev->qede_lock); } -/* This version of the lock should be used when acquiring the RTNL lock is also -* needed in addition to the internal qede lock. -*/ -static void qede_lock (struct qede_dev *edev) -{ -rtnl_lock (); -__qede_lock (edev); -} - -static void qede_unlock (struct qede_dev *edev) -{ -__qede_unlock (edev); -rtnl_unlock (); -} -static void qede_periodic_task (struct work_struct *work) { struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1116,6 +1101,8 @@ static void qede_sp_task(struct work_struct *work)*/ if (test_and_clear_bit (QEDE_SP_RECOVERY , &edev->sp_flags)) { +bool reloaded; +cancel_delayed_work_sync (&edev->periodic_task);#ifdef CONFIG_QED_SRIOV /* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1124,9 +1111,17 @@ static void qede_sp_task(struct work_struct *work)if (pci_num_vf (edev->pdev))qede_sriov_configure (edev->pdev,0 );#endif -qede_lock (edev); -qede_recovery_handler (edev); -qede_unlock (edev); +rtnl_lock (); +__qede_lock (edev); + reloaded =qede_recovery_handler (edev); +__qede_unlock (edev); + +/* The udp_tunnel core synchronously calls back into +* qede_udp_tunnel_sync(), which takes the qede lock. +*/ +if (reloaded) +udp_tunnel_nic_reset_ntf (edev->ndev); +rtnl_unlock (); }__qede_lock (edev);
@@ -2667,9 +2662,13 @@ static void qede_recovery_failed(struct qede_dev *edev) edev->ops->common->set_power_state (edev->cdev, PCI_D3hot); } -static void qede_recovery_handler (struct qede_dev *edev) +/* Returns true if an open device was successfully reloaded and its +* udp_tunnel ports need to be re-synced by the caller. +*/ +static bool qede_recovery_handler (struct qede_dev *edev) {u32 curr_state = edev->state; +bool reloaded = false;int rc;DP_NOTICE (edev,"Starting a recovery process\n" );
@@ -2699,17 +2698,18 @@ static void qede_recovery_handler(struct qede_dev *edev) goto err;qede_config_rx_mode (edev->ndev); -udp_tunnel_nic_reset_ntf (edev->ndev); + reloaded = true; } edev->state = curr_state;DP_NOTICE (edev,"Recovery handling is done\n" ); -return ; +return reloaded; err:qede_recovery_failed (edev); +return false; }static void qede_atomic_hw_err_handler (struct qede_dev *edev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 152/396 drm/i915/hdmi: Poll for 200 msec for TMDS_Scrambler_Status
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jerome Tollet <[email protected]>
[ Upstream commit 1afb8eaeec44fd011f2b93ccd9fd426d753d963b ]
HDMI 2.0 section 6.1.3.1 specifies that after enabling Scrambling_Enable and starting scrambled video transmission, the source should poll Scrambling_Status until it reads 1 or until a timeout of 200 ms expires.
Add a polling step after enabling the HDMI port to check the scrambling status when HDMI scrambling is enabled.
On some HDMI 2.0 sinks, omitting this check can result in 4K@60Hz (594 MHz) failing to come up correctly because the sink has not yet finished its scrambling setup. In practice, waiting for the scrambling status here fixes such sinks.
While this synchronous polling is not itself explicitly required for correct modeset sequencing, HDMI 2.0 section 6.1.3.1 does recommend it as the way for the source to verify that the TMDS link is functioning correctly with scrambling enabled.
v3:
- Add explicit HDMI 2.0 section reference in code comment
- Clarify commit message around the observed sink fix
v2:
- Poll TMDS_Scrambler_Status for up to 200 ms instead of using a fixed delay
--- drivers/gpu/drm/i915/display/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/display/intel_hdmi.c | 26 +++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hdmi.h | 2 ++ 3 files changed, 30 insertions(+)
drivers/gpu/drm/i915/display/intel_ddi.c +2 -0
@@ -3502,6 +3502,8 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state, }intel_ddi_buf_enable (encoder, buf_ctl); + +intel_hdmi_poll_for_scrambling_enable (crtc_state, connector); } static void intel_ddi_enable(struct intel_atomic_state *state,
drivers/gpu/drm/i915/display/intel_hdmi.c +26 -0
@@ -2680,6 +2680,32 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_drm_connector_attach_max_bpc_property (&connector->base,8 ,12 ); } +/* +* HDMI 2.0 spec, section 6.1.3.1 (Scrambling Control): after +* enabling Scrambling_Enable and starting scrambled video +* transmission, poll Scrambling_Status for up to 200 ms. +*/ +void +intel_hdmi_poll_for_scrambling_enable (const struct intel_crtc_state *crtc_state, +struct drm_connector *_connector) +{ +struct intel_connector *connector =to_intel_connector (_connector); +struct intel_display *display =to_intel_display (crtc_state); +bool scrambling_enabled = false; +int ret; + +if (!crtc_state->hdmi_scrambling) +return ; + +/* Poll for a max of 200 msec as per HDMI spec */ + ret =poll_timeout_us (scrambling_enabled =drm_scdc_get_scrambling_status (&connector->base), + scrambling_enabled,1000 ,200 *1000 , false); +if (ret) +drm_dbg_kms (display->drm, +"[CONNECTOR:%d:%s] Timed out waiting for scrambling enable\n" , + connector->base.base.id, connector->base.name); +} +/* * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup * @encoder: intel_encoder
drivers/gpu/drm/i915/display/intel_hdmi.h +2 -0
@@ -69,5 +69,7 @@ void hsw_read_infoframe(struct intel_encoder *encoder,const struct intel_crtc_state *crtc_state, unsigned int type, void *frame, ssize_t len); +void intel_hdmi_poll_for_scrambling_enable (const struct intel_crtc_state *crtc_state, +struct drm_connector *_connector);#endif /* __INTEL_HDMI_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 153/396 ksmbd: return success for deferred final close
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit c5db4de8988f1a621556ca5c4537f77b766ca07d ]
ksmbd_close_fd() marks an open file as FP_CLOSED and drops the file table reference. If another in-flight request still holds a reference, the final close is deferred until that request drops its reference.
The function currently returns -EINVAL in that deferred-final-close case because fp is cleared when the reference count does not reach zero. That turns a valid close into STATUS_FILE_CLOSED.
smb2.compound_find.compound_find_close sends QUERY_DIRECTORY and then closes the same directory handle before receiving the find response. The query holds a reference while it builds the response, so close must mark the handle closed and return success even though final teardown is delayed. Track whether the handle was successfully transitioned to FP_CLOSED and return success when only the final close is deferred.
Stable-dep-of: e7188199eff4 ("ksmbd: fix use-after-free in __close_file_table_ids()")
--- fs/smb/server/vfs_cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/smb/server/vfs_cache.c +3 -1
@@ -487,6 +487,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) {struct ksmbd_file *fp;struct ksmbd_file_table *ft; +bool closed = false;if (!has_file_id (id))return 0 ;
@@ -501,6 +502,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) fp =NULL ; else { fp->f_state =FP_CLOSED ; + closed = true;if (!atomic_dec_and_test (&fp->refcount)) fp =NULL ; }
@@ -508,7 +510,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)write_unlock (&ft->lock);if (!fp) -return -EINVAL ; +return closed ?0 : -EINVAL ;__put_fd_final (work, fp);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 154/396 ksmbd: fix use-after-free in __close_file_table_ids()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit e7188199eff46a636f3436356f0aae039be6dd66 ]
A ksmbd_file can remain alive after logical close while another session holds a temporary reference obtained through ksmbd_lookup_fd_inode(). ksmbd_close_fd() currently marks the file closed and drops the idr-owned reference, but leaves the pointer published in the closing session's idr until the final reference is dropped.
If the foreign holder performs the final ksmbd_fd_put(), __put_fd_final() supplies the foreign session's file table to __ksmbd_close_fd(). The object is then freed without being removed from its owner's idr, and the owner session later dereferences the stale pointer during file-table teardown.
Remove the volatile id from the owner's idr while ksmbd_close_fd() still holds that table's lock, and clear volatile_id before dropping the idr-owned reference. A later foreign final put then only performs physical destruction and cannot remove the object from the wrong table.
--- fs/smb/server/vfs_cache.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/vfs_cache.c +2 -0
@@ -502,6 +502,8 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) fp =NULL ; else { fp->f_state =FP_CLOSED ; +idr_remove (ft->idr, id); + fp->volatile_id =KSMBD_NO_FID ; closed = true;if (!atomic_dec_and_test (&fp->refcount)) fp =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 155/396 iomap: add a separate bio_set for iomap_split_ioend
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
[ Upstream commit c679ce3be6cb63763d68ab9b5d9d73ddc0a40762 ]
iomap_split_ioend can split bios that already come from iomap_ioend_bioset and thus deadlock when the bioset is exhausted.
Add a separate bio_set to avoid this deadlock.
Christian Brauner <[email protected]> says:
Mark iomap_ioend_split_bioset static as it is only used in ioend.c, fixing the sparse warning reported by the kernel test robot.
--- fs/iomap/ioend.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
fs/iomap/ioend.c +19 -2
@@ -11,6 +11,7 @@struct bio_set iomap_ioend_bioset;EXPORT_SYMBOL_GPL (iomap_ioend_bioset); +static struct bio_set iomap_ioend_split_bioset;struct iomap_ioend *iomap_init_ioend (struct inode *inode,struct bio *bio,loff_t file_offset,u16 ioend_flags)
@@ -409,7 +410,8 @@ struct iomap_ioend *iomap_split_ioend(struct iomap_ioend *ioend, sector_offset =ALIGN_DOWN (sector_offset <<SECTOR_SHIFT ,i_blocksize (ioend->io_inode)) >>SECTOR_SHIFT ; - split =bio_split (bio, sector_offset,GFP_NOFS , &iomap_ioend_bioset); + split =bio_split (bio, sector_offset,GFP_NOFS , + &iomap_ioend_split_bioset);if (IS_ERR (split))return ERR_CAST (split); split->bi_private = bio->bi_private;
@@ -432,8 +434,23 @@ EXPORT_SYMBOL_GPL(iomap_split_ioend);static int __init iomap_ioend_init (void ) { -return bioset_init (&iomap_ioend_bioset,4 * (PAGE_SIZE /SECTOR_SIZE ), +const unsigned int nr_mempool_entries =4 * (PAGE_SIZE /SECTOR_SIZE ); +int error; + + error =bioset_init (&iomap_ioend_bioset, nr_mempool_entries, offsetof(struct iomap_ioend , io_bio),BIOSET_NEED_BVECS ); +if (error) +return error; + error =bioset_init (&iomap_ioend_split_bioset, nr_mempool_entries, + offsetof(struct iomap_ioend , io_bio), +BIOSET_NEED_BVECS ); +if (error) + goto out_exit_ioend_bioset; +return 0 ; + +out_exit_ioend_bioset: +bioset_exit (&iomap_ioend_bioset); +return error; }fs_initcall (iomap_ioend_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 156/396 mshv: Fix race in mshv_irqfd_deassign
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 0762262ac3e70f65b3bb843fe892f8bac1562d08 ]
mshv_irqfd_deactivate() and the hlist traversal of pt_irqfds_list require pt->pt_irqfds_lock to be held, but mshv_irqfd_deassign() omits it. This races with the EPOLLHUP path in mshv_irqfd_wakeup(), which does take the lock before calling mshv_irqfd_deactivate().
Additionally, mshv_irqfd_deactivate() uses hlist_del() which poisons the node pointers rather than resetting them. Since mshv_irqfd_is_active() relies on hlist_unhashed() (checks pprev == NULL), a poisoned node still appears active. If a concurrent path calls mshv_irqfd_deactivate() again on the same irqfd, the guard fails to prevent a double hlist_del() on poisoned pointers.
Fix both issues:
- Add the missing spin_lock_irq/spin_unlock_irq around the list traversal in mshv_irqfd_deassign(), matching mshv_irqfd_release().
- Use hlist_del_init() instead of hlist_del() so the node is properly marked as unhashed after removal, making the is_active guard reliable.
--- drivers/hv/mshv_eventfd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hv/mshv_eventfd.c +3 -2
@@ -280,7 +280,7 @@ static void mshv_irqfd_deactivate(struct mshv_irqfd *irqfd)if (!mshv_irqfd_is_active (irqfd))return ; -hlist_del (&irqfd->irqfd_hnode); +hlist_del_init (&irqfd->irqfd_hnode);queue_work (irqfd_cleanup_wq, &irqfd->irqfd_shutdown); }
@@ -535,13 +535,14 @@ static int mshv_irqfd_deassign(struct mshv_partition *pt,if (IS_ERR (eventfd))return PTR_ERR (eventfd); +spin_lock_irq (&pt->pt_irqfds_lock);hlist_for_each_entry_safe (irqfd, n, &pt->pt_irqfds_list, irqfd_hnode) {if (irqfd->irqfd_eventfd_ctx == eventfd && irqfd->irqfd_irqnum == args->gsi) -mshv_irqfd_deactivate (irqfd); } +spin_unlock_irq (&pt->pt_irqfds_lock);eventfd_ctx_put (eventfd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 157/396 mshv: adjust interrupt control structure for ARM64
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinank Jain <[email protected]>
[ Upstream commit 9d70ef7a18e0ec1653ac63020a13a5d4dda7cc0d ]
Interrupt control structure (union hv_interupt_control) has different fields when it comes to x86 vs ARM64. Bring in the correct structure from HyperV header files and adjust the existing interrupt routing code accordingly.
Stable-dep-of: 0289a67cd70b ("mshv: Fix level-triggered check on uninitialized data")
--- drivers/hv/mshv_eventfd.c | 6 ++++++ drivers/hv/mshv_irq.c | 4 ++++ drivers/hv/mshv_root_hv_call.c | 6 ++++++ include/hyperv/hvhdk.h | 6 ++++++ 4 files changed, 22 insertions(+)
drivers/hv/mshv_eventfd.c +6 -0
@@ -164,8 +164,10 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)if (hv_scheduler_type !=HV_SCHEDULER_TYPE_ROOT )return -EOPNOTSUPP ; +#if IS_ENABLED (CONFIG_X86 )if (irq->lapic_control.logical_dest_mode)return -EOPNOTSUPP ; +#endif vp = partition->pt_vp_array[irq->lapic_apic_id];
@@ -197,8 +199,10 @@ static void mshv_assert_irq_slow(struct mshv_irqfd *irqfd)unsigned int seq;int idx; +#if IS_ENABLED (CONFIG_X86 )WARN_ON (irqfd->irqfd_resampler && !irq->lapic_control.level_triggered); +#endif idx =srcu_read_lock (&partition->pt_irq_srcu);if (irqfd->irqfd_girq_ent.guest_irq_num) {
@@ -469,6 +473,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,init_poll_funcptr (&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);spin_lock_irq (&pt->pt_irqfds_lock); +#if IS_ENABLED (CONFIG_X86 )if (args->flags &BIT (MSHV_IRQFD_BIT_RESAMPLE ) && !irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {/*
@@ -479,6 +484,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt, ret = -EINVAL ; goto fail; } +#endif ret =0 ;hlist_for_each_entry (tmp, &pt->pt_irqfds_list, irqfd_hnode) {if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx)
drivers/hv/mshv_irq.c +4 -0
@@ -119,6 +119,10 @@ void mshv_copy_girq_info(struct mshv_guest_irq_ent *ent, lirq->lapic_vector = ent->girq_irq_data &0xFF ; lirq->lapic_apic_id = (ent->girq_addr_lo >>12 ) &0xFF ; lirq->lapic_control.interrupt_type = (ent->girq_irq_data &0x700 ) >>8 ; +#if IS_ENABLED (CONFIG_X86 ) lirq->lapic_control.level_triggered = (ent->girq_irq_data >>15 ) &0x1 ; lirq->lapic_control.logical_dest_mode = (ent->girq_addr_lo >>2 ) &0x1 ; +#elif IS_ENABLED (CONFIG_ARM64 ) + lirq->lapic_control.asserted =1 ; +#endif }
drivers/hv/mshv_root_hv_call.c +6 -0
@@ -388,7 +388,13 @@ int hv_call_assert_virtual_interrupt(u64 partition_id, u32 vector,memset (input,0 ,sizeof (*input)); input->partition_id = partition_id; input->vector = vector; +/* +* NOTE: dest_addr only needs to be provided while asserting an +* interrupt on x86 platform +*/ +#if IS_ENABLED (CONFIG_X86 ) input->dest_addr = dest_addr; +#endif input->control = control; status =hv_do_hypercall (HVCALL_ASSERT_VIRTUAL_INTERRUPT , input,NULL );local_irq_restore (flags);
include/hyperv/hvhdk.h +6 -0
@@ -540,9 +540,15 @@ union hv_interrupt_control {u64 as_uint64;struct {u32 interrupt_type;/* enum hv_interrupt_type */ +#if IS_ENABLED (CONFIG_X86 )u32 level_triggered :1 ;u32 logical_dest_mode :1 ;u32 rsvd :30 ; +#elif IS_ENABLED (CONFIG_ARM64 ) +u32 rsvd1 :2 ; +u32 asserted :1 ; +u32 rsvd2 :29 ; +#endif } __packed; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 158/396 mshv: Fix level-triggered check on uninitialized data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 0289a67cd70bf9d3807e289f4efd643e16a6c6b4 ]
In mshv_irqfd_assign(), the level-triggered validation for resample irqfds checks irqfd_lapic_irq.lapic_control.level_triggered before mshv_irqfd_update() has populated the field. Since the irqfd struct is zero-allocated, level_triggered is always 0 at that point, causing the check to always reject resample irqfds with -EINVAL. This makes level-triggered interrupt resampling — used to avoid interrupt storms with assigned devices — completely non-functional.
Move the check after the mshv_irqfd_update() call, which resolves the IRQ routing entry and populates irqfd_lapic_irq with the actual trigger mode.
--- drivers/hv/mshv_eventfd.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)
drivers/hv/mshv_eventfd.c +14 -11
@@ -473,6 +473,19 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,init_poll_funcptr (&irqfd->irqfd_polltbl, mshv_irqfd_queue_proc);spin_lock_irq (&pt->pt_irqfds_lock); + ret =0 ; +hlist_for_each_entry (tmp, &pt->pt_irqfds_list, irqfd_hnode) { +if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx) +continue ; +/* This fd is used for another irq already. */ + ret = -EBUSY ; +spin_unlock_irq (&pt->pt_irqfds_lock); + goto fail; + } + + idx =srcu_read_lock (&pt->pt_irq_srcu); +mshv_irqfd_update (pt, irqfd); +#if IS_ENABLED (CONFIG_X86 )if (args->flags &BIT (MSHV_IRQFD_BIT_RESAMPLE ) && !irqfd->irqfd_lapic_irq.lapic_control.level_triggered) {
@@ -481,22 +494,12 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,* Otherwise return with failure */ spin_unlock_irq (&pt->pt_irqfds_lock); +srcu_read_unlock (&pt->pt_irq_srcu, idx); ret = -EINVAL ; goto fail; }#endif - ret =0 ; -hlist_for_each_entry (tmp, &pt->pt_irqfds_list, irqfd_hnode) { -if (irqfd->irqfd_eventfd_ctx != tmp->irqfd_eventfd_ctx) -continue ; -/* This fd is used for another irq already. */ - ret = -EBUSY ; -spin_unlock_irq (&pt->pt_irqfds_lock); - goto fail; - } - idx =srcu_read_lock (&pt->pt_irq_srcu); -mshv_irqfd_update (pt, irqfd);hlist_add_head (&irqfd->irqfd_hnode, &pt->pt_irqfds_list);spin_unlock_irq (&pt->pt_irqfds_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 159/396 mshv: Order pt_vp_array publish against irqfd assertion path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit b098dc869219c15dc49bf9cf63fb5fc1481d3373 ]
mshv_partition_ioctl_create_vp() initialises a VP struct (allocations, mutex_init, init_waitqueue_head, page mappings) and then publishes the pointer into partition->pt_vp_array. Several ISR paths read this array
locklessly: the intercept ISR, the two scheduler ISRs, and mshv_try_assert_irq_fast() on the irqfd fast path.
Of these, only mshv_try_assert_irq_fast() can structurally race the publish. It runs from an eventfd waker without holding pt_mutex, and MSHV_IRQFD does not require the target lapic_apic_id (== vp_index) to refer to an existing VP at registration time. A user can therefore register an irqfd targeting a yet-to-be-created VP, then trigger mshv_try_assert_irq_fast() concurrently with MSHV_CREATE_VP for the same index. On weakly-ordered architectures the reader can observe a non-NULL pointer in pt_vp_array before the initialising stores to the VP struct become visible, leading to use of partially-initialised fields (e.g. vp_register_page).
The other ISR readers cannot reach this race: the hypervisor will not generate intercept or scheduler messages for a VP that has never been told to run, and the user can only call MSHV_RUN_VP on the VP fd returned by MSHV_CREATE_VP, which by construction is returned after the publish. Leave those readers as plain loads.
Use smp_store_release() in mshv_partition_ioctl_create_vp() to publish the pointer, and pair it with smp_load_acquire() in mshv_try_assert_irq_fast(). On x86 these compile to plain accesses under TSO; on ARM64 they emit one-instruction acquire/release barriers, acceptable on this fast path.
The destroy-side path (destroy_partition() clearing pt_vp_array[i] to NULL after kfree(vp)) has a separate ordering and lifetime concern that is out of scope here.
--- drivers/hv/mshv_eventfd.c | 9 ++++++++- drivers/hv/mshv_root_main.c | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-)
drivers/hv/mshv_eventfd.c +8 -1
@@ -169,7 +169,14 @@ static int mshv_try_assert_irq_fast(struct mshv_irqfd *irqfd)return -EOPNOTSUPP ;#endif - vp = partition->pt_vp_array[irq->lapic_apic_id]; +/* +* Pairs with smp_store_release() in mshv_partition_ioctl_create_vp(). +* MSHV_IRQFD does not require the target lapic_apic_id to refer to an +* existing VP, so this read can race a concurrent VP creation; the +* acquire ensures that a non-NULL pointer implies the VP's +* initialising stores are visible. +*/ + vp =smp_load_acquire (&partition->pt_vp_array[irq->lapic_apic_id]);if (!vp->vp_register_page)return -EOPNOTSUPP ;
drivers/hv/mshv_root_main.c +7 -1
@@ -979,7 +979,13 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,/* already exclusive with the partition mutex for all ioctls */ partition->pt_vp_count++; - partition->pt_vp_array[args.vp_index] = vp; +/* +* Pairs with smp_load_acquire() in mshv_try_assert_irq_fast(), which +* can run concurrently from an irqfd waker without holding pt_mutex. +* The release ensures the VP's initialising stores are visible to any +* reader that observes a non-NULL pointer in pt_vp_array. +*/ +smp_store_release (&partition->pt_vp_array[args.vp_index], vp);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 160/396 iommufd/viommu: Release the igroup lock on the vdevice_size error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 339bd11591593ab7ce88136ab7fd01ef3813b724 upstream.
iommufd_vdevice_alloc_ioctl() takes idev->igroup->lock, then validates the driver's vdevice_size against the core structure size with a WARN_ON_ONCE. On failure that guard jumps to out_put_idev, below out_unlock_igroup, so it skips the mutex_unlock(), leaving the igroup lock held and deadlocking the next vDEVICE operation on that group.
Jump to out_unlock_igroup instead.
--- drivers/iommu/iommufd/viommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/viommu.c +1 -1
@@ -189,7 +189,7 @@ int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd)if (WARN_ON_ONCE (viommu->ops->vdevice_size < vdev_size || !viommu->ops->vdevice_init)) { rc = -EOPNOTSUPP ; - goto out_put_idev; + goto out_unlock_igroup; } vdev_size = viommu->ops->vdevice_size; }
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 161/396 iommufd/viommu: Publish a vDEVICE only after vdevice_init() succeeds
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 9be311cfbe6154da146a7408e0d5e518a9321ed3 upstream.
iommufd_vdevice_alloc_ioctl() adds the vDEVICE to the viommu->vdevs xarray with xa_cmpxchg() before the driver's vdevice_init() op runs. That op is where a driver validates the device and may reject it, but the xarray entry is already live by then: a concurrent IOMMU_HWPT_INVALIDATE can look it up with iommufd_viommu_find_dev() and run the driver invalidation path against a device that vdevice_init() would have refused.
Reserve the index with xa_insert(): it stores a zero entry that reads back as NULL, and returns -EBUSY on a duplicate virt_id. Run vdevice_init() and store the vDEVICE pointer only once it succeeds. A failed vdevice_init() releases the reservation, so lookups observe the vDEVICE only after it is fully initialized and accepted.
--- drivers/iommu/iommufd/viommu.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
drivers/iommu/iommufd/viommu.c +15 -5
@@ -143,7 +143,7 @@ void iommufd_vdevice_destroy(struct iommufd_object *obj)int iommufd_vdevice_alloc_ioctl (struct iommufd_ucmd *ucmd) {struct iommu_vdevice_alloc *cmd = ucmd->cmd; -struct iommufd_vdevice *vdev, *curr; +struct iommufd_vdevice *vdev;size_t vdev_size =sizeof (*vdev);struct iommufd_viommu *viommu;struct iommufd_device *idev;
@@ -218,18 +218,28 @@ int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd)*/ idev->vdev = vdev; - curr =xa_cmpxchg (&viommu->vdevs, virt_id,NULL , vdev,GFP_KERNEL ); -if (curr) { - rc =xa_err (curr) ?: -EEXIST ; +/* +* Reserve the slot with a zero entry (reads back as NULL) until the +* vdevice_init() op accepts the vDEVICE. Only the xa_* helpers hide a +* reserved entry, so never use a raw xas_* iterator on this xarray. +*/ + rc =xa_insert (&viommu->vdevs, virt_id,NULL ,GFP_KERNEL ); +if (rc) { +if (rc == -EBUSY ) + rc = -EEXIST ; goto out_abort; }if (viommu->ops && viommu->ops->vdevice_init) { rc = viommu->ops->vdevice_init (vdev); -if (rc) +if (rc) { +xa_release (&viommu->vdevs, virt_id); goto out_abort; + } } +xa_store (&viommu->vdevs, virt_id, vdev,GFP_KERNEL ); + cmd->out_vdevice_id = vdev->obj.id; rc =iommufd_ucmd_respond (ucmd,sizeof (*cmd));if (rc)
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 162/396 iommufd: Fix wrong hwpt passed to iommufd_auto_response_faults on replace
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit ba5c0f28a26e7d9be1e0997f8920dd638e2782fd upstream.
iommufd_hwpt_replace_device() calls:
iommufd_auto_response_faults(hwpt, old_handle);
passing the *new* hwpt together with the handle of the device's *old* domain. This should be a parameter mismatch:
1. Semantically, iommufd_auto_response_faults(x, handle) scans x->fault's deliver list and response xarray for groups matching "handle". A group is queued under the hwpt that was attached at fault-delivery time. old_handle is fetched *before* the domain switch, so its group lives on old->fault, not on the new hwpt->fault.
2. Historically, the first argument was "old". The routine was introduced by commit b7d8833677ba ("iommufd: Fault-capable hwpt attach/detach/replace") as __fault_domain_replace_dev() in fault.c, correctly calling iommufd_auto_response_faults(old, curr). Commit fb21b1568ada ("iommufd: Make attach_handle generic than fault specific") moved this into iommufd_hwpt_replace_device() in device.c and swapped it to "hwpt". This should be a refactor regression, not an intentional change.
Fix this by passing "old" instead.
--- drivers/iommu/iommufd/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/device.c +1 -1
@@ -589,7 +589,7 @@ static int iommufd_hwpt_replace_device(sif (rc) goto out_free_handle; -iommufd_auto_response_faults (hwpt, old_handle); +iommufd_auto_response_faults (old, old_handle);kfree (old_handle);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 163/396 iommu/iommufd: Fix IOPF group ownership UAF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <[email protected]>
commit 738e6f32e61d80b554e37015ecb7bc620b88001c upstream.
iopf_group_alloc() links each last-page IOPF group into the generic IOPF pending list before invoking the domain fault handler. iommufd_fault_iopf_handler() also queued an accepted group in the IOMMUFD deliver list without removing it from the generic pending list.
When detach or HWPT replacement drops the device's IOPF reference count to zero, an IOMMU driver may call iopf_queue_remove_device(). That function responds to and frees groups through the generic pending list without removing the same groups from IOMMUFD's deliver list or response xarray. A later read, response, or cleanup can then access the freed group and cause a UAF.
Fix this by dequeuing an accepted group from the generic pending list before IOMMUFD queues it for userspace response.
Make iopf_group_response() send a response regardless of pending-list membership, so the dequeued group can still be completed by IOMMUFD.
--- drivers/iommu/io-pgfault.c | 24 +++++++++++++++++++----- drivers/iommu/iommufd/eventq.c | 2 ++ include/linux/iommu.h | 5 +++++ 3 files changed, 26 insertions(+), 5 deletions(-)
drivers/iommu/io-pgfault.c +19 -5
@@ -332,17 +332,31 @@ void iopf_group_response(struct iopf_gro .code = status, }; -/* Only send response if there is a fault report pending */ mutex_lock (&fault_param->lock); -if (!list_empty (&group->pending_node)) { - ops->page_response (dev, &group->last_fault, &resp); -list_del_init (&group->pending_node); - } + ops->page_response (dev, &group->last_fault, &resp); +list_del_init (&group->pending_node);mutex_unlock (&fault_param->lock); }EXPORT_SYMBOL_GPL (iopf_group_response);/** +* iopf_group_dequeue - Dequeue a page fault group from the pending list +* @group: the group to dequeue +* +* The fault handler is responsible for responding to the group after +* this function returns. +*/ +void iopf_group_dequeue (struct iopf_group *group) +{ +struct iommu_fault_param *fault_param = group->fault_param; + +mutex_lock (&fault_param->lock); +list_del_init (&group->pending_node); +mutex_unlock (&fault_param->lock); +} +EXPORT_SYMBOL_GPL (iopf_group_dequeue); + +/** * iopf_queue_discard_partial - Remove all pending partial fault * @queue: the queue whose partial faults need to be discarded *
drivers/iommu/iommufd/eventq.c +2 -0
@@ -484,6 +484,8 @@ int iommufd_fault_iopf_handler(struct io hwpt = group->attach_handle->domain->iommufd_hwpt; fault = hwpt->fault; +iopf_group_dequeue (group); +spin_lock (&fault->common.lock);list_add_tail (&group->node, &fault->common.deliver);spin_unlock (&fault->common.lock);
include/linux/iommu.h +5 -0
@@ -1657,6 +1657,7 @@ void iopf_free_group(struct iopf_group *int iommu_report_device_fault (struct device *dev,struct iopf_fault *evt);void iopf_group_response (struct iopf_group *group,enum iommu_page_response_code status); +void iopf_group_dequeue (struct iopf_group *group);#else static inline int iopf_queue_add_device (struct iopf_queue *queue,struct device *dev)
@@ -1702,5 +1703,9 @@ static inline void iopf_group_response(s enum iommu_page_response_code status) { } + +static inline void iopf_group_dequeue (struct iopf_group *group) +{ +}#endif /* CONFIG_IOMMU_IOPF */ #endif /* __LINUX_IOMMU_H */
Greg Kroah-Hartman
maintainerPATCH 164/396 pinctrl: microchip-sgpio: add missing select REGMAP_MMIO
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Boortz <[email protected]>
commit 25cb6e9a13123d1039cdc75b446ac52e1ebdc26d upstream.
The driver calls ocelot_regmap_from_resource() via <linux/mfd/ocelot.h>, which internally uses devm_regmap_init_mmio() and requires REGMAP_MMIO. The Kconfig entry does not select REGMAP_MMIO, causing a build failure when no other driver in the config happens to pull in REGMAP_MMIO:
include/linux/mfd/ocelot.h:34:24: error: implicit declaration of function 'devm_regmap_init_mmio'
Found by randconfig testing on arm64; tinyconfig reproducer below.
--- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/pinctrl/Kconfig +1 -0
@@ -238,6 +238,7 @@ config PINCTRL_EQUILIBRIUM select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS + select REGMAP_MMIO help Equilibrium driver is a pinctrl and GPIO driver for Intel Lightning Mountain network processor SoC that supports both the GPIO and pin
Greg Kroah-Hartman
maintainerPATCH 165/396 pinctrl: devicetree: dont free uninitialized dev_name on error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 015b5bcbcb622b32317642be91a7f79aa5413649 upstream.
dt_remember_or_free_map() duplicates dev_name for each map entry. If kstrdup_const() fails, dt_free_map() frees dev_name in all num_maps entries, including entries that have not been initialized.
Some pinctrl drivers, including pinctrl-imx, allocate the map with kmalloc() and leave dev_name for the core to initialize. The untouched entries therefore contain uninitialized data which is passed to kfree_const().
Reproduced on qemu's mcimx6ul-evk (pinctrl-imx) with failslab injection while binding the pinctrl-consuming device, under KASAN:
BUG: KASAN: double-free in dt_free_map+0x34/0xa4 Free of addr c425a900 by task init/1 kfree from dt_free_map+0x34/0xa4 dt_free_map from dt_remember_or_free_map+0x184/0x198 dt_remember_or_free_map from pinctrl_dt_to_map+0x33c/0x4c8 pinctrl_dt_to_map from create_pinctrl+0x9c/0x5c0
Initialize all dev_name fields to NULL before duplicating the device name, making the full-map cleanup safe after a partial failure.
--- drivers/pinctrl/devicetree.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/pinctrl/devicetree.c +4 -0
@@ -69,6 +69,10 @@ static int dt_remember_or_free_map(strucint i;struct pinctrl_dt_map *dt_map; +/* Initialize dev_name before any allocation can fail */ +for (i =0 ; i < num_maps; i++) + map[i].dev_name =NULL ; +/* Initialize common mapping table entry fields */ for (i =0 ; i < num_maps; i++) {const char *devname;
Greg Kroah-Hartman
maintainerPATCH 166/396 erofs: cap LZMA stream pool size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit c9b47e6b23114e939b17f818471c7a46e59006e7 upstream.
fs/erofs/decompressor_lzma.c sizes the module-global MicroLZMA stream pool from num_possible_cpus() when the lzma_streams module parameter is unset, then z_erofs_load_lzma_config() preallocates one image-supplied dictionary per stream, accepting dictionaries up to 8 MiB. On high-CPU systems, a small EROFS image can pin hundreds of MiB of vmalloc-backed decoder state until the erofs module is unloaded.
Impact: An EROFS image mounted by the system can pin up to 8 MiB of vmalloc memory per LZMA stream, either as intended or unexpectedly.
Bound the default stream count by a new CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS option, default 16, so the worst-case default preallocation is 128 MiB if the number of CPUs is no less than 16 while preserving the existing per-image dictionary limit. An explicit lzma_streams module parameter is still honoured as-is, so administrators who deliberately size the pool are not affected.
--- fs/erofs/Kconfig | 14 ++++++++++++++ fs/erofs/decompressor_lzma.c | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-)
fs/erofs/Kconfig +14 -0
@@ -120,6 +120,20 @@ config EROFS_FS_ZIP_LZMA If unsure, say N. +config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS + int "EROFS LZMA default maximum decompression streams" + depends on EROFS_FS_ZIP_LZMA + range 1 NR_CPUS + default 16 + help + By default EROFS allocates one LZMA decompression stream per CPU. + Each stream can hold a dictionary of up to 8 MiB taken from the + mounted image, so on systems with many CPUs this can reserve a lot + of memory. This caps the default; the lzma_streams module parameter + still overrides it. + + If unsure, keep the default of 16. + config EROFS_FS_ZIP_DEFLATE bool "EROFS DEFLATE compressed data support" depends on EROFS_FS_ZIP
fs/erofs/decompressor_lzma.c +2 -1
@@ -51,7 +51,8 @@ static int __init z_erofs_lzma_init(void/* by default, use # of possible CPUs instead */ if (!z_erofs_lzma_nstrms) - z_erofs_lzma_nstrms =num_possible_cpus (); + z_erofs_lzma_nstrms = min_t(unsigned int, num_possible_cpus(), +CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS );for (i =0 ; i < z_erofs_lzma_nstrms; ++i) {struct z_erofs_lzma *strm =kzalloc (sizeof (*strm),GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 167/396 pinctrl: bm1880: add missing select GENERIC_PINCONF
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Boortz <[email protected]>
commit dad6e107b3cd9d20514e7799b7ad8674f81e3f30 upstream.
drivers/pinctrl/pinctrl-bm1880.c initialises its pinconf_ops with .is_generic = true, but that field is only present when CONFIG_GENERIC_PINCONF is enabled (guarded by #ifdef in pinconf.h). The Kconfig entry for PINCTRL_BM1880 never selects GENERIC_PINCONF, so any config that enables CONFIG_PINCTRL_BM1880=y without CONFIG_GENERIC_PINCONF=y fails to compile:
drivers/pinctrl/pinctrl-bm1880.c:1288:10: error: 'const struct pinconf_ops' has no member named 'is_generic'
Found by randconfig testing on arm64; tinyconfig reproducer below. Add the missing select to fix the build.
--- drivers/pinctrl/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/pinctrl/Kconfig +1 -0
@@ -162,6 +162,7 @@ config PINCTRL_BM1880 depends on OF && (ARCH_BITMAIN || COMPILE_TEST) default ARCH_BITMAIN select PINMUX + select GENERIC_PINCONF help Pinctrl driver for Bitmain BM1880 SoC.
Greg Kroah-Hartman
maintainerPATCH 168/396 fortify: Disable -Wstringop-overread in tests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit c1f3e770eec26d6f96dd6d2ea30555ba7c09a244 upstream.
clang recently added support for -Wstringop-overread [1], which is on by default like -Wfortify-source. This breaks the usage of -Werror in the fortify tests, resulting in the following false positive warnings in the kernel build:
warning: unsafe memcmp() usage lacked '__read_overflow2' warning in lib/test_fortify/read_overflow2-memcmp.c
warning: unsafe memcmp() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memcmp.c
warning: unsafe memchr() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memchr.c
Examining the fortify test logs shows a warning like the following in each of the failed logs:
In file included from lib/test_fortify/read_overflow2-memcmp.c:5:
lib/test_fortify/test_fortify.h:34:2: error: 'memcmp' reading 17 bytes from a region of size 16 [-Werror,-Wstringop-overread]
34 | TEST;
| ^
lib/test_fortify/read_overflow2-memcmp.c:3:2: note: expanded from macro 'TEST'
3 | memcmp(large, small, sizeof(small) + 1)
| ^1 error generated.
Disable -Wstringop-overread for the fortify tests, as it defeats the purpose of testing the Linux specific implementation of fortify, like -Wfortify-source.
--- lib/test_fortify/Makefile | 1 + 1 file changed, 1 insertion(+)
lib/test_fortify/Makefile +1 -0
@@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 ccflags-y := $(call cc-disable-warning,fortify-source) +ccflags-y += $(call cc-disable-warning,stringop-overread) quiet_cmd_test_fortify = TEST $@ cmd_test_fortify = $(CONFIG_SHELL) $(src)/test_fortify.sh \
Greg Kroah-Hartman
maintainerPATCH 169/396 mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kefeng Wang <[email protected]>
commit 63867c82d0c0c2d182016a32b1cc0103116b0ea5 upstream.
pte_pfn() and pte_dirty() have undefined behaviour when called on a non-present PTE. In migrate_vma_collect_pmd(), these functions may be invoked on non-present entries (e.g., device-private entries), leading to potential crashes from pte_pfn() or incorrect dirty folio accounting from pte_dirty(). Fix both by guarding with pte_present() checks.
--- mm/migrate_device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
mm/migrate_device.c +3 -2
@@ -209,7 +209,8 @@ again:bool anon_exclusive;pte_t swp_pte; -flush_cache_page (vma, addr,pte_pfn (pte)); +if (pte_present (pte)) +flush_cache_page (vma, addr,pte_pfn (pte)); anon_exclusive =folio_test_anon (folio) &&PageAnonExclusive (page);if (anon_exclusive) {
@@ -230,7 +231,7 @@ again: migrate->cpages++;/* Set the dirty flag on the folio now the pte is gone. */ -if (pte_dirty (pte)) +if (pte_present (pte) &&pte_dirty (pte))folio_mark_dirty (folio);/* Setup special migration page table entry */
Greg Kroah-Hartman
maintainerPATCH 170/396 mm/util: dont read __page_2 for order-1 folios in snapshot_page()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
commit 7441d6348c70738e9ed307510db171c7a9b3f4bf upstream.
snapshot_page() currently reads __page_2 after checking nr_pages > 1, but it should only do so when nr_pages > 2.
If an order-1 folio is allocated at the end of a vmemmap section, __page_2 will not exist and reading it will cause a fault.
During DLPAR memory remove on a 22 TB ppc64le LPAR, snapshot_page() oopsed on the page isolation path while reading an order-1 folio's __page_2 from an adjacent absent section (unmapped vmemmap).
Fix this to avoid reading memmap that doesn't exist (e.g., a vmemmap hole).
--- mm/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/util.c +1 -1
@@ -1263,7 +1263,7 @@ again:if (ps->idx <MAX_FOLIO_NR_PAGES ) {memcpy (&ps->folio_snapshot, foliop,2 *sizeof (struct page )); nr_pages =folio_nr_pages (&ps->folio_snapshot); -if (nr_pages >1 ) +if (nr_pages >2 )memcpy (&ps->folio_snapshot.__page_2, &foliop->__page_2,sizeof (struct page ));set_ps_flags (ps, foliop, page);
Greg Kroah-Hartman
maintainerPATCH 171/396 selftest: fix headers in fclog.c
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jori Koolstra <[email protected]>
commit e3a0127eee04db8769e53c8102c4e76aa49be8c3 upstream.
fclog.c does not compile because it is missing fcntl.h, needed for O_RDONLY etc.
There are also some redundant includes that are also in kselftest_harness.h.
--- tools/testing/selftests/filesystems/fclog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
tools/testing/selftests/filesystems/fclog.c +1 -3
@@ -6,10 +6,8 @@#include <assert.h> #include <errno.h> +#include <fcntl.h> #include <sched.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <unistd.h> #include <sys/mount.h>
Greg Kroah-Hartman
maintainerPATCH 172/396 fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau (Meta) <[email protected]>
commit 40de8160ca7f67d14619ee0351ce5d68fc4a237a upstream.
PAGEMAP_SCAN reports an unpopulated PTE in a uffd-wp VMA as written, but a range with no page table at all -- a PMD hole -- is skipped:pagemap_scan_pte_hole() tests p->cur_vma_category, which never carries PAGE_IS_WRITTEN, so the hole is neither reported nor (under PM_SCAN_WP_MATCHING) armed.
In a uffd-wp VMA, WP_UNPOPULATED installs uffd-wp markers when protecting a range, allocating page tables as needed, so an unpopulated slot is treated as written -- see the pte_none() handling in pagemap_page_category(). A missing marker therefore means the range was zapped, e.g. via MADV_DONTNEED. This applies to anon and shmem VMAs.
An anonymous THP is write-protected in place as a huge PMD, so a full-PMD MADV_DONTNEED clears it to pmd_none -- a hole with no page table -- and pagemap_scan_pte_hole() misses it. For a MAP_PRIVATE|MAP_ANON mapping MADV_DONTNEED has fill-with-zeros semantics, so a write-tracking checkpoint/migration tool (e.g. CRIU) treats the range as unchanged and keeps its previous contents; after restore or live migration the process reads stale data instead of zeroes -- data corruption.
Report a hole in a non-hugetlb uffd-wp VMA as written, matching the pte_none handling in pagemap_page_category(); the existing PM_SCAN_WP_MATCHING path then arms it via uffd_wp_range().
hugetlb is excluded: pagemap_hugetlb_category() reports an empty hugetlb entry (huge_pte_none) as not-written, unlike pagemap_page_category(), which reports pte_none as written. pagemap_scan_pte_hole() fires for a hugetlb slot only when it has no page table; keeping that not-written matches how an allocated-but-empty hugetlb entry reads, so the hole and the empty-entry cases agree within the VMA.
--- fs/proc/task_mmu.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
fs/proc/task_mmu.c +18 -2
@@ -2918,12 +2918,28 @@ static int pagemap_scan_pte_hole(unsigne {struct pagemap_scan_private *p = walk->private;struct vm_area_struct *vma = walk->vma; +unsigned long categories;int ret, err; -if (!vma || !pagemap_scan_is_interesting_page (p->cur_vma_category, p)) +if (!vma)return 0 ; - ret =pagemap_scan_output (p->cur_vma_category, p, addr, &end); +/* +* In a uffd-wp VMA an unpopulated range is treated as written: +* uffd-wp registration populates page tables and installs markers +* with WP_UNPOPULATED, so a missing marker means the range was +* zapped. See the pte_none() handling in pagemap_page_category(). +* +* hugetlb differs, see pagemap_hugetlb_category(). +*/ + categories = p->cur_vma_category; +if (userfaultfd_wp (vma) && !is_vm_hugetlb_page (vma)) + categories |=PAGE_IS_WRITTEN ; + +if (!pagemap_scan_is_interesting_page (categories, p)) +return 0 ; + + ret =pagemap_scan_output (categories, p, addr, &end);if (addr == end)return ret;
Greg Kroah-Hartman
maintainerPATCH 173/396 mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zi Yan <[email protected]>
commit 89b1b79c308818a715e75f28744b70d8940a07c9 upstream.
In pcpu_create_chunk(), nr_pages is the total contiguous backing allocation, i.e., nr_units * pcpu_unit_pages, but pcpu_chunk_populated() uses it to set chunk->populated, whose size is pcpu_unit_pages, bitmap. Since bit N in chunk->populated means page offset N inside every unit is backed. When nr_units > 1, the function writes beyond chunk->populated. Fix it by using chunk->nr_pages.
It also fixes the global pcpu_nr_empty_pop_pages accounting, since pcpu_balance_free() only iterates up to chunk->nr_pages.
Commit a63d4ac4ab609 ("percpu: make percpu-km set chunk->populated bitmap properly") introduced the bitmap overflow issue. Later, commit b539b87fed37f ("percpu: implmeent pcpu_nr_empty_pop_pages and chunk->nr_populated") added pcpu_nr_empty_pop_pages and caused the accounting issue.
--- mm/percpu-km.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/percpu-km.c +1 -1
@@ -75,7 +75,7 @@ static struct pcpu_chunk *pcpu_create_ch chunk->base_addr =page_address (pages);spin_lock_irqsave (&pcpu_lock, flags); -pcpu_chunk_populated (chunk,0 , nr_pages); +pcpu_chunk_populated (chunk,0 , chunk->nr_pages);spin_unlock_irqrestore (&pcpu_lock, flags);pcpu_stats_chunk_alloc ();
Greg Kroah-Hartman
maintainerPATCH 174/396 mm/hugetlb: fix list corruption in allocate_file_region_entries()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiangfeng Cai <[email protected]>
commit dd9623f58ec702a07b2d67179d6fcea79c52231a upstream.
allocate_file_region_entries() tops up resv->region_cache with freshly allocated file_region descriptors. The allocation uses GFP_KERNEL, so resv->lock is dropped around it: the new entries are gathered on a stack-local list head, allocated_regions, and spliced into resv->region_cache once the lock is re-acquired.
The splice used list_splice(), which moves the entries but does not re-initialize the source head, so allocated_regions is left pointing at an entry that now lives on resv->region_cache. The top-up runs in a while loop that re-checks the cache deficit after re-acquiring the lock. For a shared mapping the resv_map is shared by every mapper of the hugetlbfs inode, so a concurrent region_chg()/region_add()/region_del() on the same resv_map can consume cache entries during the unlocked window and force a second iteration. That iteration calls list_add() on the stale head and corrupts the list; with CONFIG_DEBUG_LIST the __list_add_valid() check trips:
list_add corruption. next->prev should be prev (ffffc900011ff7f8), but was ffff88814c281460. (next=ffff88814c545640). kernel BUG at lib/list_debug.c:31!
allocate_file_region_entries+0x191/0x420 region_chg+0x267/0x300 hugetlb_reserve_pages+0x387/0xc80 hugetlbfs_file_mmap+0x2ce/0x3f0 mmap_region+0x1348/0x1a80 do_mmap+0x85e/0xb90 vm_mmap_pgoff+0x18c/0x330 ksys_mmap_pgoff+0x2a1/0x3e0 do_syscall_64+0xd7/0x420
Without CONFIG_DEBUG_LIST the bad list_add() silently links a kernel-stack address into resv->region_cache, leading to later use-after-free.
This was observed as a real host panic on a dense KVM host where a QEMU guest-RAM hugetlbfs file was mapped MAP_SHARED by both QEMU and a separate SPDK/DPDK vhost-user target, generating concurrent region_* traffic on one shared resv_map.
Use list_splice_init() so the source head is re-initialized empty after each splice, making the retry loop safe.
--- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/hugetlb.c +1 -1
@@ -705,7 +705,7 @@ static int allocate_file_region_entries(spin_lock (&resv->lock); -list_splice (&allocated_regions, &resv->region_cache); +list_splice_init (&allocated_regions, &resv->region_cache); resv->region_cache_count += to_allocate; }
Greg Kroah-Hartman
maintainerPATCH 175/396 mm/vmstat: fold stranded per-cpu node stats when a node comes online
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
commit ea3034b2b00fa50c8d2518d0804c9d427bbafa86 upstream.
A per-node vmstat counter is pgdat->vm_stat[] plus per-cpu deltas. A balanced counter can sit split as global=+N / per-cpu=-N.
The folds reconciling the split only walk online nodes, so when try_offline_node() marks a node offline the per-cpu deltas are stranded.
A subsequent online resets the per-cpu area but not pgdat->vm_stat[], orphaning the +N permanently. All NR_VM_NODE_STAT_ITEMS are affected.
The existing code zeroes the per-cpu counters and causes a permanent skew. Fold the stranded deltas instead, before the node rejoins the online set. The node is not online yet and the hotplug lock is held, so the remote access to per-cpu values is safe.
Discovered when node compaction hung for a nearly empty node, as the math to determine throttling broke. Reproduced by repeated memory hotplug/unplug cycles on a node under pressure: NR_ISOLATED_ANON ratchets up and never returns to zero.
--- mm/mm_init.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
mm/mm_init.c +11 -4
@@ -1565,7 +1565,7 @@ void __ref free_area_init_core_hotplug(s {int nid = pgdat->node_id;enum zone_type z; -int cpu; +int cpu, i;pgdat_init_internals (pgdat);
@@ -1583,10 +1583,17 @@ void __ref free_area_init_core_hotplug(s pgdat->node_start_pfn =0 ; pgdat->node_present_pages =0 ; -for_each_online_cpu (cpu) { -struct per_cpu_nodestat *p; +/* +* Hot-unplug can leave per-cpu vmstat deltas unfolded (folders skip +* offline nodes) - reconcile this at online. Foreign access to counters +* is safe: the node is not online yet and we hold the hotplug lock. +*/ +for_each_possible_cpu (cpu) { +struct per_cpu_nodestat *p =per_cpu_ptr (pgdat->per_cpu_nodestats, cpu); - p =per_cpu_ptr (pgdat->per_cpu_nodestats, cpu); +for (i =0 ; i <NR_VM_NODE_STAT_ITEMS ; i++) +if (p->vm_node_stat_diff[i]) +node_page_state_add (p->vm_node_stat_diff[i], pgdat, i);memset (p,0 ,sizeof (*p)); }
Greg Kroah-Hartman
maintainerPATCH 176/396 tracing/probes: Reject $arg0 in meta argument expansion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raushan Patel <[email protected]>
commit 00a8ce2a2a9fa17674e1feec4d9105c1a5d6a419 upstream.
traceprobe_expand_meta_args() parses $argN with simple_strtoul() and calls sprint_nth_btf_arg(n - 1, ...). For $arg0, n is 0 so the index is -1. Because ctx->nr_params is signed, the "idx >= nr_params" guard in sprint_nth_btf_arg() does not catch the negative index, and ctx->params[-1].name_off is read out of bounds.
The normal per-argument path (parse_probe_vars()) already rejects $arg0 via its argument-number check, but meta-argument expansion runs before per-argument parsing and substitutes the value first, bypassing that check.
Reject $arg0 explicitly during expansion.
--- kernel/trace/trace_probe.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/trace/trace_probe.c +5 -1
@@ -1906,7 +1906,11 @@ const char **traceprobe_expand_meta_argstrace_probe_log_err (0 ,BAD_VAR );return ERR_PTR (-ENOENT ); } -/* Note: $argN starts from $arg1 */ +/* Note: $argN starts from $arg1, so $arg0 is invalid. */ +if (n ==0 ) { +trace_probe_log_err (0 ,BAD_ARG_NUM ); +return ERR_PTR (-EINVAL ); + } ret =sprint_nth_btf_arg (n -1 , type, buf + used, bufsize - used, ctx);if (ret <0 )
Greg Kroah-Hartman
maintainerPATCH 177/396 tracing/fprobe: Roll back on enable_trace_fprobe() failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raushan Patel <[email protected]>
commit aca0cd1bf16574327ef64f3178e5f5e37a61ef0b upstream.
enable_trace_fprobe() sets the file link or the TP_FLAG_PROFILE flag and then registers each trace_fprobe in the probe list. If __register_trace_fprobe() fails partway through, the function returns immediately without unregistering the trace_fprobes it already registered or undoing the file link / flag it set, leaving the event half-enabled and leaking the registered fprobe(s).
enable_trace_kprobe() already handles this with a rollback path. Do the same for fprobe: on failure, unregister all probes and clear the file link or profile flag.
--- kernel/trace/trace_fprobe.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
kernel/trace/trace_fprobe.c +11 -1
@@ -1481,11 +1481,21 @@ static int enable_trace_fprobe(struct trlist_for_each_entry (tf,trace_probe_probe_list (tp), tp.list) { ret =__register_trace_fprobe (tf);if (ret <0 ) -return ret; + goto err; } }return 0 ; + +err: +/* Failed to enable one of them. Roll back all */ +list_for_each_entry (tf,trace_probe_probe_list (tp), tp.list) +__unregister_trace_fprobe (tf); +if (file) +trace_probe_remove_file (tp, file); +else +trace_probe_clear_flag (tp,TP_FLAG_PROFILE ); +return ret; }/*
Greg Kroah-Hartman
maintainerPATCH 178/396 KVM: VMX: add memory clobber to asm for VMX instructions
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini <[email protected]>
commit 0e65cd9e5d41c34f86b7c347967bedac54926041 upstream.
VMCLEAR/VMREAD/VMWRITE/VMPTRLD access the internal VMCS cache, which is not visible to the compiler; without a memory clobber, the compiler can reorder them in troublesome ways because "asm volatile" and "asm goto" only protect against removal of the asm. For example, placing a VMWRITE before the corresponding VMCS pointer is loaded can lead to corruption. While none of this has been observed, it is better to prevent than cure.
Likewise, INVEPT and INVVPID access the TLB and, even though in their case the effect is only visible to the next VMLAUNCH/VMRESUME, it is technically correct to add the clobber there too. So avoid any urge to special case them, and simply hardcode "memory" into the clobber list of vmx_asm1() and vmx_asm2(). __vmcs_readl() open-codes its own asm, so add the clobber there as well.
--- arch/x86/kvm/vmx/vmx_ops.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/kvm/vmx/vmx_ops.h +4 -4
@@ -101,7 +101,7 @@ static __always_inline unsigned long __v : [output] "=r" (value) : [field] "r" (field) - : "cc" + : "cc", "memory" : do_fail, do_exception);return value;
@@ -146,7 +146,7 @@ do_exception: : ASM_CALL_CONSTRAINT, [output] "=&r" (value) : [field] "r" (field) - : "cc"); + : "cc", "memory");return value;#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
@@ -194,7 +194,7 @@ do { \ ".byte 0x2e\n\t" /* branch not taken hint */ \ "jna %l[error]\n\t" \ _ASM_EXTABLE(1b, %l[fault]) \ - : : op1 : "cc" : error, fault); \ + : : op1 : "cc", "memory" : error, fault); \return ; \ error: \instrumentation_begin (); \
@@ -211,7 +211,7 @@ do { \ ".byte 0x2e\n\t" /* branch not taken hint */ \ "jna %l[error]\n\t" \ _ASM_EXTABLE(1b, %l[fault]) \ - : : op1, op2 : "cc" : error, fault); \ + : : op1, op2 : "cc", "memory" : error, fault);\return; \ error: \ instrumentation_begin(); \
Greg Kroah-Hartman
maintainerPATCH 179/396 KVM: SVM: Update x2APIC MSR intercepts if AVIC is inhibited while L2 is active
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 7d3aae206663c4e006b25a1c7a20a4029e67da76 upstream.
Always update x2APIC MSR intercepts for L1 when AVIC is deactivated, even if L2 is active and KVM is using a separate MSR bitmap to run L2. If AVIC is fully enabled prior to running L2, and is then inhibited while L2 is active (for a VM-scoped inhibit), then KVM will run L1 with AVIC disabled, but with x2APIC MSR intercepts disabled, i.e. will allow L1 to read most of the host's APIC state, send arbitrary interrupts, change task priority, and ultimately trivially DoS the host.
E.g. sending a self-IPI in L1 on HYPERV_REENLIGHTENMENT_VECTOR, 0xee, with CONFIG_HYPERV=n in the host kernel as a "safe" PoC, yields:
Spurious interrupt (vector 0xee) on CPU#425. Acked
And hacking KVM to abuse kvm_set_posted_intr_wakeup_handler() to register a handler and WARN on POSTED_INTR_WAKEUP_VECTOR yields:
------------[ cut here ]------------ WARNING: arch/x86/kvm/svm/svm.c:5594 at pi_wakeup_handler+0x9/0x10 [kvm_amd], CPU#156: nested_x2apic_t/316940 CPU: 156 UID: 0 PID: 316940 Comm: nested_x2apic_t Tainted: G S U Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER Hardware name: Google Astoria-Turin/astoria, BIOS 0.20260209.0-0 02/09/2026 RIP: 0010:pi_wakeup_handler+0x9/0x10 [kvm_amd] Call Trace: <IRQ> sysvec_kvm_posted_intr_wakeup_ipi+0x64/0x80 </IRQ> <TASK> asm_sysvec_kvm_posted_intr_wakeup_ipi+0x1a/0x20 RIP: 0010:vcpu_run+0x1430/0x1e40 [kvm] kvm_arch_vcpu_ioctl_run+0x2c1/0x600 [kvm] kvm_vcpu_ioctl+0x580/0x6b0 [kvm] __se_sys_ioctl+0x6d/0xb0 do_syscall_64+0x10a/0x480 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x46ff4b </TASK> ---[ end trace 0000000000000000 ]---
--- arch/x86/kvm/svm/avic.c | 8 -------- 1 file changed, 8 deletions(-)
arch/x86/kvm/svm/avic.c +0 -8
@@ -220,14 +220,6 @@ static void avic_deactivate_vmcb(structif (!sev_es_guest (svm->vcpu.kvm))svm_set_intercept (svm,INTERCEPT_CR8_WRITE ); -/* -* If running nested and the guest uses its own MSR bitmap, there -* is no need to update L0's msr bitmap -*/ -if (is_guest_mode (&svm->vcpu) && -vmcb12_is_intercept (&svm->nested.ctl,INTERCEPT_MSR_PROT )) -return ; -/* Enabling MSR intercept for x2APIC registers */ avic_set_x2apic_msr_interception (svm, true); }
Greg Kroah-Hartman
maintainerPATCH 180/396 KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 8fa01be5a6149404adb82c0979a78f6347edd3ef upstream.
The MPCIFC instruction doesn't allow registering adapter interrupts without first unregistering. So reject any request to enable interrupt forwarding if its already enabled for the zPCI device. This also fixes overwriting and thus leaking resources when the ioctl is called multiple times for the same device.
--- arch/s390/kvm/pci.c | 4 ++++ 1 file changed, 4 insertions(+)
arch/s390/kvm/pci.c +4 -0
@@ -238,6 +238,10 @@ static int kvm_s390_pci_aif_enable(strucif (zdev->gisa ==0 )return -EINVAL ; +/* AIF already enabled for the device */ +if (zdev->kzdev->fib.fmt0.aibv !=0 ) +return -EINVAL ; + kvm = zdev->kzdev->kvm; msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
Greg Kroah-Hartman
maintainerPATCH 181/396 KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 36f6999ecde3976731a8bfc0b8e667da6f593069 upstream.
The account_mem() and unaccount_mem() functions call get_uid() which increments the reference count of struct user_struct on every invocation. But we don't decrement the count by calling free_uid(). It also accounted/unaccounted the pages against the current->mm. But its possible the unaccount_mem() can be called from a different process context than the one that originally pinned the pages.
Let's fix this by storing the pinning process user_struct and mm_struct when accounting for pinned pages, and subsequently free these resources when the pages are unpinned.
--- arch/s390/kvm/pci.c | 43 ++++++++++++++++++++++++++++++++----------- arch/s390/kvm/pci.h | 2 ++ 2 files changed, 34 insertions(+), 11 deletions(-)
arch/s390/kvm/pci.c +32 -11
@@ -191,33 +191,54 @@ static int kvm_zpci_clear_airq(struct zpreturn cc ? -EIO :0 ; } -static inline void unaccount_mem (unsigned long nr_pages) +static inline void unaccount_mem (struct kvm_zdev *kzdev,unsigned long nr_pages) { -struct user_struct *user =get_uid (current_user ()); +struct user_struct *user = kzdev->user_account; +struct mm_struct *mm_account = kzdev->mm_account; -if (user) +if (user) {atomic_long_sub (nr_pages, &user->locked_vm); -if (current->mm) -atomic64_sub (nr_pages, ¤t->mm->pinned_vm); +free_uid (user); + kzdev->user_account =NULL ; + } + +if (mm_account) { +atomic64_sub (nr_pages, &mm_account->pinned_vm); +mmdrop (mm_account); + kzdev->mm_account =NULL ; + } } -static inline int account_mem (unsigned long nr_pages) +static inline int account_mem (struct kvm_zdev *kzdev,unsigned long nr_pages) {struct user_struct *user =get_uid (current_user ());unsigned long page_limit, cur_pages, new_pages; +int rc =0 ; page_limit =rlimit (RLIMIT_MEMLOCK ) >>PAGE_SHIFT ; cur_pages =atomic_long_read (&user->locked_vm);do { new_pages = cur_pages + nr_pages; -if (new_pages > page_limit) -return -ENOMEM ; +if (new_pages > page_limit) { + rc = -ENOMEM ; + goto out; + } }while (!atomic_long_try_cmpxchg (&user->locked_vm, &cur_pages, new_pages)); -atomic64_add (nr_pages, ¤t->mm->pinned_vm); +if (current->mm) { +mmgrab (current->mm); +atomic64_add (nr_pages, ¤t->mm->pinned_vm); + } + + kzdev->user_account = user; + kzdev->mm_account = current->mm;return 0 ; + +out: +free_uid (user); +return rc; } static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
@@ -280,7 +301,7 @@ static int kvm_s390_pci_aif_enable(struc }/* Account for pinned pages, roll back on failure */ -if (account_mem (pcount)) +if (account_mem (zdev->kzdev, pcount)) goto unpin2;/* AISB must be allocated before we can fill in GAITE */
@@ -401,7 +422,7 @@ static int kvm_s390_pci_aif_disable(stru pcount++; }if (pcount >0 ) -unaccount_mem (pcount); +unaccount_mem (kzdev, pcount); out:mutex_unlock (&aift->aift_lock);
arch/s390/kvm/pci.h +2 -0
@@ -22,6 +22,8 @@ struct kvm_zdev {struct kvm *kvm;struct zpci_fib fib;struct list_head entry; +struct user_struct *user_account; +struct mm_struct *mm_account; };struct zpci_gaite {
Greg Kroah-Hartman
maintainerPATCH 182/396 KVM: s390: pci: Fix missing error codes and memory unaccounting
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit f86842e4d6c482300f4567f492d512c9ccf5bc4f upstream.
In kvm_s390_pci_aif_enable() two error paths failed to set an error code, causing the function to return 0 on failure. It also failed to rollback memory accounting on failure. Fix both by propagating an error code on failure and calling unaccount_mem() in the cleanup path.
--- arch/s390/kvm/pci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
arch/s390/kvm/pci.c +7 -2
@@ -301,14 +301,17 @@ static int kvm_s390_pci_aif_enable(struc }/* Account for pinned pages, roll back on failure */ -if (account_mem (zdev->kzdev, pcount)) + rc =account_mem (zdev->kzdev, pcount); +if (rc) goto unpin2;/* AISB must be allocated before we can fill in GAITE */ mutex_lock (&aift->aift_lock); bit =airq_iv_alloc_bit (aift->sbv); -if (bit ==-1UL ) +if (bit ==-1UL ) { + rc = -ENOMEM ; goto unlock; + } zdev->aisb = bit;/* store the summary bit number */ zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK |
@@ -352,6 +355,8 @@ static int kvm_s390_pci_aif_enable(strucreturn rc; unlock: +if (pcount >0 ) +unaccount_mem (zdev->kzdev, pcount);mutex_unlock (&aift->aift_lock); unpin2:if (fib->fmt0.sum ==1 )
Greg Kroah-Hartman
maintainerPATCH 183/396 KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 8bf09b9b7d3232806df95f409581f8a9fd99a3fa upstream.
The airq_iv_create() can return NULL on failure, but the return value was never checked. If it fails, zdev->aibv will be NULL and fail when dereferenced in kvm_zpci_set_airq(). Add a NULL check and free the previously allocated AISB bit and zdev->aisb on failure.
--- arch/s390/kvm/pci.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/s390/kvm/pci.c +8 -0
@@ -318,6 +318,11 @@ static int kvm_s390_pci_aif_enable(strucAIRQ_IV_GUESTVEC , phys_to_virt(fib->fmt0.aibv)); +if (!zdev->aibv) { + rc = -ENOMEM ; + goto free_aisb; + } +spin_lock_irq (&aift->gait_lock); gaite = aift->gait + zdev->aisb;
@@ -354,6 +359,9 @@ static int kvm_s390_pci_aif_enable(struc rc =kvm_zpci_set_airq (zdev);return rc; +free_aisb: +airq_iv_free_bit (aift->sbv, zdev->aisb); + zdev->aisb =0 ; unlock:if (pcount >0 )unaccount_mem (zdev->kzdev, pcount);
Greg Kroah-Hartman
maintainerPATCH 184/396 KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Farhan Ali <[email protected]>
commit 868d32ac72cba21c5c6d8a66a814b7c25a3a5c01 upstream.
The AIBV holds one bit per MSI-X vector for a given function. The size of the bit vector is derived from the NOI and the AIBVO. If the size of the AIBV exceeds a single page boundary, then reject the request as we cannot safely pin the guest AIBV.
Similarly reject the request if the AISB address is not 8-byte aligned as the architecture requires doubleword alignment for the summary bit address. Since the AISBO can address up to 64 bits, the size of the AISB can only be 8 bytes for the function. This also ensures the AISB doesn't exceed a single page boundary.
--- arch/s390/kvm/pci.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
arch/s390/kvm/pci.c +15 -1
@@ -245,7 +245,7 @@ static int kvm_s390_pci_aif_enable(struc bool assist) {struct page *pages[1 ], *aibv_page, *aisb_page =NULL ; -unsigned int msi_vecs, idx; +unsigned int msi_vecs, idx, size;struct zpci_gaite *gaite;unsigned long hva, bit;struct kvm *kvm;
@@ -272,6 +272,14 @@ static int kvm_s390_pci_aif_enable(strucreturn gisc;/* Replace AIBV address */ + size =BITS_TO_LONGS (msi_vecs + fib->fmt0.aibvo) *sizeof (unsigned long ); + npages =DIV_ROUND_UP ((fib->fmt0.aibv & ~PAGE_MASK ) + size,PAGE_SIZE ); +/* AIBV cannot span more than 1 page */ +if (npages >1 ) { + rc = -EINVAL ; + goto out; + } + idx =srcu_read_lock (&kvm->srcu); hva =gfn_to_hva (kvm,gpa_to_gfn ((gpa_t )fib->fmt0.aibv)); npages =pin_user_pages_fast (hva,1 ,FOLL_WRITE |FOLL_LONGTERM , pages);
@@ -287,6 +295,12 @@ static int kvm_s390_pci_aif_enable(struc/* Pin the guest AISB if one was specified */ if (fib->fmt0.sum ==1 ) { +/* AISB must be dword aligned */ +if (fib->fmt0.aisb &0x7 ) { + rc = -EINVAL ; + goto unpin1; + } + idx =srcu_read_lock (&kvm->srcu); hva =gfn_to_hva (kvm,gpa_to_gfn ((gpa_t )fib->fmt0.aisb)); npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
Greg Kroah-Hartman
maintainerPATCH 185/396 dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit a10ea943356b9d70c5616a0a06f6fa97cfdaccb1 upstream.
dibs_lo_attach_dmb(), dibs_lo_detach_dmb() and dibs_lo_unregister_dmb() look up the dmb_node under dmb_ht_lock, drop the lock and only then operate on the node's refcount. Nothing keeps the node alive across that window: __dibs_lo_unregister_dmb() removes the node from the hash table under the write lock and immediately frees it.
A concurrent final put can therefore free the node between the lookup and the refcount operation:
CPU0 (attach) CPU1 (owner unregisters)
read_lock_bh(&dmb_ht_lock)
find dmb_node (refcnt == 1)read_unlock_bh(&dmb_ht_lock)
refcount_dec_and_test() 1 -> 0
write_lock_bh(&dmb_ht_lock)
hash_del(&dmb_node->list)
write_unlock_bh(&dmb_ht_lock)
kfree(dmb_node)refcount_inc_not_zero(&dmb_node->refcnt) <-- use-after-free
The same window exists for the refcount_dec_and_test() calls in the detach and unregister paths.
Close the race structurally by making hash table membership and the refcount transitions atomic with respect to each other:
- Perform the final refcount_dec_and_test() and hash_del() in a single dmb_ht_lock write-side critical section, in both the unregister and the detach path. Freeing the node still happens after the lock is dropped, which is safe because a node whose refcount reached zero has left the hash table and can no longer be found.
- This establishes the invariant that any node found in the hash table holds at least one reference, and that the final reference can only be dropped under the write lock. dibs_lo_attach_dmb() can thus take its reference with a plain refcount_inc() while still holding the read lock; refcount_inc_not_zero() is no longer needed.
__dibs_lo_unregister_dmb() no longer touches the hash table and is renamed to dibs_lo_free_dmb() accordingly.
Note: commit cc21191b584c ("dibs: Move data path to dibs layer") moved the code to its current location; the race was introduced earlier by commit c3a910f2380f ("net/smc: implement DMB-merged operations of loopback-ism").
Tested SMC-D via ISM and dibs loopback.
--- drivers/dibs/dibs_loopback.c | 47 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 23 deletions(-)
drivers/dibs/dibs_loopback.c +24 -23
@@ -118,14 +118,9 @@ err_bit:return rc; } -static void __dibs_lo_unregister_dmb (struct dibs_lo_dev *ldev, -struct dibs_lo_dmb_node *dmb_node) +static void dibs_lo_free_dmb (struct dibs_lo_dev *ldev, +struct dibs_lo_dmb_node *dmb_node) { -/* remove dmb from hash table */ -write_lock_bh (&ldev->dmb_ht_lock); -hash_del (&dmb_node->list); -write_unlock_bh (&ldev->dmb_ht_lock); -clear_bit (dmb_node->sba_idx, ldev->sba_idx_mask);folio_put (virt_to_folio (dmb_node->cpu_addr));kfree (dmb_node);
@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(structstruct dibs_lo_dmb_node *dmb_node =NULL , *tmp_node;struct dibs_lo_dev *ldev;unsigned long flags; +bool last; ldev = dibs->drv_priv;/* find dmb from hash table */ -read_lock_bh (&ldev->dmb_ht_lock); +write_lock_bh (&ldev->dmb_ht_lock);hash_for_each_possible (ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {if (tmp_node->token == dmb->dmb_tok) { dmb_node = tmp_node;break ; } } -read_unlock_bh (&ldev->dmb_ht_lock); -if (!dmb_node) +if (!dmb_node) { +write_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; + } + last =refcount_dec_and_test (&dmb_node->refcnt); +if (last) +hash_del (&dmb_node->list); +write_unlock_bh (&ldev->dmb_ht_lock); -if (refcount_dec_and_test (&dmb_node->refcnt)) { +if (last) {spin_lock_irqsave (&dibs->lock, flags); dibs->dmb_clientid_arr[dmb_node->sba_idx] =NO_DIBS_CLIENT ;spin_unlock_irqrestore (&dibs->lock, flags); -__dibs_lo_unregister_dmb (ldev, dmb_node); +dibs_lo_free_dmb (ldev, dmb_node); }return 0 ; }
@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibread_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; } +refcount_inc (&dmb_node->refcnt);read_unlock_bh (&ldev->dmb_ht_lock); -if (!refcount_inc_not_zero (&dmb_node->refcnt)) -/* the dmb is being unregistered, but has -* not been removed from the hash table. -*/ -return -EINVAL ; -/* provide dmb information */ dmb->idx = dmb_node->sba_idx; dmb->dmb_tok = dmb_node->token;
@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dib {struct dibs_lo_dmb_node *dmb_node =NULL , *tmp_node;struct dibs_lo_dev *ldev; +bool last; ldev = dibs->drv_priv;/* find dmb_node according to dmb->dmb_tok */ -read_lock_bh (&ldev->dmb_ht_lock); +write_lock_bh (&ldev->dmb_ht_lock);hash_for_each_possible (ldev->dmb_ht, tmp_node, list, token) {if (tmp_node->token == token) { dmb_node = tmp_node;
@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dib } }if (!dmb_node) { -read_unlock_bh (&ldev->dmb_ht_lock); +write_unlock_bh (&ldev->dmb_ht_lock);return -EINVAL ; } -read_unlock_bh (&ldev->dmb_ht_lock); + last =refcount_dec_and_test (&dmb_node->refcnt); +if (last) +hash_del (&dmb_node->list); +write_unlock_bh (&ldev->dmb_ht_lock); + +if (last) +dibs_lo_free_dmb (ldev, dmb_node); -if (refcount_dec_and_test (&dmb_node->refcnt)) -__dibs_lo_unregister_dmb (ldev, dmb_node);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 186/396 sctp: validate Adaptation Indication parameter length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charles Vosburgh <[email protected]>
commit 74b21f52c5c5a71a05c0ff70e513f4f04ff28b17 upstream.
The Adaptation Layer Indication parameter contains a fixed 32-bit Adaptation Code Point after its parameter header. However, sctp_verify_param() accepts a header-only parameter because the generic parameter walker only requires the header to be present.
sctp_process_param() then reads adaptation_ind beyond the declared parameter. When the malformed parameter is last in an INIT, the read starts at the receive skb tail, and the value is copied into the state cookie returned in the INIT ACK. This may disclose four receive-buffer tail bytes.
Require the declared parameter length to match the fixed structure size and abort the association through the existing invalid parameter length path otherwise.
--- net/sctp/sm_make_chunk.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_make_chunk.c +6 -0
@@ -2168,7 +2168,13 @@ static enum sctp_ierror sctp_verify_paracase SCTP_PARAM_HEARTBEAT_INFO :case SCTP_PARAM_UNRECOGNIZED_PARAMETERS :case SCTP_PARAM_ECN_CAPABLE : +break ;case SCTP_PARAM_ADAPTATION_LAYER_IND : +if (ntohs (param.p->length) !=sizeof (*param.aind)) { +sctp_process_inv_paramlength (asoc, param.p, + chunk, err_chunk); + retval =SCTP_IERROR_ABORT ; + }break ;case SCTP_PARAM_SUPPORTED_EXT :
Greg Kroah-Hartman
maintainerPATCH 187/396 audit: fix potential integer overflow in audit_log_n_string()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit f865c143629d4094866a811dba5f329250bad486 upstream.
audit_log_n_string() computes new_len as "slen + 3" (enclosing quotes plus the NUL terminator) and stores it into an int, while slen is a size_t. For a sufficiently large slen the addition can overflow and/or the result be truncated when assigned to the int new_len, so the "new_len > avail" check can be bypassed and the subsequent memcpy(ptr, string, slen) can write past the skb tail.
This is the same class of bug that was fixed for the hex sibling in commit 65dfde57d1e2 ("audit: fix potential integer overflow in audit_log_n_hex()"); both helpers are reached through audit_log_n_untrustedstring() with the same length source.
Make new_len a size_t and use check_add_overflow() to catch the overflow, mirroring the audit_log_n_hex() fix. No functional change for the in-tree callers, which all pass bounded lengths.
--- kernel/audit.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/audit.c +9 -2
@@ -2115,7 +2115,8 @@ void audit_log_n_hex(struct audit_buffervoid audit_log_n_string (struct audit_buffer *ab,const char *string,size_t slen) { -int avail, new_len; +int avail; +size_t new_len;unsigned char *ptr;struct sk_buff *skb;
@@ -2125,7 +2126,13 @@ void audit_log_n_string(struct audit_bufBUG_ON (!ab->skb); skb = ab->skb; avail =skb_tailroom (skb); - new_len = slen +3 ;/* enclosing quotes + null terminator */ + +/* enclosing quotes + null terminator */ +if (check_add_overflow (slen,3 , &new_len)) { +audit_log_format (ab,"?" ); +return ; + } +if (new_len > avail) { avail =audit_expand (ab, new_len);if (!avail)
Greg Kroah-Hartman
maintainerPATCH 188/396 audit: fix potential use-after-free in audit_del_rule()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <[email protected]>
commit 246df90b5f1a8a6e6abbd2f058b029558720adec upstream.
audit_del_rule() destroys e->rule.exe via audit_remove_mark_rule() before unlinking the rule from RCU-visible filter lists and waiting for a grace period. Concurrent readers in audit_filter() and audit_filter_rules() still dereference e->rule.exe, while the fsnotify mark can be freed on an independent lifetime path. This creates a use-after-free window during rule deletion.
Fix this by unlinking the rule from the RCU-visible lists and invoking synchronize_rcu() before calling audit_remove_mark_rule() (and other rule removal helpers). This ensures that all existing RCU readers have exited the critical section before any underlying resources are destroyed.
--- kernel/auditfilter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/auditfilter.c +4 -2
@@ -1047,6 +1047,10 @@ int audit_del_rule(struct audit_entry *e goto out; } +list_del_rcu (&e->list); +list_del (&e->rule.list); +synchronize_rcu (); +if (e->rule.watch)audit_remove_watch_rule (&e->rule);
@@ -1064,8 +1068,6 @@ int audit_del_rule(struct audit_entry *e audit_signals--;#endif -list_del_rcu (&e->list); -list_del (&e->rule.list);call_rcu (&e->rcu, audit_free_rule_rcu); out:
Greg Kroah-Hartman
maintainerPATCH 189/396 Bluetooth: btusb: Fix short read errors in btusb_qca_send_vendor_req()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit cac43d360c928bc0cbbd18809632388265649761 upstream.
If btusb_qca_send_vendor_req() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btusb_qca_send_vendor_req() is called.
--- drivers/bluetooth/btusb.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/bluetooth/btusb.c +9 -21
@@ -3345,28 +3345,16 @@ static const char *qca_get_fw_subdirectostatic int btusb_qca_send_vendor_req (struct usb_device *udev,u8 request,void *data,u16 size) { -int pipe, err; -u8 *buf; - - buf =kmalloc (size,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +int err;/* Found some of USB hosts have IOT issues with ours so that we should * not wait until HCI layer is ready. */ - pipe =usb_rcvctrlpipe (udev,0 ); - err =usb_control_msg (udev, pipe, request,USB_TYPE_VENDOR |USB_DIR_IN , -0 ,0 , buf, size,USB_CTRL_GET_TIMEOUT ); -if (err <0 ) { + err =usb_control_msg_recv (udev,0 , request,USB_TYPE_VENDOR |USB_DIR_IN , +0 ,0 , data, size,USB_CTRL_GET_TIMEOUT , +GFP_KERNEL ); +if (err)dev_err (&udev->dev,"Failed to access otp area (%d)" , err); - goto done; - } - -memcpy (data, buf, size); - -done: -kfree (buf);return err; }
@@ -3573,7 +3561,7 @@ static bool btusb_qca_need_patch(structstruct qca_version ver;if (btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver, -sizeof (ver)) <0 ) +sizeof (ver)))return false;/* only low ROM versions need patches */ return !(le32_to_cpu (ver.rom_version) & ~0xffffU );
@@ -3591,7 +3579,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver,sizeof (ver)); -if (err <0 ) +if (err)return err; ver_rom =le32_to_cpu (ver.rom_version);
@@ -3614,7 +3602,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_CHECK_STATUS , &status,sizeof (status)); -if (err <0 ) +if (err)return err;if (!(status &QCA_PATCH_UPDATED )) {
@@ -3625,7 +3613,7 @@ static int btusb_setup_qca(struct hci_de err =btusb_qca_send_vendor_req (udev,QCA_GET_TARGET_VERSION , &ver,sizeof (ver)); -if (err <0 ) +if (err)return err; btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version);
Greg Kroah-Hartman
maintainerPATCH 190/396 Bluetooth: btmtk: Fix short read errors in btmtk_usb_uhw_reg_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit b186c18c4843dd58adc29443369bddc71cb626a3 upstream.
If btmtk_usb_uhw_reg_read() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btmtk_usb_uhw_reg_read() is called.
Note, one caller of btmtk_usb_uhw_reg_read() does not check the return value, but as we pre-initialize the return value as 0, an incorrect read will not do anything wrong.
--- drivers/bluetooth/btmtk.c | 50 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-)
drivers/bluetooth/btmtk.c +22 -28
@@ -763,30 +763,24 @@ static int btmtk_usb_uhw_reg_write(strucstatic int btmtk_usb_uhw_reg_read (struct hci_dev *hdev,u32 reg,u32 *val) {struct btmtk_data *data =hci_get_priv (hdev); -int pipe, err; -void *buf; - - buf =kzalloc (4 ,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +u8 buf[sizeof (u32)]; +int err; - pipe =usb_rcvctrlpipe (data->udev,0 ); - err =usb_control_msg (data->udev, pipe,0x01 , -0xDE , - reg >>16 , reg &0xffff , - buf,4 ,USB_CTRL_GET_TIMEOUT ); -if (err <0 ) { + *val =0 ; + err =usb_control_msg_recv (data->udev,0 ,0x01 , +0xDE , + reg >>16 , reg &0xffff , + buf,sizeof (buf),USB_CTRL_GET_TIMEOUT , +GFP_KERNEL ); +if (err) {bt_dev_err (hdev,"Failed to read uhw reg(%d)" , err); - goto err_free_buf; +return err; } *val =get_unaligned_le32 (buf);bt_dev_dbg (hdev,"reg=%x, value=0x%08x" , reg, *val); -err_free_buf: -kfree (buf); - -return err; +return 0 ; }static int btmtk_usb_reg_read (struct hci_dev *hdev,u32 reg,u32 *val)
@@ -836,7 +830,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (dev_id ==0x7922 ) { err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; val |=0x00002020 ; err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST , val);
@@ -846,7 +840,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; val |=BIT (0 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST , val);
@@ -855,14 +849,14 @@ int btmtk_usb_subsys_reset(struct hci_demsleep (100 ); }else if (dev_id ==0x7925 ) { err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val |= (1 <<5 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_RESET_REG_CONNV3 , val);if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val &=0xFFFF00FF ; val |= (1 <<13 );
@@ -873,7 +867,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val); -if (err <0 ) +if (err)return err; val |= (1 <<0 ); err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_RESET_REG_CONNV3 , val);
@@ -883,13 +877,13 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT , &val); -if (err <0 ) +if (err)return err; err =btmtk_usb_uhw_reg_write (hdev,MTK_UDMA_INT_STA_BT1 ,0x000000FF );if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT1 , &val); -if (err <0 ) +if (err)return err;msleep (100 ); }else {
@@ -899,7 +893,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_WDT_STATUS , &val); -if (err <0 ) +if (err)return err;/* Reset the bluetooth chip via USB interface. */ err =btmtk_usb_uhw_reg_write (hdev,MTK_BT_SUBSYS_RST ,1 );
@@ -909,13 +903,13 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT , &val); -if (err <0 ) +if (err)return err; err =btmtk_usb_uhw_reg_write (hdev,MTK_UDMA_INT_STA_BT1 ,0x000000FF );if (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_UDMA_INT_STA_BT1 , &val); -if (err <0 ) +if (err)return err;/* MT7921 need to delay 20ms between toggle reset bit */ msleep (20 );
@@ -923,7 +917,7 @@ int btmtk_usb_subsys_reset(struct hci_deif (err <0 )return err; err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_SUBSYS_RST , &val); -if (err <0 ) +if (err)return err; }
Greg Kroah-Hartman
maintainerPATCH 191/396 Bluetooth: mgmt: fix pending command UAF in EIR updates
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit 8f2f62855a41d1730fb9e8122912bd2c8d6bed5d upstream.
MGMT_OP_SET_LOCAL_NAME is handled asynchronously on powered controllers and can run set_name_sync(). When the controller is BR/EDR capable, set_name_sync() updates the local name and then rebuilds EIR data through eir_create(). The EIR builder walks hdev->uuids, but the UUID list can be changed and entries can be freed by MGMT_OP_ADD_UUID and MGMT_OP_REMOVE_UUID.
pending_eir_or_class() is meant to serialize management commands that can change EIR or the class of device, but it did not include MGMT_OP_SET_LOCAL_NAME. In addition, it walked hdev->mgmt_pending without hdev->mgmt_pending_lock even though pending commands are added and removed under that mutex. A racing command completion can therefore remove and free a pending command while pending_eir_or_class() is still inspecting it, leading to a use-after-free in the pending-command list or allowing a local name update to rebuild EIR while UUID entries are being removed.
Take hdev->mgmt_pending_lock while scanning hdev->mgmt_pending and treat MGMT_OP_SET_LOCAL_NAME as an EIR/class-affecting pending command on the powered asynchronous path. Check for a conflicting pending command before copying the new short name so a rejected SET_LOCAL_NAME request does not modify hdev->short_name.
--- net/bluetooth/mgmt.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
net/bluetooth/mgmt.c +18 -2
@@ -2699,18 +2699,28 @@ static int mgmt_hci_cmd_sync(struct sockstatic bool pending_eir_or_class (struct hci_dev *hdev) {struct mgmt_pending_cmd *cmd; +bool pending = false; + +mutex_lock (&hdev->mgmt_pending_lock);list_for_each_entry (cmd, &hdev->mgmt_pending, list) {switch (cmd->opcode) {case MGMT_OP_ADD_UUID :case MGMT_OP_REMOVE_UUID :case MGMT_OP_SET_DEV_CLASS : +case MGMT_OP_SET_LOCAL_NAME :case MGMT_OP_SET_POWERED : -return true; + pending = true; +break ; } + +if (pending) +break ; } -return false; +mutex_unlock (&hdev->mgmt_pending_lock); + +return pending; }static const u8 bluetooth_base_uuid[] = {
@@ -4046,6 +4056,12 @@ static int set_local_name(struct sock *s goto failed; } +if (hdev_is_powered (hdev) &&pending_eir_or_class (hdev)) { + err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_SET_LOCAL_NAME , +MGMT_STATUS_BUSY ); + goto failed; + } +memcpy (hdev->short_name, cp->short_name,sizeof (hdev->short_name));if (!hdev_is_powered (hdev)) {
Greg Kroah-Hartman
maintainerPATCH 192/396 Bluetooth: SCO: give the socket its own sco_conn reference
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]>
commit abd93c85c8667add738ee82aeab95dd9fc8265a2 upstream.
sco_conn_del() drops a reference it does not own. It takes one transient reference via sco_conn_hold_unless_zero() and releases it with the sco_conn_put() that follows sco_sock_hold(); the additional put in the !sk branch releases a second one:
conn = sco_conn_hold_unless_zero(conn);
...
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
sco_conn_put(conn);
if (!sk) {
sco_conn_put(conn);
return;
}When close() races the controller's Disconnection Complete, sco_chan_del() clears conn->sk and drops the socket's reference while sco_conn_del() is running. sco_conn_del() then sees sk == NULL, its own put drops the count to zero and frees the conn, and the second put writes to the freed kref:
BUG: KASAN: slab-use-after-free in sco_conn_put.part.0+0x1a/0x190
Write of size 4 at addr ffff8881099dec74 by task kworker/u17:3/413
Workqueue: hci1 hci_rx_work
Call Trace:
sco_conn_put.part.0+0x1a/0x190
hci_disconn_complete_evt+0x1ee/0x3e0
hci_event_packet+0x54a/0x650
hci_rx_work+0x321/0x3d0
Allocated by task 413:
sco_conn_add+0x72/0x1a0
sco_connect_cfm+0x88/0x670
Freed by task 413:
sco_conn_del.isra.0+0x3f/0xf0
hci_disconn_complete_evt+0x1ee/0x3e0
refcount_t: underflow; use-after-free.The root cause is that the socket stores the connection without holding a reference of its own. __sco_chan_add() does:
sco_pi(sk)->conn = conn;
so the socket borrows whatever reference its caller happened to hold, and the callers paper over that with ad-hoc holds and puts. Give the socket a counted reference instead: __sco_chan_add() takes one and it is released together with the channel (sco_chan_del()) and in sco_sock_destruct(). With the socket holding its own reference, sco_conn_del() no longer needs the extra put and the redundant hold in sco_conn_ready() goes away.
Making the socket own its reference means the connection is now actually freed on the error paths of sco_connect() where it used to leak, which in turn runs sco_conn_free() and its hci_conn_drop(conn->hcon). To keep the hci_conn accounting balanced, make that ownership explicit as well:sco_conn_add() consumes one hci_conn reference and the sco_conn owns it for its lifetime. sco_connect() hands over the reference returned by hci_connect_sco() and no longer drops it on the error paths; sco_connect_cfm(), which is not given a reference, takes one with hci_conn_hold() before handing it to sco_conn_add() (and drops it again if the allocation fails); and the explicit hci_conn_hold() in sco_conn_ready() is removed. Every reference then has a single, clear owner.
--- net/bluetooth/sco.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
net/bluetooth/sco.c +13 -9
@@ -190,6 +190,9 @@ static void sco_sock_clear_timer(struct }/* ---- SCO connections ---- */ +/* Consumes a reference on @hcon, which the returned sco_conn owns until it is +* freed. On failure (NULL return) the reference is left for the caller to drop. +*/ static struct sco_conn *sco_conn_add (struct hci_conn *hcon) {struct sco_conn *conn = hcon->sco_data;
@@ -200,6 +203,9 @@ static struct sco_conn *sco_conn_add(strsco_conn_lock (conn); conn->hcon = hcon;sco_conn_unlock (conn); + }else { +/* conn already owns a reference on hcon */ +hci_conn_drop (hcon); }return conn; }
@@ -267,10 +273,8 @@ static void sco_conn_del(struct hci_connsco_conn_unlock (conn);sco_conn_put (conn); -if (!sk) { -sco_conn_put (conn); +if (!sk)return ; - }/* Kill socket */ lock_sock (sk);
@@ -285,7 +289,7 @@ static void __sco_chan_add(struct sco_co {BT_DBG ("conn %p" , conn); -sco_pi (sk)->conn = conn; +sco_pi (sk)->conn =sco_conn_hold (conn); conn->sk = sk;if (parent)
@@ -368,15 +372,15 @@ static int sco_connect(struct sock *sk)*/ if (sk->sk_state !=BT_OPEN && sk->sk_state !=BT_BOUND ) {release_sock (sk); -hci_conn_drop (hcon); +sco_conn_put (conn); err = -EBADFD ; goto unlock; } err =sco_chan_add (conn, sk,NULL ); +sco_conn_put (conn);if (err) {release_sock (sk); -hci_conn_drop (hcon); goto unlock; }
@@ -1452,8 +1456,6 @@ static void sco_conn_ready(struct sco_cobacpy (&sco_pi (sk)->src, &conn->hcon->src);bacpy (&sco_pi (sk)->dst, &conn->hcon->dst); -sco_conn_hold (conn); -hci_conn_hold (conn->hcon);__sco_chan_add (conn, sk, parent);if (test_bit (BT_SK_DEFER_SETUP , &bt_sk (parent)->flags))
@@ -1509,10 +1511,12 @@ static void sco_connect_cfm(struct hci_cif (!status) {struct sco_conn *conn; - conn =sco_conn_add (hcon); + conn =sco_conn_add (hci_conn_hold (hcon));if (conn) {sco_conn_ready (conn);sco_conn_put (conn); + }else { +hci_conn_drop (hcon); } }else sco_conn_del (hcon,bt_to_errno (status));
Greg Kroah-Hartman
maintainerPATCH 193/396 Bluetooth: mgmt: fix UAF in pair command cancellation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit d0a7b48ad0921bd88effaee10bf970ab1d5d0ddd upstream.
The pairing completion and authentication failure callbacks look up the pending MGMT_OP_PAIR_DEVICE command by walking hdev->mgmt_pending. The lookup returned a command that was still linked on the shared pending list, without keeping mgmt_pending_lock held for the later dereference and removal.
A concurrent MGMT_OP_CANCEL_PAIR_DEVICE request can remove and free the same pending command before the callback uses it. The reverse race is also possible when cancel_pair_device() gets a command from pending_find() and a callback removes it before the cancel path dereferences it. This can lead to a use-after-free and a second list_del().
Make the pairing lookup helpers transfer ownership of the pending command by removing it from hdev->mgmt_pending while holding mgmt_pending_lock. The callbacks and cancel path then complete the command and free it directly, so racing paths cannot find or free the same command again. Take a temporary hci_conn reference in cancel_pair_device() because the command completion drops the reference stored in the pending command.
--- net/bluetooth/mgmt.c | 64 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 18 deletions(-)
net/bluetooth/mgmt.c +46 -18
@@ -3527,11 +3527,13 @@ static int set_io_capability(struct sock NULL, 0); } -static struct mgmt_pending_cmd *find_pairing (struct hci_conn *conn) +static struct mgmt_pending_cmd *remove_pairing (struct hci_conn *conn) {struct hci_dev *hdev = conn->hdev;struct mgmt_pending_cmd *cmd; +mutex_lock (&hdev->mgmt_pending_lock); +list_for_each_entry (cmd, &hdev->mgmt_pending, list) {if (cmd->opcode !=MGMT_OP_PAIR_DEVICE )continue ;
@@ -3539,9 +3541,39 @@ static struct mgmt_pending_cmd *find_paiif (cmd->user_data != conn)continue ; +list_del (&cmd->list); +mutex_unlock (&hdev->mgmt_pending_lock);return cmd; } +mutex_unlock (&hdev->mgmt_pending_lock); + +return NULL ; +} + +static struct mgmt_pending_cmd *remove_pairing_by_addr (struct hci_dev *hdev, +bdaddr_t *bdaddr) +{ +struct mgmt_pending_cmd *cmd; +struct hci_conn *conn; + +mutex_lock (&hdev->mgmt_pending_lock); + +list_for_each_entry (cmd, &hdev->mgmt_pending, list) { +if (cmd->opcode !=MGMT_OP_PAIR_DEVICE ) +continue ; + + conn = cmd->user_data; +if (bacmp (bdaddr, &conn->dst) !=0 ) +continue ; + +list_del (&cmd->list); +mutex_unlock (&hdev->mgmt_pending_lock); +return cmd; + } + +mutex_unlock (&hdev->mgmt_pending_lock); +return NULL ; }
@@ -3579,10 +3611,10 @@ void mgmt_smp_complete(struct hci_conn *u8 status = complete ?MGMT_STATUS_SUCCESS :MGMT_STATUS_FAILED ;struct mgmt_pending_cmd *cmd; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (cmd) { cmd->cmd_complete (cmd, status); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } }
@@ -3592,14 +3624,14 @@ static void pairing_complete_cb(struct hBT_DBG ("status %u" , status); - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (!cmd) {BT_DBG ("Unable to find a pending command" );return ; } cmd->cmd_complete (cmd,mgmt_status (status)); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); }static void le_pairing_complete_cb (struct hci_conn *conn,u8 status)
@@ -3611,14 +3643,14 @@ static void le_pairing_complete_cb(strucif (!status)return ; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);if (!cmd) {BT_DBG ("Unable to find a pending command" );return ; } cmd->cmd_complete (cmd,mgmt_status (status)); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -3775,23 +3807,17 @@ static int cancel_pair_device(struct soc goto unlock; } - cmd =pending_find (MGMT_OP_PAIR_DEVICE , hdev); + cmd =remove_pairing_by_addr (hdev, &addr->bdaddr);if (!cmd) { err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE ,MGMT_STATUS_INVALID_PARAMS ); goto unlock; } - conn = cmd->user_data; - -if (bacmp (&addr->bdaddr, &conn->dst) !=0 ) { - err =mgmt_cmd_status (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE , -MGMT_STATUS_INVALID_PARAMS ); - goto unlock; - } + conn =hci_conn_get (cmd->user_data); cmd->cmd_complete (cmd,MGMT_STATUS_CANCELLED ); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); err =mgmt_cmd_complete (sk, hdev->id,MGMT_OP_CANCEL_PAIR_DEVICE ,0 , addr,sizeof (*addr));
@@ -3809,6 +3835,8 @@ static int cancel_pair_device(struct socif (conn->conn_reason ==CONN_REASON_PAIR_DEVICE )hci_abort_conn (conn,HCI_ERROR_REMOTE_USER_TERM ); +hci_conn_put (conn); + unlock:hci_dev_unlock (hdev);return err;
@@ -10135,14 +10163,14 @@ void mgmt_auth_failed(struct hci_conn *c ev.addr.type =link_to_bdaddr (conn->type, conn->dst_type); ev.status = status; - cmd =find_pairing (conn); + cmd =remove_pairing (conn);mgmt_event (MGMT_EV_AUTH_FAILED , conn->hdev, &ev,sizeof (ev), cmd ? cmd->sk :NULL );if (cmd) { cmd->cmd_complete (cmd, status); -mgmt_pending_remove (cmd); +mgmt_pending_free (cmd); } }
Greg Kroah-Hartman
maintainerPATCH 194/396 Bluetooth: hci_sync: Fix advertising data UAFs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit cdc36db204ffd97b947d64374cf23a210dc74777 upstream.
hci_find_adv_instance() returns an adv_info pointer that is valid only while hdev->lock is held. The advertising command-sync paths perform instance lookups without that lock and, in some cases, retain the pointer while waiting for a controller response.
An advertising termination event can therefore interleave as follows:
hci_cmd_sync_work hci_rx_work
hci_find_adv_instance()
__hci_cmd_sync_status()
wait for controller reply hci_dev_lock()
hci_remove_adv_instance()
kfree(adv)
adv->scan_rsp_changed = false
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88 Workqueue: hci0 hci_cmd_sync_work Call Trace: hci_set_ext_scan_rsp_data_sync+0x2e1/0x300 hci_schedule_adv_instance_sync+0x390/0x4c0 hci_cmd_sync_work+0x173/0x300 Allocated by task 87: hci_add_adv_instance+0x538/0xac0 add_advertising+0x885/0x1160 Freed by task 89: kfree+0x131/0x3c0 hci_remove_adv_instance+0x1d8/0x3b0 hci_le_ext_adv_term_evt+0x17b/0x730
Protect the instance lookup and payload construction in the extended advertising, scan response, and periodic advertising data paths. Snapshot the advertising parameters under hdev->lock, but release the lock before waiting for the controller.
Clear advertising-data dirty bits before issuing their commands and restore them after a failure using a fresh lookup. Likewise, update the reported transmit power through a fresh lookup after the parameter command completes. No adv_info pointer then survives an HCI command wait.
--- net/bluetooth/hci_sync.c | 131 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 34 deletions(-)
net/bluetooth/hci_sync.c +97 -34
@@ -1233,10 +1233,11 @@ static int hci_set_adv_set_random_addr_s }static int -hci_set_ext_adv_params_sync (struct hci_dev *hdev,struct adv_info *adv, +hci_set_ext_adv_params_sync (struct hci_dev *hdev,u8 instance,const struct hci_cp_le_set_ext_adv_params *cp,struct hci_rp_le_set_ext_adv_params *rp) { +struct adv_info *adv;struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
@@ -1264,11 +1265,15 @@ hci_set_ext_adv_params_sync(struct hci_dif (!rp->status) { hdev->adv_addr_type = cp->own_addr_type; -if (!cp->handle) { +if (!instance) {/* Store in hdev for instance 0 */ hdev->adv_tx_power = rp->tx_power; - }else if (adv) { - adv->tx_power = rp->tx_power; + }else { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->tx_power = rp->tx_power; +hci_dev_unlock (hdev); } }
@@ -1284,9 +1289,13 @@ static int hci_set_ext_adv_data_sync(strint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->adv_data_changed) +if (!adv || !adv->adv_data_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len = eir_create_adv_data(hdev, instance, pdu->data,
@@ -1297,16 +1306,27 @@ static int hci_set_ext_adv_data_sync(str pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->adv_data_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->adv_data_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -/* Update data if the command succeed */ -if (adv) { - adv->adv_data_changed = false; - }else { +if (!instance) {memcpy (hdev->adv_data, pdu->data, len); hdev->adv_data_len = len; }
@@ -1360,22 +1380,22 @@ int hci_setup_ext_adv_instance_sync(strustruct adv_info *adv;bool secondary_adv; -if (instance >0 ) { - adv =hci_find_adv_instance (hdev, instance); -if (!adv) -return -EINVAL ; - }else { - adv =NULL ; - } -/* Updating parameters of an active instance will return a -* Command Disallowed error, so we must first disable the -* instance if it is active. +* Command Disallowed error, so disable it before taking a snapshot. */ -if (adv) { +if (instance >0 ) { err =hci_disable_ext_adv_instance_sync (hdev, instance);if (err)return err; + +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv) { +hci_dev_unlock (hdev); +return -EINVAL ; + } + }else { + adv =NULL ; } flags =hci_adv_instance_flags (hdev, instance);
@@ -1386,8 +1406,11 @@ int hci_setup_ext_adv_instance_sync(stru connectable = (flags &MGMT_ADV_FLAG_CONNECTABLE ) ||mgmt_get_connectable (hdev); -if (!is_advertising_allowed (hdev, connectable)) +if (!is_advertising_allowed (hdev, connectable)) { +if (instance) +hci_dev_unlock (hdev);return -EPERM ; + }/* Set require_privacy to true only when non-connectable * advertising is used and it is not periodic.
@@ -1398,8 +1421,11 @@ int hci_setup_ext_adv_instance_sync(stru err =hci_get_random_address (hdev, require_privacy,adv_use_rpa (hdev, flags), adv, &own_addr_type, &random_addr); -if (err <0 ) +if (err <0 ) { +if (instance) +hci_dev_unlock (hdev);return err; + }memset (&cp,0 ,sizeof (cp));
@@ -1450,6 +1476,9 @@ int hci_setup_ext_adv_instance_sync(stru cp.channel_map = hdev->le_adv_channel_map; cp.handle = adv ? adv->handle : instance; +if (instance) +hci_dev_unlock (hdev); +if (flags &MGMT_ADV_FLAG_SEC_2M ) { cp.primary_phy =HCI_ADV_PHY_1M ; cp.secondary_phy =HCI_ADV_PHY_2M ;
@@ -1462,12 +1491,12 @@ int hci_setup_ext_adv_instance_sync(stru cp.secondary_phy =HCI_ADV_PHY_1M ; } - err =hci_set_ext_adv_params_sync (hdev, adv, &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev, instance, &cp, &rp);if (err)return err;/* Update adv data as tx power is known now */ - err =hci_set_ext_adv_data_sync (hdev, cp.handle); + err =hci_set_ext_adv_data_sync (hdev, instance);if (err)return err;
@@ -1475,9 +1504,14 @@ int hci_setup_ext_adv_instance_sync(stru own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) && bacmp(&random_addr, BDADDR_ANY)) {/* Check if random address need to be updated */ -if (adv) { -if (!bacmp (&random_addr, &adv->random_addr)) +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (!adv || !bacmp (&random_addr, &adv->random_addr)) { +hci_dev_unlock (hdev);return 0 ; + } +hci_dev_unlock (hdev); }else {if (!bacmp (&random_addr, &hdev->random_addr))return 0 ;
@@ -1499,9 +1533,13 @@ static int hci_set_ext_scan_rsp_data_synint err;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->scan_rsp_changed) +if (!adv || !adv->scan_rsp_changed) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_scan_rsp (hdev, instance, pdu->data);
@@ -1511,15 +1549,27 @@ static int hci_set_ext_scan_rsp_data_syn pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; pdu->frag_pref =LE_SET_ADV_DATA_NO_FRAG ; +if (adv) { + adv->scan_rsp_changed = false; +hci_dev_unlock (hdev); + } + err =__hci_cmd_sync_status (hdev,HCI_OP_LE_SET_EXT_SCAN_RSP_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT ); -if (err) +if (err) { +if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); +if (adv) + adv->scan_rsp_changed = true; +hci_dev_unlock (hdev); + } +return err; + } -if (adv) { - adv->scan_rsp_changed = false; - }else { +if (!instance) {memcpy (hdev->scan_rsp_data, pdu->data, len); hdev->scan_rsp_data_len = len; }
@@ -1534,8 +1584,14 @@ static int __hci_set_scan_rsp_data_sync(memset (&cp,0 ,sizeof (cp)); +if (instance) +hci_dev_lock (hdev); + len =eir_create_scan_rsp (hdev, instance, cp.data); +if (instance) +hci_dev_unlock (hdev); +if (hdev->scan_rsp_data_len == len && !memcmp (cp.data, hdev->scan_rsp_data, len))return 0 ;
@@ -1670,9 +1726,13 @@ static int hci_set_per_adv_data_sync(strstruct adv_info *adv =NULL ;if (instance) { +hci_dev_lock (hdev); + adv =hci_find_adv_instance (hdev, instance); -if (!adv || !adv->periodic) +if (!adv || !adv->periodic) { +hci_dev_unlock (hdev);return 0 ; + } } len =eir_create_per_adv_data (hdev, instance, pdu->data);
@@ -1681,6 +1741,9 @@ static int hci_set_per_adv_data_sync(str pdu->handle = adv ? adv->handle : instance; pdu->operation =LE_SET_ADV_DATA_OP_COMPLETE ; +if (adv) +hci_dev_unlock (hdev); +return __hci_cmd_sync_status (hdev,HCI_OP_LE_SET_PER_ADV_DATA ,struct_size (pdu, data, len), pdu,HCI_CMD_TIMEOUT );
@@ -6449,7 +6512,7 @@ static int hci_le_ext_directed_advertisiif (err)return err; - err =hci_set_ext_adv_params_sync (hdev,NULL , &cp, &rp); + err =hci_set_ext_adv_params_sync (hdev,0 , &cp, &rp);if (err)return err;
Greg Kroah-Hartman
maintainerPATCH 195/396 Bluetooth: HIDP: reject frames without a transaction header
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangho Lee <[email protected]>
commit 47778d2c2087b5d192398f6fddf692d16a5431cf upstream.
hidp_recv_ctrl_frame() and hidp_recv_intr_frame() read skb->data[0] before checking that the L2CAP SDU contains a transaction header. A connected HIDP peer can send an empty basic-mode SDU and make both paths use an uninitialized byte from skb tailroom.
KMSAN reports the use in hidp_session_run(), with the uninitialized value originating in __alloc_skb() through vhci_write(). The control path produces two reports and the interrupt path produces one.
The byte can also be controlled by a malformed lower-layer packet. If an HCI ACL packet contains an L2CAP PDU with a declared zero-length payload followed by an extra 0x15 byte, l2cap_recv_acldata() reduces skb->len to the declared PDU length before dispatch. The current HIDP path nevertheless consumes the extra byte as HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG and terminates the HIDP session. With this change, the same packet is discarded and a subsequent feature report request succeeds.
Pull the transaction header with skb_pull_data() and discard frames that do not contain it.
--- net/bluetooth/hidp/core.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
net/bluetooth/hidp/core.c +15 -10
@@ -563,16 +563,18 @@ static int hidp_process_data(struct hidpstatic void hidp_recv_ctrl_frame (struct hidp_session *session,struct sk_buff *skb) { -unsigned char hdr, type, param; +unsigned char type, param; +u8 *hdr;int free_skb =1 ;BT_DBG ("session %p skb %p len %u" , session, skb, skb->len); - hdr = skb->data[0 ]; -skb_pull (skb,1 ); + hdr =skb_pull_data (skb,1 ); +if (!hdr) + goto free; - type = hdr &HIDP_HEADER_TRANS_MASK ; - param = hdr &HIDP_HEADER_PARAM_MASK ; + type = *hdr &HIDP_HEADER_TRANS_MASK ; + param = *hdr &HIDP_HEADER_PARAM_MASK ;switch (type) {case HIDP_TRANS_HANDSHAKE :
@@ -593,6 +595,7 @@ static void hidp_recv_ctrl_frame(structbreak ; } +free:if (free_skb)kfree_skb (skb); }
@@ -600,14 +603,15 @@ static void hidp_recv_ctrl_frame(structstatic void hidp_recv_intr_frame (struct hidp_session *session,struct sk_buff *skb) { -unsigned char hdr; +u8 *hdr;BT_DBG ("session %p skb %p len %u" , session, skb, skb->len); - hdr = skb->data[0 ]; -skb_pull (skb,1 ); + hdr =skb_pull_data (skb,1 ); +if (!hdr) + goto free; -if (hdr == (HIDP_TRANS_DATA |HIDP_DATA_RTYPE_INPUT )) { +if (*hdr == (HIDP_TRANS_DATA |HIDP_DATA_RTYPE_INPUT )) {hidp_set_timer (session);if (session->input)
@@ -619,9 +623,10 @@ static void hidp_recv_intr_frame(structBT_DBG ("report len %d" , skb->len); } }else { -BT_DBG ("Unsupported protocol header 0x%02x" , hdr); +BT_DBG ("Unsupported protocol header 0x%02x" , *hdr); } +free:kfree_skb (skb); }
Greg Kroah-Hartman
maintainerPATCH 196/396 Bluetooth: HIDP: validate numbered report payloads
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangho Lee <[email protected]>
commit 34f53d27b81a16a02828c8fdfa4e02badc326f17 upstream.
When hidp_get_raw_report() waits for a numbered report, hidp_process_data() compares the expected report number with skb->data[0]. A connected HIDP peer can reply with only a DATA transaction header, leaving the skb empty after the header is removed.
KMSAN reports an uninitialized-value use in hidp_session_run(), with the value originating in __alloc_skb() through vhci_write(). The transaction header checks remove the empty-frame reports, but this report remains until the payload check is added.
The comparison can also consume a peer-controlled byte beyond the declared L2CAP PDU. A DATA | FEATURE response followed by an extra 0x01 byte made the current code accept that byte as report ID 1 and complete HIDIOCGFEATURE with a zero-byte result. With this change the malformed response is rejected with -EIO, while a subsequent valid response still succeeds.
Require a payload byte before comparing a numbered report ID. Unnumbered reports continue to accept an empty payload.
--- net/bluetooth/hidp/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/bluetooth/hidp/core.c +3 -2
@@ -546,9 +546,10 @@ static int hidp_process_data(struct hidp }if (test_bit (HIDP_WAITING_FOR_RETURN , &session->flags) && - param == session->waiting_report_type) { + param == session->waiting_report_type) {if (session->waiting_report_number <0 || - session->waiting_report_number == skb->data[0 ]) { + (skb->len && + session->waiting_report_number == skb->data[0 ])) {/* hidp_get_raw_report() is waiting on this report. */ session->report_return = skb; done_with_skb =0 ;
Greg Kroah-Hartman
maintainerPATCH 197/396 bpf: lwt: Fix dst reference leak on reroute failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit 88c17de85ddb459c3fe1e3c65d61fa366b1cf0a8 upstream.
bpf_lwt_xmit_reroute() obtains a referenced dst from the route lookup. When skb_cow_head() fails before that dst is installed on the skb, the error path only frees the skb. The skb still owns its previous dst, so the newly looked up dst reference is leaked.
Release the new dst reference before freeing the skb on this error path.
--- net/core/lwt_bpf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/lwt_bpf.c +3 -1
@@ -251,8 +251,10 @@ static int bpf_lwt_xmit_reroute(struct s* if there is enough header space in skb. */ err =skb_cow_head (skb,LL_RESERVED_SPACE (dst->dev)); -if (unlikely (err)) +if (unlikely (err)) { +dst_release (dst); goto err; + }skb_dst_drop (skb);skb_dst_set (skb, dst);
Greg Kroah-Hartman
maintainerPATCH 198/396 afs: Fix afs_fs_fetch_data() to set call->async
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit d568a43f6dbba3ba006304d95fd09862bd482a2f upstream.
Fix afs_fs_fetch_data() to set call->async on an async operation as does afs_fs_fetch_data64().
--- fs/afs/fsclient.c | 3 +++ 1 file changed, 3 insertions(+)
fs/afs/fsclient.c +3 -0
@@ -477,6 +477,9 @@ void afs_fs_fetch_data(struct afs_operatif (!call)return afs_op_nomem (op); +if (op->flags &AFS_OPERATION_ASYNC ) + call->async = true; +/* marshall the parameters */ bp = call->request; bp[0 ] =htonl (FSFETCHDATA );
Greg Kroah-Hartman
maintainerPATCH 199/396 afs: Fix afs_fs_fetch_data() to subtract transferred from len
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit 222052c6be186f2074b3a4d741d5de200f654c43 upstream.
Fix afs_fs_fetch_data() to subtract subreq->transferred from subreq->len rather than adding it.
--- fs/afs/fsclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/fsclient.c +1 -1
@@ -487,7 +487,7 @@ void afs_fs_fetch_data(struct afs_operation *op) bp[2 ] =htonl (vp->fid.vnode); bp[3 ] =htonl (vp->fid.unique); bp[4 ] =htonl (lower_32_bits (subreq->start + subreq->transferred)); - bp[5 ] =htonl (lower_32_bits (subreq->len + subreq->transferred)); + bp[5 ] =htonl (lower_32_bits (subreq->len - subreq->transferred)); call->fid = vp->fid;trace_afs_make_fs_call (call, &vp->fid);
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 200/396 afs: Fix UAF when sending a message
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit 4af1ec68d54b3871155914d584fb10669c41a861 upstream.
In afs_make_call(), there's a race with async call reception and destruction. If a call is dispatched that doesn't have call->write_iter set (used to specify the data content for FS.StoreData), then the first rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr.
Once rxrpc_send_data() queues the last request packet, the response could come in at any time and cause the call to be completed and put. However, afs_make_call() will look at the call again to see it ->write_iter should be handled - something it's only allowed to do if it has its own ref on the call. Whilst this is the case for synchronous calls, it isn't true for async calls such as FS.FetchData.
There's also a potential UAF in afs_make_call() in the event that an asynchronous call is being sent, but the call fails in some way (e.g. it gets aborted from the server). The problem there is that afs_make_call() tries to abort a call if the rxrpc send fails, but the asynchronous notification from rxrpc may have caused the afs_call to be torn down.
generic/650 plays games with randomly taking CPUs offline, and can interject a significant delay such that the call is deallocated before afs_make_call() gets to check call->write_iter - and a UAF ensues (caught by KASAN).
BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs] Read of size 8 at addr ffff888035e050e8 by task fsstress/1409
Fix this by making afs_make_op_call() give the op->call its own ref rather than transferring the caller's ref to it and then dropping the ref when afs_make_call() returns.
This also means that the afs_make_call() func never loses its ref on the call now.
--- fs/afs/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/afs/internal.h +2 -1
@@ -1420,7 +1420,7 @@ static inline void afs_make_op_call(stru {struct afs_addr_list *alist = op->estate->addresses; - op->call = call; + op->call =afs_get_call (call, afs_call_trace_get); op->type = call->type; call->op = op; call->key = op->key;
@@ -1428,6 +1428,7 @@ static inline void afs_make_op_call(stru call->peer =rxrpc_kernel_get_peer (alist->addrs[op->addr_index].peer); call->service_id = op->server->service_id;afs_make_call (call, gfp); +afs_put_call (call); }static inline void afs_extract_begin (struct afs_call *call,void *buf,size_t size)
Greg Kroah-Hartman
maintainerPATCH 201/396 ALSA: 6fire: Fix UAF at error handling during probe
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit a54bf16965f896415c3337bc4fbb40fb11941d99 upstream.
Although 6fire driver had a few fixes for dealing with the early error handling during the probe phase, it forgot a pending URB before freeing the resources, which may lead to a UAF.
This patch addresses it by doing the almost same cleanup procedure like the normal disconnect phase at the error path.
--- sound/usb/6fire/chip.c | 4 ++++ 1 file changed, 4 insertions(+)
sound/usb/6fire/chip.c +4 -0
@@ -156,6 +156,10 @@ static int usb6fire_chip_probe(struct usreturn 0 ; destroy_chip: + chip->shutdown = true; +if (card) +snd_card_disconnect (card); +usb6fire_chip_abort (chip);snd_card_free (card);return ret; }
Greg Kroah-Hartman
maintainerPATCH 202/396 ALSA: hda/realtek: Add quirk for TongFang X6SP45xU
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eckhart Mohr <[email protected]>
commit 26a94400ffa4fcbeff32e23abebb83a1a20eb401 upstream.
TongFang X6KK45xU and X6SP45xU have actually different PCI IDs. This patch Adds the missing PCI ID to fix headphone detection and clarifies the naming.
--- sound/hda/codecs/realtek/alc269.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
sound/hda/codecs/realtek/alc269.c +2 -1
@@ -7560,7 +7560,8 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x1d05 ,0x300f ,"TongFang X6AR5xxY" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d05 ,0x3019 ,"TongFang X6FR5xxY" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d05 ,0x3031 ,"TongFang X6AR55xU" ,ALC2XX_FIXUP_HEADSET_MIC ), -SND_PCI_QUIRK (0x1d05 ,0x3034 ,"TongFang X6xx45xU" ,ALC2XX_FIXUP_HEADSET_MIC ), +SND_PCI_QUIRK (0x1d05 ,0x3033 ,"TongFang X6SP45xU" ,ALC2XX_FIXUP_HEADSET_MIC ), +SND_PCI_QUIRK (0x1d05 ,0x3034 ,"TongFang X6KK45xU" ,ALC2XX_FIXUP_HEADSET_MIC ),SND_PCI_QUIRK (0x1d17 ,0x3288 ,"Haier Boyue G42" ,ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS ),SND_PCI_QUIRK (0x1d72 ,0x1602 ,"RedmiBook" ,ALC255_FIXUP_XIAOMI_HEADSET_MIC ), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
Greg Kroah-Hartman
maintainerPATCH 203/396 ALSA: lx6464es: fix period byte count for 16-bit streams
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 6437033bffe8bd2af174d139af552d90d40c7ac6 upstream.
The lx6464es driver advertises both 16-bit and packed 24-bit PCM formats, but lx_trigger_start() and lx_interrupt_request_new_buffer() calculate the DMA period size as runtime->period_size * runtime->channels * 3. That is only correct for the packed 24-bit formats.
For 16-bit streams the driver submits buffers that are 50% larger than the actual ALSA period and advances the DMA address by the same wrong amount. For example, with 2 channels, 256 frames and 4 periods, the third buffer already extends beyond the ALSA buffer and the fourth buffer starts outside it.
Use snd_pcm_lib_period_bytes() so the byte count matches the runtime format, channel count and period size.
--- sound/pci/lx6464es/lx6464es.c | 5 +---- sound/pci/lx6464es/lx_core.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-)
sound/pci/lx6464es/lx6464es.c +1 -4
@@ -402,11 +402,8 @@ static void lx_trigger_start(struct lx64int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size;const u32 periods = substream->runtime->periods; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);dma_addr_t buf = substream->dma_buffer.addr;int i;
sound/pci/lx6464es/lx_core.c +1 -4
@@ -969,10 +969,7 @@ static int lx_interrupt_request_new_buffconst unsigned int is_capture = lx_stream->is_capture;int err; -const u32 channels = substream->runtime->channels; -const u32 bytes_per_frame = channels *3 ; -const u32 period_size = substream->runtime->period_size; -const u32 period_bytes = period_size * bytes_per_frame; +const u32 period_bytes =snd_pcm_lib_period_bytes (substream);const u32 pos = lx_stream->frame_pos;const u32 next_pos = ((pos+1 ) == substream->runtime->periods) ?0 : pos +1 ;
Greg Kroah-Hartman
maintainerPATCH 204/396 ALSA: pcm: wake linked drain waiters on unlink
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit f495b6c4c8594122918552c9be2b51eb71647cd9 upstream.
snd_pcm_drain() on a linked stream parks an on-stack wait entry on the drained peer's runtime->sleep, and after schedule_timeout() removes it only if that peer is still found in the caller's group. If group membership changes during the wait and the sleep ends by signal or timeout (so autoremove_wake_function() does not run), finish_wait() is skipped and snd_pcm_drain() returns with the entry still queued on that stream's sleep list; a later wake_up() then walks a freed stack frame. This is reachable by unlinking either the drained or the draining stream.
Unlike the close path (snd_pcm_drop() -> snd_pcm_post_stop()), snd_pcm_unlink() never wakes the sleep queues. Wake every group member under the group lock before the membership change, so a linked drainer is released and drops its entry while the streams are still grouped.
The window was opened when snd_pcm_link_rwsem stopped being held across the wait and the removal became conditional on group membership (see Fixes). The later switch to finish_wait() kept that conditional removal, so the signal/timeout case remained.
--- sound/core/pcm_native.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/core/pcm_native.c +7 -0
@@ -2334,6 +2334,7 @@ static void relink_to_local(struct snd_pstatic int snd_pcm_unlink (struct snd_pcm_substream *substream) { +struct snd_pcm_substream *s;struct snd_pcm_group *group;bool nonatomic = substream->pcm->nonatomic;bool do_free = false;
@@ -2346,6 +2347,12 @@ static int snd_pcm_unlink(struct snd_pcm group = substream->group;snd_pcm_group_lock_irq (group, nonatomic); +/* release drain waiters before changing membership, else snd_pcm_drain() +* leaves its on-stack wait entry queued on a member's sleep list +*/ +snd_pcm_group_for_each_entry (s, substream) +wake_up (&s->runtime->sleep); +relink_to_local (substream);refcount_dec (&group->refs);
Greg Kroah-Hartman
maintainerPATCH 205/396 ALSA: seq: Fix division by zero in initialize_timer()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 21e19688433452dfbbbe6b2bb670dea6eb92f0f6 upstream.
A userspace-driven ALSA timer (SND_UTIMER) lets an unprivileged user set the backing snd_timer's hardware resolution to an arbitrary 64-bit value via SNDRV_TIMER_IOCTL_CREATE. snd_utimer_create() only rejects zero.
When such a timer is bound to a sequencer queue, initialize_timer() computes the tick period as
tmr->ticks = 1000000000 / (r * freq);
where r is that user-controlled resolution and freq is the sequencer update rate in Hz, clamped to MIN_FREQUENCY..MAX_FREQUENCY (10..6250). A resolution of 2^63 makes the 64-bit product r * freq wrap to zero for any even freq, including DEFAULT_FREQUENCY (1000), so the division faults with a divide-by-zero.
The division runs under tmr->lock with interrupts disabled, so the oops leaves the spinlock held and hangs the CPU. It is reachable by an unprivileged user with access to /dev/snd/timer and /dev/snd/seq.
Oops: divide error: 0000 [#1] SMP KASAN PTI CPU: 7 UID: 1000 PID: 456 Comm: alsa_seq_utimer Not tainted 7.2.0-rc4+ RIP: 0010:initialize_timer.constprop.0+0x20a/0x2d0 snd_seq_timer_start+0x15e/0x2b0 snd_seq_control_queue+0x56f/0xba0 snd_seq_write+0x3e0/0x730
Reject an overflowing product with check_mul_overflow() and fall back to a single tick, which also avoids feeding a wrapped-but-nonzero divisor (e.g. 2^63 * 1000 mod 2^64 == 0, or other resolutions wrapping to a small value) into the period computation.
--- sound/core/seq/seq_timer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
sound/core/seq/seq_timer.c +4 -5
@@ -362,11 +362,10 @@ static int initialize_timer(struct snd_s tmr->ticks =1 ;if (!(t->hw.flags &SNDRV_TIMER_HW_SLAVE )) {unsigned long r =snd_timer_resolution (tmr->timeri); -if (r) { - tmr->ticks = (unsigned int )(1000000000uL / (r * freq)); -if (! tmr->ticks) - tmr->ticks =1 ; - } +unsigned long den; + +if (r && !check_mul_overflow (r, freq, &den)) + tmr->ticks =max (1U , (unsigned int )(1000000000uL / den)); } tmr->initialized =1 ;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 206/396 ALSA: timer: Clear SNDRV_TIMER_IFLG_DEAD once the close completes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit c2744d5f3aea474513fd2298daecb94a952ce441 upstream.
snd_timer_close_locked() marks an instance with SNDRV_TIMER_IFLG_DEAD and returns early when the flag is already set, but the flag is never cleared again. A completed close ends in remove_slave_links(), which leaves timeri->timer NULL, so a second close is already harmless through the timer == NULL path; the early return can only be reached by an instance that was opened again in between. For such an instance the close unlinks nothing, so snd_timer_instance_free() frees an object that is still on timer->open_list_head, still on snd_timer_master_list if it was opened with a slave key, still owns any adopted slaves, and still holds its timer and module references.
snd_seq_timer_open() reopens an instance exactly like that: it retries its fallback open on the same object after a failure that has already run snd_timer_close_locked() internally. An unprivileged user with access to /dev/snd/timer and /dev/snd/seq can force that failure, since snd_timer_check_master() returns -EBUSY when a pending slave matches the new master's (slave_class, slave_id) key and the target timer has reached max_instances, and SNDRV_TIMER_IOCTL_SELECT with dev_class = SNDRV_TIMER_CLASS_SLAVE keeps the caller-supplied dev_sclass, so a sequencer queue's key can be forged. The freed instance is afterwards dereferenced by any further snd_timer_open() on that timer, by snd_timer_check_slave(), and by /proc/asound/timers, which faults on the stale ti->owner pointer.
The flag only has to be visible while the close is in progress, which is all its other users need. Clear it in remove_slave_links(), under the same timer->lock that sets it, once the instance is off every list.
--- sound/core/timer.c | 2 ++ 1 file changed, 2 insertions(+)
sound/core/timer.c +2 -0
@@ -409,6 +409,8 @@ static void remove_slave_links(struct snlist_del_init (&slave->ack_list);list_del_init (&slave->active_list); } +/* the close is done; a reopen must not see the mark */ + timeri->flags &= ~SNDRV_TIMER_IFLG_DEAD ; }/*
Greg Kroah-Hartman
maintainerPATCH 207/396 ALSA: ump: fix double free of out_cvts on rawmidi error
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 70c977815af0d997feb2d0c5d284d55689bf7051 upstream.
snd_ump_attach_legacy_rawmidi() allocates the legacy conversion array ump->out_cvts and, on the snd_rawmidi_new() error path, frees it with kfree() but leaves ump->out_cvts pointing at the freed memory. When the endpoint is later torn down, snd_ump_endpoint_free() frees ump->out_cvts a second time, resulting in a double free.
The host snd-usb-audio driver attaches the legacy rawmidi for any USB MIDI 2.0 (UMP) device, so a device that makes snd_rawmidi_new() fail reaches this path on enumeration.
Clear ump->out_cvts after freeing it on the error path so it is not freed again during teardown.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/core/ump.c | 1 + 1 file changed, 1 insertion(+)
sound/core/ump.c +1 -0
@@ -1366,6 +1366,7 @@ int snd_ump_attach_legacy_rawmidi(struct &rmidi);if (err <0 ) {kfree (ump->out_cvts); + ump->out_cvts =NULL ;return err; }
Greg Kroah-Hartman
maintainerPATCH 208/396 ASoC: fsl_asrc: fix m2m_init error path to use goto instead of bare return
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
commit 890b4253134f3a39883af7d5bea67af9c494c56d upstream.
When fsl_asrc_m2m_init() fails in fsl_asrc_probe(), the code did a bare return ret, bypassing pm_runtime_disable() in err_pm_get_sync. Use goto err_pm_get_sync to ensure proper cleanup on failure.
--- sound/soc/fsl/fsl_asrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_asrc.c +1 -1
@@ -1388,7 +1388,7 @@ static int fsl_asrc_probe(struct platfor ret =fsl_asrc_m2m_init (asrc);if (ret) {dev_err (&pdev->dev,"failed to init m2m device %d\n" , ret); -return ret; + goto err_pm_get_sync; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 209/396 ASoC: fsl_easrc: fix m2m_init error path to use goto instead of bare return
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
commit a54bc0eef90ea760039c14bb7f3b5db42529f84d upstream.
When fsl_asrc_m2m_init() fails in fsl_easrc_probe(), the code did a bare return ret, bypassing pm_runtime_disable() in err_pm_disable. Use goto err_pm_disable to ensure proper cleanup on failure.
--- sound/soc/fsl/fsl_easrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/fsl/fsl_easrc.c +1 -1
@@ -2266,7 +2266,7 @@ static int fsl_easrc_probe(struct platfo ret =fsl_asrc_m2m_init (easrc);if (ret) {dev_err (&pdev->dev,"failed to init m2m device %d\n" , ret); -return ret; + goto err_pm_disable; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 210/396 ASoC: tas2562: fix DVC coefficient write order
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit 8e957e4907c58e9ca944f98799524f2bbb9cf68a upstream.
The TAS2562 applies the 32-bit digital volume coefficient to the playback path when the last byte, DVC_CFG4 (book 0 page 2 reg 0x0F), is written. tas2562_volume_control_put() wrote DVC_CFG4 first and DVC_CFG1 (the MSB) last, so every volume change latched a value made of the previous coefficient's upper three bytes combined with the new LSB; the remaining bytes only took effect on the next volume change.
In practice the control was unusable: the first setting after power-on always played at roughly 0 dB no matter what value was requested (the chip's default upper bytes were still latched), and most subsequent changes muted the output entirely or produced a distorted, over-unity gain.
Verified on a TAS2562 (ADLINK OSM-520 / MT8189 board) by tracing the I2C writes with ftrace and by writing the same coefficients manually in both byte orders: written MSB-first the register block behaves exactly as the driver expects, LSB-first reproduces the broken behaviour.
Write the bytes MSB first with DVC_CFG4 last so the complete new coefficient is latched atomically.
--- sound/soc/codecs/tas2562.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
sound/soc/codecs/tas2562.c +15 -8
@@ -475,20 +475,27 @@ static int tas2562_volume_control_put(stu32 reg_val; reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , - (reg_val &0xff )); -if (ret) -return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , - ((reg_val >>8 ) &0xff )); +/* +* The device applies the 32-bit coefficient to the playback path on +* the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the +* bytes must be written MSB first and DVC_CFG4 last. Writing CFG4 +* first latches a mix of the previous coefficient's upper bytes and +* the new LSB instead of the requested value. +*/ + ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , + ((reg_val >>24 ) &0xff ));if (ret)return ret; ret =snd_soc_component_write (component,TAS2562_DVC_CFG2 , ((reg_val >>16 ) &0xff ));if (ret)return ret; - ret =snd_soc_component_write (component,TAS2562_DVC_CFG1 , - ((reg_val >>24 ) &0xff )); + ret =snd_soc_component_write (component,TAS2562_DVC_CFG3 , + ((reg_val >>8 ) &0xff )); +if (ret) +return ret; + ret =snd_soc_component_write (component,TAS2562_DVC_CFG4 , + (reg_val &0xff ));if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 211/396 ASoC: tas2562: fix broken entries in the volume lookup table
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haidar Lee <[email protected]>
commit bdb0fd6de403fcea7b85dc9d38f0a571583ebe80 upstream.
The float_vol_db_lookup table is supposed to hold round(10^(dB/20) * 2^30) for every 2 dB step from -110 dB to 0 dB, which is 56 entries, but it only has 55: the -90 dB entry duplicates the -92 dB value (0x0000695b) and the -20 dB entry (0x06666666) is missing altogether. As a result every step between -90 dB and -22 dB is off by 2 dB, and the control's maximum raw value of 110 indexes one element past the end of the array.
Replace the duplicated -90 dB entry with the correct value 0x000084a3 and add the missing -20 dB entry, bringing the table to the full 56 entries so index 55 (raw value 110, 0 dB) is in range again.
--- sound/soc/codecs/tas2562.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
sound/soc/codecs/tas2562.c +4 -3
@@ -32,15 +32,16 @@static const unsigned int float_vol_db_lookup[] = {0x00000d43 ,0x000010b2 ,0x00001505 ,0x00001a67 ,0x00002151 ,0x000029f1 ,0x000034cd ,0x00004279 ,0x000053af ,0x0000695b , -0x0000695b ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a , +0x000084a3 ,0x0000a6fa ,0x0000d236 ,0x000108a4 ,0x00014d2a ,0x0001a36e ,0x00021008 ,0x000298c0 ,0x000344df ,0x00041d8f ,0x00052e5a ,0x000685c8 ,0x00083621 ,0x000a566d ,0x000d03a7 ,0x0010624d ,0x0014a050 ,0x0019f786 ,0x0020b0bc ,0x0029279d ,0x0033cf8d ,0x004139d3 ,0x00521d50 ,0x00676044 ,0x0082248a ,0x00a3d70a ,0x00ce4328 ,0x0103ab3d ,0x0146e75d ,0x019b8c27 ,0x02061b89 ,0x028c423f ,0x03352529 ,0x0409c2b0 ,0x05156d68 , -0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 ,0x143d1362 , -0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 ,0x40000000 +0x06666666 ,0x080e9f96 ,0x0a24b062 ,0x0cc509ab ,0x10137987 , +0x143d1362 ,0x197a967f ,0x2013739e ,0x28619ae9 ,0x32d64617 , +0x40000000 };struct tas2562_data {
Greg Kroah-Hartman
maintainerPATCH 212/396 ata: libata-eh: Increase STANDBY IMMEDIATE timeout
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Vollrath <[email protected]>
commit 1e024d2b41ee32bc06818f7f09a3562c58842cf9 upstream.
Correct a previous change (see Fixes) which reduced the standby timeout from 30 to 5 seconds. Increase it to 15 seconds.
I was troubleshooting an error spotted during system suspend:
[ 1217.152867] ata1.00: Entering standby power mode
[ 1222.322948] ata1.00: qc timeout after 5000 msecs (cmd 0xe0)
[ 1222.324010] ata1.00: STANDBY IMMEDIATE failed (err_mask=0x4)This drive is a Samsung 870 EVO SSD in good SMART standing, and I wasn't aware of any reason it should be taking so long to standby. The issue is intermittent, but I observed it sometimes taking 7 seconds to manually standby. I assume this was interruption of background maintenance after a power outage.
As a desktop user, I would prefer to wait the extra 2 seconds at suspend to let the drive finish its business rather than drop the rails from under it.
The change from 30 to 5 seconds was implicit when switching suspend from START STOP UNIT to an internal command with no timeout table entry. No reason was stated for the change.
--- drivers/ata/libata-eh.c | 8 ++++++++ include/linux/libata.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/ata/libata-eh.c +8 -0
@@ -106,6 +106,12 @@ static const unsigned int ata_eh_flush_t UINT_MAX, }; +static const unsigned int ata_eh_standby_timeouts[] = { +15000 ,/* Some drives may be slow to standby */ +/* but don't hold up a suspend too long waiting for them */ +UINT_MAX , +}; +static const unsigned int ata_eh_other_timeouts[] = {5000 ,/* same rationale as identify timeout */ 10000 ,/* ditto */
@@ -147,6 +153,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIME .timeouts = ata_eh_other_timeouts, }, { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT), .timeouts = ata_eh_flush_timeouts }, + { .commands = CMDS(ATA_CMD_STANDBYNOW1), + .timeouts = ata_eh_standby_timeouts }, { .commands = CMDS(ATA_CMD_VERIFY), .timeouts = ata_eh_reset_timeouts }, };
include/linux/libata.h +1 -1
@@ -389,7 +389,7 @@ enum {/* This should match the actual table size of * ata_eh_cmd_timeout_table in libata-eh.c. */ - ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 8, + ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 9,/* * Quirk flags: may be set by libata or controller drivers on drives.
Greg Kroah-Hartman
maintainerPATCH 213/396 ata: libata-sata: fix ata_scsi_lpm_supported() iteration
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Cassel <[email protected]>
commit 3fd70e96914d761c17c376aadd0b0d1a3c9badba upstream.
The inner loop of ata_scsi_lpm_supported() uses the wrong variable when iterating.
It should obviously use the link that we are currently iterating over, rather than always using the host link.
ata_scsi_lpm_supported() is used to control if a user should be allowed to change lpm policy (from the default) via sysfs.
Thus, this bug could potentially disallow users to change the LPM policy for certain SATA devices via sysfs.
--- drivers/ata/libata-sata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ata/libata-sata.c +1 -1
@@ -913,7 +913,7 @@ static bool ata_scsi_lpm_supported(strucreturn false;ata_for_each_link (link, ap,EDGE ) { -ata_for_each_dev (dev, &ap->link,ENABLED ) { +ata_for_each_dev (dev, link,ENABLED ) {if (dev->quirks &ATA_QUIRK_NOLPM )return false; }
Greg Kroah-Hartman
maintainerPATCH 214/396 ALSA: usb-audio: fix use-after-free in ump_to_endpoint()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 4a05b2d1b4642df74f30b6f54843e825c4a2bfd3 upstream.
create_midi2_ump() registers a card-owned snd_ump_endpoint and stores a back-pointer to its per-interface snd_usb_midi2_ump object in ump->private_data, but it never installs an ump->private_free hook and never clears that pointer.
If a later step of snd_usb_midi_v2_create() fails, its error path calls free_all_midi2_umps(), which kfree()s the snd_usb_midi2_ump object while the already-registered endpoint keeps pointing at it. The created /dev/snd/umpC*D* node stays exposed, so the first operation of any UMP open, ump_to_endpoint(), dereferences the dangling ump->private_data and reads rmidi->eps[dir] out of freed memory.
A malicious USB MIDI 2.0 device that makes creation fail after the endpoint is registered can thus trigger a slab use-after-free read on a subsequent open of the UMP node.
Clear the endpoint's back-pointer before freeing the object, and let ump_to_endpoint() tolerate a NULL private_data so the open/close/trigger callbacks fail cleanly (their callers already handle a NULL endpoint) instead of dereferencing a stale pointer.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/midi2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/usb/midi2.c +3 -1
@@ -329,7 +329,7 @@ ump_to_endpoint(struct snd_ump_endpoint {struct snd_usb_midi2_ump *rmidi = ump->private_data; -return rmidi->eps[dir]; +return rmidi ? rmidi->eps[dir] :NULL ; }/* ump open callback */
@@ -685,6 +685,8 @@ static void free_all_midi2_umps(struct s rmidi =list_first_entry (&umidi->rawmidi_list, struct snd_usb_midi2_ump, list);list_del (&rmidi->list); +if (rmidi->ump) + rmidi->ump->private_data =NULL ;kfree (rmidi); } }
Greg Kroah-Hartman
maintainerPATCH 215/396 ALSA: usb-audio: fix stack info leak in RME Digiface status
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 441aaad150c57edaf57ee482a79a3bf4c5b7e353 upstream.
snd_rme_digiface_read_status() reads a four-word status block from the device into an uninitialised on-stack __le32 buf[4] and, whenever the vendor control-IN transfer does not return a negative error, copies all four words into the caller's status[].
snd_usb_ctl_msg() copies the full requested size back into the caller's buffer regardless of how many bytes the data stage actually delivered:
buf = kmemdup(data, size, GFP_KERNEL); err = usb_control_msg(dev, pipe, request, requesttype, value, index, buf, size, timeout); memcpy(data, buf, size);
usb_control_msg() returns the transferred length on a short control-IN, which is a non-negative value, and writes only that many bytes. The remainder of the copy back is the kmemdup()ed image of the caller's buffer, so a device answering with a short data stage leaves the trailing words of buf[] holding leftover kernel stack. The only guard in the caller is err < 0, so those words are stored into status[].
They then reach user space: snd_rme_digiface_get_status_val() selects a 16-bit halfword of status[] per the control's reg/mask, and the eight Digiface status controls together expose the whole 16-byte frame to an unprivileged reader of /dev/snd/controlC*.
Zero-initialise the buffer so a short read yields zeros instead of stack residue. This mirrors snd_rme_get_status1(), which already clears its output word before the same kind of vendor read.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/mixer_quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/usb/mixer_quirks.c +1 -1
@@ -3352,7 +3352,7 @@ static int snd_rme_digiface_read_status(struct usb_mixer_elem_list *list =snd_kcontrol_chip (kcontrol);struct snd_usb_audio *chip = list->mixer->chip;struct usb_device *dev = chip->dev; -__le32 buf[4 ]; +__le32 buf[4 ] = {};int err; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
Greg Kroah-Hartman
maintainerPATCH 216/396 ALSA: usb-audio: fix OOB write in snd_usbmidi_akai_output()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 0970274613fb463d376211450cab066d34ebfe6a upstream.
snd_usbmidi_akai_output() computes its fill-loop bound
buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
as a signed int, so a small device-advertised bulk-OUT max_transfer makes buf_end negative. The loop guard then compares the u32 urb->transfer_buffer_length against that negative int: the usual arithmetic conversion turns buf_end into a large unsigned value, so the guard stays true and each iteration keeps appending SysEx framing and payload bytes past the end of the URB transfer buffer, which is only max_transfer bytes long.
A USB device that advertises a tiny bulk-OUT endpoint can therefore trigger an attacker-length- and content-controlled heap out-of-bounds write when a process writes to the created /dev/snd/midiC*D* node.
Return early when there is no room for even one SysEx, so the loop is never entered with a bound that would wrap. The loop is the last statement of the function, so bailing out is equivalent to it not running.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/midi.c | 2 ++ 1 file changed, 2 insertions(+)
sound/usb/midi.c +2 -0
@@ -793,6 +793,8 @@ static void snd_usbmidi_akai_output(stru msg = urb->transfer_buffer + urb->transfer_buffer_length; buf_end = ep->max_transfer -MAX_AKAI_SYSEX_LEN -1 ; +if (buf_end <=0 ) +return ;/* only try adding more data when there's space for at least 1 SysEx */ while (urb->transfer_buffer_length < buf_end) {
Greg Kroah-Hartman
maintainerPATCH 217/396 ALSA: usb-audio: Fix DMA buffer out-of-bounds write when fill_max is set
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 d0199ae1666ff9ae2d1d568d64c3430d4c47f0e5 upstream.
When a USB audio endpoint requests full packet transfers via the fill_max descriptor flag, data_ep_set_params() promotes ep->curpacksize to ep->maxpacksize. However, maxsize is left at the original sample-rate derived value.
Since u->buffer_size is allocated as maxsize * packets, the resulting DMA buffer is far too small for the requested transfer length. When the USB host controller streams up to curpacksize bytes per packet, it writes past the end of the buffer via DMA, corrupting kernel heap memory.
Update maxsize to curpacksize when fill_max is set so that the allocated DMA buffer size matches the actual transfer request size.
[ changed to reassign maxsize only when ep->fill_max is set -- tiwai ]
--- sound/usb/endpoint.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
sound/usb/endpoint.c +4 -2
@@ -1164,10 +1164,12 @@ static int data_ep_set_params(struct snd << (16 - ep->datainterval); } -if (ep->fill_max) +if (ep->fill_max) { ep->curpacksize = ep->maxpacksize; -else + maxsize = ep->curpacksize; + }else { ep->curpacksize = maxsize; + }if (snd_usb_get_speed (chip->dev) !=USB_SPEED_FULL ) { packs_per_ms =8 >> ep->datainterval;
Greg Kroah-Hartman
maintainerPATCH 218/396 ALSA: usb-audio: Clamp frame size in implicit-feedback mode
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 8d7a30c50c2e58a6839634ed0acde14466d1dc61 upstream.
snd_usb_handle_sync_urb() scales received sync packet sizes by the sender's stride and stores the result directly in out_packet->packet_size[i]. If a connected USB device sends an oversized sync packet, this frame count can exceed ep->maxframesize.
The un-clamped frame count then propagates to the playback endpoint queue, potentially driving packet transfers beyond the endpoint's hardware frame limits.
Cap the calculated frame count against ep->maxframesize in snd_usb_handle_sync_urb() to prevent oversized packets from entering the playback queue.
--- sound/usb/endpoint.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +5 -3
@@ -1806,11 +1806,13 @@ static void snd_usb_handle_sync_urb(stru out_packet->packets = in_ctx->packets;for (i =0 ; i < in_ctx->packets; i++) { -if (urb->iso_frame_desc[i].status ==0 ) - out_packet->packet_size[i] = +if (urb->iso_frame_desc[i].status ==0 ) { +unsigned int frames = urb->iso_frame_desc[i].actual_length / sender->stride; -else + out_packet->packet_size[i] =min (frames, ep->maxframesize); + }else { out_packet->packet_size[i] =0 ; + } }spin_unlock_irqrestore (&ep->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 219/396 dmaengine: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Md Sadre Alam <[email protected]>
commit 867621ba203027338b525af6729719c544135336 upstream.
BAM version 1.6.0 and later changed the behavior of the mask field in command elements for read operations.
In older BAM versions, or prior implementation assumptions, the mask field was effectively ignored for read commands. However, starting from BAM v1.6.0, the mask field for read commands is repurposed to carry the upper 4 bits of the destination address, enabling support for 36-bit addressing. For write commands, the mask field continues to function as a traditional write mask.
The current driver sets mask = 0xffffffff for all command elements. While this works for write operations, it breaks read operations on BAM v1.6.0+ hardware. In such cases, the hardware interprets the upper address bits as 0xf, resulting in an invalid destination address (0xf_xxxxxxxx instead of 0x0_xxxxxxxx).
This leads to failures such as NAND enumeration issues observed on platforms like IPQ5424.
Fix this by assigning the mask field based on command type:
- For read commands: set mask = 0 (upper address bits = 0)
- For write commands: retain mask = 0xffffffff
Also update the bam_cmd_element structure documentation to reflect the dual purpose of the mask field across BAM versions.
This ensures correct behavior on BAM v1.6.0+ while maintaining backward compatibility with older hardware.
--- include/linux/dma/qcom_bam_dma.h | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
include/linux/dma/qcom_bam_dma.h +16 -5
@@ -13,9 +13,12 @@* supported by BAM DMA Engine. * * @cmd_and_addr - upper 8 bits command and lower 24 bits register address. -* @data - for write command: content to be written into peripheral register. -* for read command: dest addr to write peripheral register value. -* @mask - register mask. +* @data - For write command: content to be written into peripheral register. +* For read command: lower 32 bits of destination address. +* @mask - For write command: register write mask. +* For read command on BAM v1.6.0+: upper 4 bits of destination address. +* For read command on BAM < v1.6.0: ignored by hardware. +* Setting to 0 ensures 32-bit addressing compatibility. * @reserved - for future usage. * */
@@ -42,6 +45,10 @@ enum bam_command_type {* @addr: target address * @cmd: BAM command * @data: actual data for write and dest addr for read in le32 +* +* For BAM v1.6.0+, the mask field behavior depends on command type: +* - Write commands: mask = write mask (typically 0xffffffff) +* - Read commands: mask = upper 4 bits of destination address (0 for 32-bit) */ static inline void bam_prep_ce_le32(struct bam_cmd_element *bam_ce, u32 addr,
@@ -50,7 +57,11 @@ bam_prep_ce_le32(struct bam_cmd_element bam_ce->cmd_and_addr =cpu_to_le32 ((addr &0xffffff ) | ((cmd &0xff ) <<24 )); bam_ce->data = data; - bam_ce->mask =cpu_to_le32 (0xffffffff ); +if (cmd ==BAM_READ_COMMAND ) + bam_ce->mask =cpu_to_le32 (0x0 );/* 32-bit addressing */ +else + bam_ce->mask =cpu_to_le32 (0xffffffff );/* Write mask */ + bam_ce->reserved =0 ; }/*
@@ -60,7 +71,7 @@ bam_prep_ce_le32(struct bam_cmd_element* @bam_ce: BAM command element * @addr: target address * @cmd: BAM command -* @data: actual data for write and dest addr for read +* @data: actual data for write and destination address for read */ static inline void bam_prep_ce(struct bam_cmd_element *bam_ce, u32 addr,
Greg Kroah-Hartman
maintainerPATCH 220/396 e1000: fix memory leak in e1000_probe()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 816419dfea5c88126f35eb7a1b429a1bf546665e upstream.
In the e1000_probe() path, e1000_sw_init() allocates adapter->tx_ring and adapter->rx_ring. If the subsequent CE4100-specific MDIO BAR mapping fails, the error handling jumps past the ring cleanup code, leaking both allocations.
Fix this leak by moving the err_mdio_ioremap label above the ring deallocation logic. This guarantees the proper release of these resources and prevents the memory leak.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1-rc6.
An x86_64 allyesconfig build showed no new warnings. As we do not have a CE4100 reference platform to test with, no runtime testing was able to be performed.
--- drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/e1000/e1000_main.c +1 -1
@@ -1222,11 +1222,11 @@ err_eeprom:if (hw->flash_address)iounmap (hw->flash_address); +err_mdio_ioremap:kfree (adapter->tx_ring);kfree (adapter->rx_ring); err_dma: err_sw_init: -err_mdio_ioremap:iounmap (hw->ce4100_gbe_mdio_base_virt);iounmap (hw->hw_addr); err_ioremap:
Greg Kroah-Hartman
maintainerPATCH 221/396 igbvf: Fix leak in TX DMA error cleanup
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Vollrath <[email protected]>
commit 0565052b7e2f436b7f1541f4849da96dc0aa7a0e upstream.
If an error is encountered while mapping TX buffers, the driver should unmap any buffers already mapped for that skb.
Because count is incremented before each frag mapping, it will always match the correct number of unmappings needed when dma_error is reached. Decrementing count before the while loop in dma_error causes an off-by-one error. If any mapping was successful before an unsuccessful mapping, exactly one DMA mapping (the head) would leak.
This bug was introduced by a 2010 fix for an endless loop in dma_error. All other affected drivers have already been fixed.
--- drivers/net/ethernet/intel/igbvf/netdev.c | 2 -- 1 file changed, 2 deletions(-)
drivers/net/ethernet/intel/igbvf/netdev.c +0 -2
@@ -2191,8 +2191,6 @@ dma_error: buffer_info->time_stamp =0 ; buffer_info->length =0 ; buffer_info->mapped_as_page = false; -if (count) - count--;/* clear timestamp and dma mappings for remaining portion of packet */ while (count--) {
Greg Kroah-Hartman
maintainerPATCH 222/396 igc: remove napi_synchronize() in igc_down()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit 5ffab5b9589c50e4cfc0cf36ffd76c89422d4019 upstream.
When an AF_XDP zero-copy application is killed abruptly, the XSK pool is torn down but NAPI keeps polling. igc_clean_rx_irq_zc() then returns the full budget on every poll, so napi_complete_done() never clears NAPI_STATE_SCHED.
igc_down() calls napi_synchronize() before napi_disable(), so it spins forever waiting for that bit and the interface never goes down. Drop the napi_synchronize() and let napi_disable() do the job -- it sets NAPI_STATE_DISABLE, which forces the stuck poll to complete. Reorder it ahead of igc_set_queue_napi() so the NAPI mapping is cleared only after polling has stopped, matching the recent igb fix b1e067240379.
--- drivers/net/ethernet/intel/igc/igc_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/ethernet/intel/igc/igc_main.c +1 -2
@@ -5354,9 +5354,8 @@ void igc_down(struct igc_adapter *adaptefor (i =0 ; i < adapter->num_q_vectors; i++) {if (adapter->q_vector[i]) { -napi_synchronize (&adapter->q_vector[i]->napi); -igc_set_queue_napi (adapter, i,NULL );napi_disable (&adapter->q_vector[i]->napi); +igc_set_queue_napi (adapter, i,NULL ); } }
Greg Kroah-Hartman
maintainerPATCH 223/396 ipvs: do not propagate one-packet flag to synced conns
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit a63d2dbaeb50a85d4c976b15a36e6b0c7113db5b upstream.
Synced connections can be created before their destination exists. When the destination is later added, ip_vs_bind_dest() copies connection flags from the destination into cp->flags.
IP_VS_CONN_F_ONE_PACKET connections are not synced. If a synced connection inherits IP_VS_CONN_F_ONE_PACKET while it is already hashed, expiry can treat it as a one-packet connection and skip unlinking the existing conn_tab node, leaving stale hash nodes pointing at a freed struct ip_vs_conn.
Drop IP_VS_CONN_F_ONE_PACKET from destination flags when binding synced connections.
--- net/netfilter/ipvs/ip_vs_conn.c | 3 +++ 1 file changed, 3 insertions(+)
net/netfilter/ipvs/ip_vs_conn.c +3 -0
@@ -599,6 +599,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s flags = cp->flags;/* Bind with the destination and its corresponding transmitter */ if (flags &IP_VS_CONN_F_SYNC ) { +/* Synced conns are hashed, so they can not get this flag */ + conn_flags &= ~IP_VS_CONN_F_ONE_PACKET ; +/* if the connection is not template and is created * by sync, preserve the activity flag. */
Greg Kroah-Hartman
maintainerPATCH 224/396 ksmbd: reject repeated SMB2 NEGOTIATE requests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit cb469993b3a61a72653770856d37af616d72d05f upstream.
Unauthenticated client can send multiple successful SMB2 NEGOTIATE requests on one connection before SESSION_SETUP. While the connection is in KSMBD_SESS_NEED_SETUP, smb2_handle_negotiate() accepts another SMB3.1.1 NEGOTIATE and overwrites conn->preauth_info with a new allocation. Only the final allocation is freed when the connection is released, leaking one object for every additional successful request.
A repeated SMB2 NEGOTIATE after a dialect has been selected is a protocol violation. MS-SMB2 section 3.3.5.4 requires the server to disconnect without replying in this case. Set the connection exiting when rejecting the request, in addition to suppressing the response.
Reject SMB2 NEGOTIATE unless the connection is new or is waiting for the SMB2 NEGOTIATE that follows an SMB1 multi-protocol negotiate. Serialize both SMB1 and SMB2 negotiation paths under conn->srv_mutex, since they update connection-wide dialect and negotiation state.
Move the locking contract to ksmbd_smb_negotiate_common(), where the state and dialect are selected, and add ksmbd_conn_new() for consistent state access.
--- fs/smb/server/connection.h | 5 +++++ fs/smb/server/smb2pdu.c | 10 ++-------- fs/smb/server/smb_common.c | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 15 deletions(-)
fs/smb/server/connection.h +5 -0
@@ -197,6 +197,11 @@ void ksmbd_conn_r_count_dec(struct ksmbd* This is a hack. We will move status to a proper place once we land * a multi-sessions support. */ +static inline bool ksmbd_conn_new (struct ksmbd_conn *conn) +{ +return READ_ONCE (conn->status) ==KSMBD_SESS_NEW ; +} +static inline bool ksmbd_conn_good (struct ksmbd_conn *conn) {return READ_ONCE (conn->status) ==KSMBD_SESS_GOOD ;
fs/smb/server/smb2pdu.c +2 -8
@@ -1102,6 +1102,8 @@ static __le32 deassemble_neg_contexts(st* smb2_handle_negotiate() - handler for smb2 negotiate command * @work: smb work containing smb request buffer * +* The caller holds conn->srv_mutex. +* * Return: 0 */ int smb2_handle_negotiate (struct ksmbd_work *work)
@@ -1115,13 +1117,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_debug (SMB ,"Received negotiate request\n" ); conn->need_neg = false; -if (ksmbd_conn_good (conn)) { -pr_err ("conn->tcp_status is already in CifsGood State\n" ); - work->send_no_response =1 ; -return rc; - } - -ksmbd_conn_lock (conn); smb2_buf_len =get_rfc1002_len (work->request_buf); smb2_neg_size = offsetof(struct smb2_negotiate_req , Dialects);if (smb2_neg_size > smb2_buf_len) {
@@ -1272,7 +1267,6 @@ int smb2_handle_negotiate(struct ksmbd_wksmbd_conn_set_need_setup (conn); err_out: -ksmbd_conn_unlock (conn);if (rc) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;
fs/smb/server/smb_common.c +30 -7
@@ -592,23 +592,46 @@ int ksmbd_smb_negotiate_common(struct ksstruct ksmbd_conn *conn = work->conn;int ret; - conn->dialect = -ksmbd_negotiate_smb_dialect (work->request_buf); -ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); -if (command ==SMB2_NEGOTIATE_HE ) { +/* +* An SMB2 NEGOTIATE is valid for a new connection, or after an +* SMB1 multi-protocol negotiate has selected SMB2. Do not allow +* a second SMB2 NEGOTIATE to replace connection-wide state +* while a session setup is pending. KSMBD_SESS_NEED_RECONNECT +* is a transient session state and does not restart transport +* negotiation. +*/ +ksmbd_conn_lock (conn); +if (!ksmbd_conn_new (conn) && + !ksmbd_conn_need_negotiate (conn)) { + work->send_no_response =1 ; +ksmbd_conn_set_exiting (conn); +ksmbd_conn_unlock (conn); +return 0 ; + } + + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect); ret =smb2_handle_negotiate (work); +ksmbd_conn_unlock (conn);return ret; }if (command ==SMB_COM_NEGOTIATE ) { +ksmbd_conn_lock (conn); + conn->dialect = +ksmbd_negotiate_smb_dialect (work->request_buf); +ksmbd_debug (SMB ,"conn->dialect 0x%x\n" , conn->dialect);if (__smb2_negotiate (conn)) {init_smb3_11_server (conn); -init_smb2_neg_rsp (work); + ret =init_smb2_neg_rsp (work);ksmbd_debug (SMB ,"Upgrade to SMB2 negotiation\n" ); -return 0 ; + }else { + ret =smb_handle_negotiate (work); } -return smb_handle_negotiate (work); +ksmbd_conn_unlock (conn); +return ret; }pr_err ("Unknown SMB negotiation command: %u\n" , command);
Greg Kroah-Hartman
maintainerPATCH 225/396 mshv: fix hv_input_get_system_property struct
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Liu <[email protected]>
commit d6f0248f04a96249660591e47fcf37ba98ac7ea3 upstream.
Keep it in sync with the correct definition.
The old code worked by chance.
--- include/hyperv/hvhdk_mini.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/hyperv/hvhdk_mini.h +2 -1
@@ -126,8 +126,9 @@ enum hv_dynamic_processor_feature_properstruct hv_input_get_system_property {u32 property_id;/* enum hv_system_property */ +u32 reserved;union { -u32 as_uint32; +u64 as_uint64;#if IS_ENABLED (CONFIG_X86 )/* enum hv_dynamic_processor_feature_property */ u32 hv_processor_feature;
Greg Kroah-Hartman
maintainerPATCH 226/396 net/smc: fix socket use-after-free during link group termination
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
commit f621d6ebeebb6374342571e4ddf45fdbc420f6cd upstream.
__smc_lgr_terminate() drops conns_lock after finding a connection in lgr->conns_all, but before taking a reference on its socket. The connection is embedded in the socket, and its registration reference protects it only while the connection remains in the tree.
A concurrent close can unregister the connection and drop that reference, freeing the socket before the termination worker reaches sock_hold().
The race is reachable when close overlaps link group termination. Local stress testing reproduced the use-after-free and KASAN reported:
BUG: KASAN: slab-use-after-free in __smc_lgr_terminate.part.0 [smc] Write of size 4 by task kworker/3:3 Workqueue: events smc_lgr_terminate_work [smc] __smc_lgr_terminate.part.0 [smc]
The socket was allocated by smc_create(), freed through slab_free_after_rcu_debug(), and was followed by:
refcount_t: addition on 0; use-after-free.
__smc_lgr_terminate.part.0 [smc]
Take the socket reference while conns_lock still protects the tree entry. The unregister path then cannot drop the last reference until termination has finished using the socket.
--- net/smc/smc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/smc/smc_core.c +1 -1
@@ -1558,10 +1558,10 @@ static void __smc_lgr_terminate(struct sread_lock_bh (&lgr->conns_lock); node =rb_first (&lgr->conns_all);while (node) { -read_unlock_bh (&lgr->conns_lock); conn = rb_entry(node, struct smc_connection, alert_node); smc = container_of(conn, struct smc_sock, conn);sock_hold (&smc->sk);/* sock_put below */ +read_unlock_bh (&lgr->conns_lock);lock_sock (&smc->sk);smc_conn_kill (conn, soft);release_sock (&smc->sk);
Greg Kroah-Hartman
maintainerPATCH 227/396 netfilter: ipset: do not update comments from kernel-side hash adds
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
commit f30415929be8aeb002d557c8d3f7ab2d2188003a upstream.
mtype_resize() copies comment pointers with memcpy(), not the comment objects themselves. During the window after an entry has been copied but before the table swap and backlog replay, the old table is still published for packet-side updates while the replacement-table entry already holds the same ip_set_comment_rcu pointer.
If xt_SET --add-set ... --exist hits that old entry in this window, mtype_add() calls ip_set_init_comment() even though packet-side adds carry no comment payload. That call frees the shared comment through the old entry, so the replacement-table entry now holds a stale pointer. When the queued add is replayed on the new table, mtype_add() calls ip_set_init_comment() again and strlen() dereferences the stale pointer.
Fix this in mtype_add() by skipping ip_set_init_comment() when ext->target marks a packet-side add. Userspace adds still update comments, while packet-side adds can no longer free comment storage shared with a resize copy.
--- net/netfilter/ipset/ip_set_hash_gen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/ipset/ip_set_hash_gen.h +1 -1
@@ -984,7 +984,7 @@ overwrite_extensions:#endif if (SET_WITH_COUNTER (set))ip_set_init_counter (ext_counter (data, set), ext); -if (SET_WITH_COMMENT (set)) +if (SET_WITH_COMMENT (set) && !ext->target)ip_set_init_comment (set,ext_comment (data, set), ext);if (SET_WITH_SKBINFO (set))ip_set_init_skbinfo (ext_skbinfo (data, set), ext);
Greg Kroah-Hartman
maintainerPATCH 228/396 of/address: Fix NULL bus dereference in of_pci_range_parser_one()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlo Caione <[email protected]>
commit bba13ad17b1a11b3f1ed9b3a5d556191d7755a59 upstream.
The bus matching rework made of_match_bus() return NULL for nodes with ranges/dma-ranges but no local #address-cells. parser_init() stored that NULL bus, and the range iterator later dereferenced it.
Reject such nodes in parser_init(), leaving an explicit empty iterator for callers that ignore the init return, and make of_dma_get_max_cpu_address() honour the init failure so a rejected node cannot clamp the DMA limit.
--- drivers/of/address.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/of/address.c +16 -6
@@ -757,6 +757,7 @@ EXPORT_SYMBOL(of_property_read_reg);static int parser_init (struct of_pci_range_parser *parser,struct device_node *node,const char *name) { +const __be32 *range;int rlen; parser->node = node;
@@ -765,12 +766,20 @@ static int parser_init(struct of_pci_ran parser->ns =of_bus_n_size_cells (node); parser->dma = !strcmp (name,"dma-ranges" ); parser->bus =of_match_bus (node); + parser->range =NULL ; + parser->end =NULL ; - parser->range =of_get_property (node, name, &rlen); -if (parser->range ==NULL ) + range =of_get_property (node, name, &rlen); +if (!range)return -ENOENT ; - parser->end = parser->range + rlen /sizeof (__be32); +if (!parser->bus || + !OF_CHECK_COUNTS (parser->na, parser->ns) || + !OF_CHECK_ADDR_COUNT (parser->pna)) +return -EINVAL ; + + parser->range = range; + parser->end = range + rlen /sizeof (__be32);return 0 ; }
@@ -796,7 +805,7 @@ struct of_pci_range *of_pci_range_parserint na = parser->na;int ns = parser->ns;int np = parser->pna + na + ns; -int busflag_na = parser->bus->flag_cells; +int busflag_na;if (!range)return NULL ;
@@ -804,6 +813,8 @@ struct of_pci_range *of_pci_range_parserif (!parser->range || parser->range + np > parser->end)return NULL ; + busflag_na = parser->bus->flag_cells; + range->flags = parser->bus->get_flags (parser->range); range->bus_addr =of_read_number (parser->range + busflag_na, na - busflag_na);
@@ -980,8 +991,7 @@ phys_addr_t __init of_dma_get_max_cpu_ad np = of_root; ranges =of_get_property (np,"dma-ranges" , &len); -if (ranges && len) { -of_dma_range_parser_init (&parser, np); +if (ranges && len && !of_dma_range_parser_init (&parser, np)) {for_each_of_range (&parser, &range)if (range.cpu_addr + range.size > cpu_end) cpu_end = range.cpu_addr + range.size -1 ;
Greg Kroah-Hartman
maintainerPATCH 229/396 tipc: avoid use-after-free in poll trace queue dumps
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
commit b4f1719dfea023220e0e6bd892b087d76b2a6a49 upstream.
TIPC socket tracepoints dump queue state through tipc_sk_dump(). Most queue-dump callsites already serialize that walk under the socket lock or sk->sk_lock.slock, but tipc_poll() calls trace_tipc_sk_poll(..., TIPC_DUMP_ALL, ...) without holding either lock.
That lets the poll trace path reach tipc_list_dump() and backlog head/tail dumping while another context dequeues and frees an skb, leaving the trace helper dereferencing a stale queue entry.
Stop the unlocked poll trace site from requesting queue dumps. Other queue dump trace callsites keep their existing output under the locking they already provide, while poll still emits the event itself without walking live queue members from an unlocked context.
--- net/tipc/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/tipc/socket.c +1 -1
@@ -795,7 +795,7 @@ static __poll_t tipc_poll(struct file *f__poll_t revents =0 ;sock_poll_wait (file, sock, wait); -trace_tipc_sk_poll (sk,NULL ,TIPC_DUMP_ALL ," " ); +trace_tipc_sk_poll (sk,NULL ,TIPC_DUMP_NONE ," " );if (sk->sk_shutdown &RCV_SHUTDOWN ) revents |=EPOLLRDHUP |EPOLLIN |EPOLLRDNORM ;
Greg Kroah-Hartman
maintainerPATCH 230/396 wifi: mwifiex: use the subframe length when parsing A-MSDU TDLS frames
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
commit 99a948382af8a225e2d5e54a7052158cd6281cc6 upstream.
mwifiex_11n_dispatch_amsdu_pkt() splits an A-MSDU with ieee80211_amsdu_to_8023s() and walks the resulting subframes. For each subframe it passes the subframe data pointer to mwifiex_process_tdls_action_frame(), but pairs it with skb->len, the length of the A-MSDU parent, instead of rx_skb->len:
rx_skb = __skb_dequeue(&list);
rx_hdr = (struct rx_packet_hdr *)rx_skb->data;
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
mwifiex_process_tdls_action_frame(priv, (u8 *)rx_hdr,
skb->len);
}The parent is not a valid description of that buffer, and may not be valid memory at all. ieee80211_amsdu_to_8023s() ends with
if (!reuse_skb) dev_kfree_skb(skb);
and it only sets reuse_skb when the parent is linear, is not a head_frag, and is being consumed as the *last* subframe. So when the parent does not qualify for reuse it has already been freed, and the read of skb->len is a use-after-free. When it is reused, skb->len is the length of the last subframe, applied to every earlier subframe, which over-states the buffer whenever an earlier subframe is shorter.
The callee cannot absorb a wrong length, because it derives its own ceiling from the value it is given. Each frame type computes
ies_len = len - sizeof(struct ethhdr) - TDLS_*_FIX_LEN;
and the element walk is then bounded entirely against that ceiling,
for (end = pos + ies_len; pos + 1 < end; pos += 2 + pos[1]) {
u8 ie_len = pos[1];
if (pos + 2 + ie_len > end)
break;so a too-large len moves end past the end of the subframe and the walk reads and copies beyond it. The A-MSDU layout is chosen by the sender, which makes the difference between the last subframe and a shorter earlier one remotely selectable. Reaching this requires TDLS support in firmware and the TDLS ethertype on the subframe.
The other caller, mwifiex_process_rx_packet(), is correct: it passes a pointer and a length that describe the same region of the RX buffer.
Pass rx_skb->len, the length of the subframe actually being parsed.
--- drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +1 -1
@@ -44,7 +44,7 @@ static int mwifiex_11n_dispatch_amsdu_pk ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {mwifiex_process_tdls_action_frame (priv, (u8 *)rx_hdr, - skb->len); + rx_skb->len); }if (priv->bss_role ==MWIFIEX_BSS_ROLE_UAP )
Greg Kroah-Hartman
maintainerPATCH 231/396 binfmt_misc: restore write access when removing an entry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit db1856ea9196cf6e015d12199a34c0b9313c7bfa upstream.
Registering an entry with the MISC_FMT_OPEN_FILE flag opens the interpreter via open_exec() which denies write access to it for as long as the entry exists. Removing the entry closes the interpreter file via filp_close() but never restores write access, leaving the inode's i_writecount permanently negative. Opening the interpreter for writing keeps failing with ETXTBSY long after the entry is gone until the inode is evicted from the inode cache.
Commit 90f601b497d7 ("binfmt_misc: restore write access before closing files opened by open_exec()") fixed the same imbalance in the error path of bm_register_write() but the actual removal path has been leaking the write denial since the introduction of the flag.
Restore write access in put_binfmt_handler() before closing the interpreter file.
--- fs/binfmt_misc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/binfmt_misc.c +3 -1
@@ -161,8 +161,10 @@ static Node *get_binfmt_handler(struct bstatic void put_binfmt_handler (Node *e) {if (refcount_dec_and_test (&e->users)) { -if (e->flags &MISC_FMT_OPEN_FILE ) +if (e->flags &MISC_FMT_OPEN_FILE ) { +exe_file_allow_write_access (e->interp_file);filp_close (e->interp_file,NULL ); + }kfree (e); } }
Greg Kroah-Hartman
maintainerPATCH 232/396 binfmt_misc: use exe_file_deny_write_access() for the interpreter clone
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit fa5990ca8fd917003e526036bcc50413edb9722c upstream.
For MISC_FMT_OPEN_FILE entries load_misc_binary() clones the registered interpreter file and denies write access to the clone via plain deny_write_access(). The clone is installed as bprm->interpreter and later released by the exec machinery through exe_file_allow_write_access() which skips the i_writecount increment for files with FMODE_FSNOTIFY_HSM set.
The deny and allow side can therefore come to different conclusions when pre-content watches are in play: if a pre-content watch is added to the interpreter after registration every subsequent exec through that entry takes a write denial on the clone that is never paired with a write allowance, driving the interpreter inode's i_writecount further down with each exec and leaving the interpreter unwritable even after the entry and all its users are gone.
Take the write denial via exe_file_deny_write_access() so both sides of the pairing base their decision on the same file mode, and propagate failure instead of silently ignoring it: an interpreter that is concurrently open for writing now fails the exec with ETXTBSY, exactly like an interpreter freshly opened via open_exec() would.
--- fs/binfmt_misc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/binfmt_misc.c +8 -2
@@ -248,8 +248,14 @@ static int load_misc_binary(struct linuxif (fmt->flags &MISC_FMT_OPEN_FILE ) { interp_file =file_clone_open (fmt->interp_file); -if (!IS_ERR (interp_file)) -deny_write_access (interp_file); +if (!IS_ERR (interp_file)) { +int err =exe_file_deny_write_access (interp_file); + +if (err) { +fput (interp_file); + interp_file =ERR_PTR (err); + } + } }else { interp_file =open_exec (fmt->interpreter); }
Greg Kroah-Hartman
maintainerPATCH 233/396 binfmt_misc: reject a flag character as the field delimiter
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 8e85d50ba1117fd446bf9a250bd8a97d48384bdc upstream.
The registration string starts with a user chosen delimiter that separates the individual fields. So that the field parsers terminate even on a truncated string create_entry() pads the buffer with that same delimiter:
memset(buf + count, del, 8);
Most fields are scanned for the delimiter with strchr()/scanarg() and happily stop on the padding. The flags field is different: instead of scanning for the delimiter check_special_flags() consumes the flag characters 'P', 'O', 'C' and 'F' and stops at the first byte that is none of them, relying on the trailing delimiter to end the scan.
If the delimiter is itself a flag character the padding no longer acts as a terminator. The scan swallows all eight padding bytes and keeps reading past the end of the allocation until it hits a byte that is not a flag character. For example registering
PaPEPPxPPiP
with 'P' as the delimiter (name "a", type extension, magic "x", interpreter "i", empty flags) leaves the flag scan running off the end of the buffer. The registration is rejected in the end because the parser does not stop exactly at buf + count, but only after the out of bounds read has already happened. With an unlucky allocation layout the scan can walk into an unmapped page; under KASAN it is reported as a slab out of bounds read. binfmt_misc mounts are available to unprivileged users in a user namespace so the read is reachable without privileges.
Reject a delimiter that is one of the flag characters up front. Such a registration was always rejected anyway, only after the out of bounds read, so no valid registration string changes meaning.
--- fs/binfmt_misc.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/binfmt_misc.c +4 -0
@@ -383,6 +383,10 @@ static Node *create_entry(const char __upr_debug ("register: delim: %#x {%c}\n" , del, del); +/* A flag-char delimiter runs the flag scan off the buffer. */ +if (del =='P' || del =='O' || del =='C' || del =='F' ) + goto einval; +/* Pad the buffer with the delim to simplify parsing below. */ memset (buf + count, del,8 );
Greg Kroah-Hartman
maintainerPATCH 234/396 binfmt_misc: dont let an F entry pin its own instance
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 79055d82772b9584f259b747fe40ff56a076678d upstream.
An entry registered with 'F' opens its interpreter at registration time and holds that file until the entry is freed. Any entry nobody removes by hand only gets closed once the binfmt_misc superblock is shut down. If the interpreter lives on a mount that keeps that superblock alive the two pin each other:
binfmt_misc sb -> inode -> entry -> interp_file -> vfsmount -> binfmt_misc sb
TL;DR the file is never closed. Once the mount namespace is gone there is nothing left to unregister through either.
There are two ways to trigger this bug:
- Point the interpreter at the instance itself. Its files are regular files owned by the mounter and both bm_get_inode() and simple_fill_super() leave i_op at empty_iops. So notify_change() falls back to simple_setattr() and chmod +x works. We never set SB_I_NOEXEC and so open_exec() accepts it.
- Use the instance as an overlayfs lower layer. The overlay superblock holds a clone_private_mount() of every layer until it is destroyed and that clone is in no namespace. So umount_tree() never reaches it.
That's a DoS. And it isn't only the superblock that leaks. It pins the user namespace it was mounted in, so every iteration permanently eats one of the caller's user namespace charges.
So let's just do the sane thing. SB_I_NOEXEC makes open_exec() fail on the instance's own files and s_stack_depth makes overlayfs reject the layer before it ever takes a clone. That also covers the ecryptfs and fuse passthrough variants. What 'F' promises is unchanged.
The stable tag is narrower than the Fixes tags on purpose. Before sandboxed mounts this needed global root against the single instance everyone shares, and the change doesn't apply to those trees anyway.
Note that SB_I_NODEV is implicitly raised for userns mounts but raise it explicitly here as well.
--- fs/binfmt_misc.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/binfmt_misc.c +4 -0
@@ -956,6 +956,10 @@ static int bm_fill_super(struct super_blif (WARN_ON (user_ns !=current_user_ns ()))return -EINVAL ; +/* Never exec off this instance and never let anything stack on it. */ + sb->s_iflags |=SB_I_NOEXEC |SB_I_NODEV ; + sb->s_stack_depth =FILESYSTEM_MAX_STACK_DEPTH ; +/* * Lazily allocate a new binfmt_misc instance for this namespace, i.e. * do it here during the first mount of binfmt_misc. We don't need to
Greg Kroah-Hartman
maintainerPATCH 235/396 io_uring/net: initialize mshot_len for send
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
commit c77ffbc980efb337fd750c337d8157d532ea14e5 upstream.
Commit:
6a8afb9fff64 ("io_uring/net: allow multishot receive per-invocation cap")
changed how io_mshot_prep_retry() set sr->len, and added the same initialization in io_mshot_prep_retry(). But it neglected to touch the send path, which may also uses the mshot retry path. Ensure that sr->mshot_len always gets initialized correctly.
--- io_uring/net.c | 1 + 1 file changed, 1 insertion(+)
io_uring/net.c +1 -0
@@ -433,6 +433,7 @@ int io_sendmsg_prep(struct io_kiocb *req req->flags |=REQ_F_NOWAIT ;if (req->flags &REQ_F_BUFFER_SELECT ) sr->buf_group = req->buf_index; + sr->mshot_total_len = sr->mshot_len =0 ;if (sr->flags &IORING_RECVSEND_BUNDLE ) {if (req->opcode ==IORING_OP_SENDMSG )return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 236/396 mm/page_reporting: use system_freezable_wq to fix UAF during suspend
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Link Lin <[email protected]>
commit 0b45f6927a14914ff685fe0e6f9d11232a1e03df upstream.
During PM freeze (e.g. S3 suspend or S4 hibernation), device drivers like virtio_balloon reset their underlying virtio devices and delete their virtqueues via vdev->config->del_vqs().
However, page reporting work (page_reporting_process) was scheduled on the global system_wq. Because system_wq lacks the WQ_FREEZABLE flag, the PM freezer skips it, leaving page_reporting_process active during suspend.
If pages are freed into the buddy allocator while suspending (for example, when core MM invokes the balloon shrinker during S4 hibernation image saving), page reporting triggers virtballoon_free_page_report() on deleted virtqueues, resulting in a Use-After-Free / General Protection Fault:
[ 196.795226] general protection fault, probably for non-canonical address 0xaa1436fe70dae6df: 0000 [#1] SMP NOPTI
[ 196.825967] Workqueue: events page_reporting_process
[ 196.831038] RIP: 0010:virtqueue_add_split+0x233/0x4c0 [virtio_ring]
[ 196.927073] virtballoon_free_page_report+0x3a/0xe0 [virtio_balloon]
[ 196.946943] page_reporting_process+0x370/0x4f0Fix this by switching page reporting work to system_freezable_wq. This ensures that the PM freezer pauses page_reporting_process before device drivers destroy their reporting virtqueues. Because the reporting worker is frozen, memory reclamation/freeing (e.g. via shrinker execution) can safely return pages to MM during freeze without triggering unfrozen reporting work on deleted virtqueues.
This aligns with the driver's existing design. The comment in virtballoon_freeze() states:
/*
* The workqueue is already frozen by the PM core before this
* function is called.
*/
Testing:
I have verified these fixes using Google’s virtualization infrastructure by running continuous suspend/resume iterations (40+ cycles) while churning memory using stress-ng (stress-ng --vm 4 --vm-bytes 60% --timeout 1) to constantly create free pages for the buddy allocator. We also set the page_reporting_order parameter to 0 to make the page reporting worker highly sensitive, forcing it to pick up any 4K free pages. This confirmed that the UAF crashes are no longer reproducible.
--- mm/page_reporting.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
mm/page_reporting.c +4 -2
@@ -80,7 +80,8 @@ __page_reporting_request(struct page_rep* now we are limiting this to running no more than once every * couple of seconds. */ -schedule_delayed_work (&prdev->work,PAGE_REPORTING_DELAY ); +queue_delayed_work (system_freezable_wq, &prdev->work, +PAGE_REPORTING_DELAY ); }/* notify prdev of free page reporting request */
@@ -343,7 +344,8 @@ err_out:*/ state =atomic_cmpxchg (&prdev->state, state,PAGE_REPORTING_IDLE );if (state ==PAGE_REPORTING_REQUESTED ) -schedule_delayed_work (&prdev->work,PAGE_REPORTING_DELAY ); +queue_delayed_work (system_freezable_wq, &prdev->work, +PAGE_REPORTING_DELAY ); }static DEFINE_MUTEX (page_reporting_mutex);
Greg Kroah-Hartman
maintainerPATCH 237/396 mm: memcg: initialize *locked in memcg1_oom_prepare() stub
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 1833ce36b35426504c64600c94f322437ea44bb2 upstream.
mem_cgroup_oom() passes an uninitialized "locked" to memcg1_oom_prepare() and reads it back in memcg1_oom_finish():
bool locked, ret; ... if (!memcg1_oom_prepare(memcg, &locked)) return false; ret = mem_cgroup_out_of_memory(memcg, mask, order); memcg1_oom_finish(memcg, locked);
This relies on memcg1_oom_prepare() setting *locked whenever it returns true. The CONFIG_MEMCG_V1=y version does, but the stub used when CONFIG_MEMCG_V1=n returns true without touching *locked, so memcg1_oom_finish() consumes an uninitialized value. On a memcg OOM this is reported by UBSAN:
UBSAN: invalid-load in mm/memcontrol.c:1932:27 load of value 0 is not a valid value for type 'bool' (aka '_Bool')
Initialize *locked to false in the stub; with cgroup v1 compiled out there is no OOM lock to take.
--- mm/memcontrol-v1.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
mm/memcontrol-v1.h +5 -1
@@ -103,7 +103,11 @@ static inline void memcg1_remove_from_trstatic inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {}static inline void memcg1_css_offline (struct mem_cgroup *memcg) {} -static inline bool memcg1_oom_prepare (struct mem_cgroup *memcg,bool *locked) {return true; } +static inline bool memcg1_oom_prepare (struct mem_cgroup *memcg,bool *locked) +{ + *locked = false; +return true; +}static inline void memcg1_oom_finish (struct mem_cgroup *memcg,bool locked) {}static inline void memcg1_oom_recover (struct mem_cgroup *memcg) {}
Greg Kroah-Hartman
maintainerPATCH 238/396 net: bridge: stop fast-leave after deleting a port group
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit a39789f211b8a4125f0c70e05b30cf715f4f187d upstream.
br_multicast_leave_group() iterates mp->ports with pp = &p->next in its fast-leave path. After br_multicast_del_pg() removes p, continuing the loop advances pp through the deleted entry.
If multicast-to-unicast was enabled, the bridge can hold multiple port groups for the same port and group with different source MAC addresses. Once multicast-to-unicast is disabled, br_port_group_equal() matches those entries by port only. A fast leave can then delete one entry and continue from its stale next pointer, leaving mp->ports pointing at a deleted port group.
Fast leave only needs to remove one matching port group. Break after br_multicast_del_pg() so the loop stops before dereferencing the removed entry.
--- net/bridge/br_multicast.c | 1 + 1 file changed, 1 insertion(+)
net/bridge/br_multicast.c +1 -0
@@ -3686,6 +3686,7 @@ br_multicast_leave_group(struct net_brid p->flags |=MDB_PG_FLAGS_FAST_LEAVE ;br_multicast_del_pg (mp, p, pp); +break ; } goto out; }
Greg Kroah-Hartman
maintainerPATCH 239/396 net: ipv6: clear suppressed fib6 rule result
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit 6aea62e433fe1b586202a5fee8b5807ce635e1d7 upstream.
fib6_rule_suppress() drops a suppressed route with ip6_rt_put_flags(), but leaves res->rt6 pointing at the released rt6_info.
If no later rule supplies a replacement, fib6_rule_lookup() still sees res.rt6 and returns that stale dst to its caller. A suppressing rule can therefore leak a released route back to rt6_lookup(), and the next put hits rcuref_put_slowpath() from dst_release().
Clear res->rt6 when suppressing the route so suppressed lookups fall through to the null dst instead of reusing the released one.
--- net/ipv6/fib6_rules.c | 1 + 1 file changed, 1 insertion(+)
net/ipv6/fib6_rules.c +1 -0
@@ -305,6 +305,7 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_s suppress_route:ip6_rt_put_flags (rt, flags); + res->rt6 =NULL ;return true; }
Greg Kroah-Hartman
maintainerPATCH 240/396 net: pktgen: fix proc entry use-after-free
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 817ff6efdb7f484ea547218e11e17d8e43daa3b4 upstream.
pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock. pktgen_remove_device() removes the same entry before _rem_dev_from_if_list() takes that lock.
This allows the following interleaving:
CPU 0 (NETDEV_CHANGENAME) CPU 1 (kpktgend)
if_lock(t)
proc_remove(pkt_dev->entry)
proc_remove(pkt_dev->entry)
pkt_dev->entry = proc_create_data(...)
if_unlock(t)
The kthread can pass the stale proc_dir_entry to proc_remove() after the rename path has freed it. A reproducer with a widened race window reports:
BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80 Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67 Call Trace: proc_remove+0x78/0x80 pktgen_remove_device.isra.0+0x11c/0x4c0 pktgen_thread_worker+0x1214/0x6bc0 kthread+0x2c6/0x3b0 Allocated by task 95: __proc_create+0x204/0x790 proc_create_data+0x72/0xe0 pktgen_thread_write+0xd61/0x1510 Freed by task 28: kmem_cache_free+0xcb/0x3d0 proc_free_inode+0x5b/0x80 rcu_core+0x50a/0x1850 The buggy address belongs to the object at ffff8881478fea00 which belongs to the cache proc_dir_entry of size 192
Move proc_remove() into the if_lock-protected list removal helper. Keep it before list_del_rcu() to preserve the ordering required by add_device(). The rename path must then finish replacing the entry before removal, or it observes that the device is no longer on the list.
--- net/core/pktgen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/core/pktgen.c +1 -3
@@ -3971,6 +3971,7 @@ static void _rem_dev_from_if_list(structstruct pktgen_dev *p;if_lock (t); +proc_remove (pkt_dev->entry);list_for_each_safe (q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list);if (p == pkt_dev)
@@ -4000,9 +4001,6 @@ static int pktgen_remove_device(struct p* list to determine if interface already exist, avoid race * with proc_create_data() */ -proc_remove (pkt_dev->entry); - -/* And update the thread if_list */ _rem_dev_from_if_list (t, pkt_dev);#ifdef CONFIG_XFRM
Greg Kroah-Hartman
maintainerPATCH 241/396 powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 0bb024f11d120abff3e8db9144a585b9d7fb8459 upstream.
If lv1_put_iopte() fails in dma_ioc0_map_pages(), the error path decrements iopage but keeps using the failed mapping's offset. As a result, it repeatedly tries to invalidate the failed IOPTE slot and leaves the already installed IOPTEs valid.
Recompute offset and invalidate the installed IOPTEs instead.
--- arch/powerpc/platforms/ps3/mm.c | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/platforms/ps3/mm.c +1 -0
@@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3 fail_map:for (iopage--;0 <= iopage; iopage--) { + offset = (1 << r->page_size) * iopage; lv1_put_iopte(0, c->bus_addr + offset, c->lpar_addr + offset,
Greg Kroah-Hartman
maintainerPATCH 242/396 um: vector: fix use-after-free in vector_mmsg_rx()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit af421e9aed3920c7ac88c24daa48606c7112feca upstream.
When vector_mmsg_rx() discards a packet whose overlay header fails verify_header(), it frees the skb and continues the loop:
if (header_check < 0) {
dev_kfree_skb_irq(skb);
vp->estats.rx_encaps_errors++;
continue;
}The normal and short-packet paths fall through to the bottom of the loop body, which clears the consumed slot and advances the cursors:
(*skbuff_vector) = NULL; mmsg_vector++; skbuff_vector++;
The verify_header() < 0 path skips that via continue, so the freed skb is left in skbuff_vector[] and the cursors do not advance. The next iteration reads the same slot, gets the freed skb, and frees it again, producing a refcount underflow / use-after-free in the RX path.
Discard the slot the same way the other paths do before continuing.
Only transports whose verify_header() can return negative are affected:
GRE and L2TPv3 do so on a cookie/session-id mismatch (raw/tap do not), so any peer on such a transport can trigger it without authentication.
--- arch/um/drivers/vector_kern.c | 3 +++ 1 file changed, 3 insertions(+)
arch/um/drivers/vector_kern.c +3 -0
@@ -1000,6 +1000,9 @@ static int vector_mmsg_rx(struct vector_*/ dev_kfree_skb_irq (skb); vp->estats.rx_encaps_errors++; + (*skbuff_vector) =NULL ; + mmsg_vector++; + skbuff_vector++;continue ; }if (header_check >0 ) {
Greg Kroah-Hartman
maintainerPATCH 243/396 uprobes: Fix NULL pointer dereference in hprobe_expire()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit cc679d7a6303e84d769f2afcde1fc51c51f127cd upstream.
Forking a task that has a pending uretprobe can oops the kernel with a NULL pointer dereference in the clone() path:
BUG: kernel NULL pointer dereference, address: 0000000000000018 Oops: 0002 [#1] SMP NOPTI RIP: 0010:hprobe_expire CR2: 0000000000000018 Call Trace: uprobe_copy_process copy_process kernel_clone __x64_sys_clone do_syscall_64 entry_SYSCALL_64_after_hwframe
This was found on real hosts on Meta fleet.
I've got the impression that this is what is happening:
CPU 1 CPU 2 (traced task)
----- -------------------
hit uprobe, prepare_uretprobe():
hprobe LEASED, refcount >= 1
uprobe_unregister()
put_uprobe(): refcount -> 0
fork() -> dup_utask()
hprobe_expire(hprobe, true)
try_get_uprobe() -> NULL
get_uprobe(NULL) <-- OopsOnly take the extra reference when the uprobe is non-NULL; a NULL means it is gone and is the correct value to return.
--- kernel/events/uprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/events/uprobes.c +1 -1
@@ -830,7 +830,7 @@ static struct uprobe *hprobe_expire(struif (try_cmpxchg (&hprobe->state, &hstate, uprobe ?HPROBE_STABLE :HPROBE_GONE )) {/* We won the race, we are the ones to unlock SRCU */ __srcu_read_unlock (&uretprobes_srcu, hprobe->srcu_idx); -return get ?get_uprobe (uprobe) : uprobe; +return get && uprobe ?get_uprobe (uprobe) : uprobe; }/*
Greg Kroah-Hartman
maintainerPATCH 244/396 veth: convert frag_list skbs before running XDP
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Fleming <[email protected]>
commit d0d6415963040c401e7a7e4e482a698ba52448cb upstream.
A frag_list skb can reach veth with data_len set but nr_frags zero. veth_convert_skb_to_xdp_buff() only converts skbs that are shared, locked, have frags[], or do not have enough headroom. It later uses skb_is_nonlinear() to decide whether to set XDP_FLAGS_HAS_FRAGS and xdp_frags_size.
That exposes frag_list data to XDP as if it were stored in frags[], but frags[] is empty. AF_XDP copy mode can then trust the bogus XDP fragment metadata, walk an empty fragment entry, and crash in memcpy() from __xsk_rcv().
Route non-linear skbs through skb_pp_cow_data() before exposing them to XDP, and only advertise XDP frags when the resulting skb has frags[]. skb_copy_bits() already handles frag_list input, and skb_pp_cow_data() builds frags[] output with skb_add_rx_frag(), which is the representation XDP multi-buffer expects.
--- drivers/net/veth.c | 4 ++-- net/core/skbuff.c | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-)
drivers/net/veth.c +2 -2
@@ -756,7 +756,7 @@ static int veth_convert_skb_to_xdp_buff(u32 frame_sz;if (skb_shared (skb) ||skb_head_is_locked (skb) || -skb_shinfo (skb)->nr_frags || +skb_is_nonlinear (skb) ||skb_headroom (skb) <XDP_PACKET_HEADROOM ) {if (skb_pp_cow_data (rq->page_pool, pskb,XDP_PACKET_HEADROOM )) goto drop;
@@ -771,7 +771,7 @@ static int veth_convert_skb_to_xdp_buff(xdp_prepare_buff (xdp, skb->head,skb_headroom (skb),skb_headlen (skb), true); -if (skb_is_nonlinear (skb)) { +if (skb_shinfo (skb)->nr_frags) {skb_shinfo (skb)->xdp_frags_size = skb->data_len;xdp_buff_set_frags_flag (xdp); }else {
net/core/skbuff.c +12 -6
@@ -895,6 +895,18 @@ static void skb_clone_fraglist(struct skskb_get (list); } +/** +* skb_pp_cow_data() - copy skb data into page-pool backed storage +* @pool: page pool to allocate from +* @pskb: pointer to skb pointer, replaced with the copied skb on success +* @headroom: headroom to reserve in the copied skb +* +* skb_copy_bits() handles both frags[] and frag_list input. If the copied +* skb remains non-linear, it uses frags[], which is the representation used +* by XDP multi-buffer. +* +* Return: 0 on success or a negative errno on failure. +*/ int skb_pp_cow_data (struct page_pool *pool,struct sk_buff **pskb,unsigned int headroom) {
@@ -904,12 +916,6 @@ int skb_pp_cow_data(struct page_pool *point err, i, head_off;void *data; -/* XDP does not support fraglist so we need to linearize -* the skb. -*/ -if (skb_has_frag_list (skb)) -return -EOPNOTSUPP ; - max_head_size =SKB_WITH_OVERHEAD (PAGE_SIZE - headroom);if (skb->len > max_head_size +MAX_SKB_FRAGS *PAGE_SIZE )return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 245/396 vxlan: re-fetch eth header after route_shortcircuit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 1395a676ec15a0a02a2a6d86602324f2d5fd41d5 upstream.
Before route_shortcircuit(), the eth header pointer is cached from eth_hdr(skb).
Inside route_shortcircuit(), pskb_may_pull() can be called, which may reallocate skb->head.
In this case, returning to vxlan_xmit() leaves the cached eth pointer pointing to freed memory, leading to a use-after-free when dereferencing eth->h_dest.
Fix this by updating eth = eth_hdr(skb) after calling route_shortcircuit().
--- drivers/net/vxlan/vxlan_core.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/vxlan/vxlan_core.c +1 -0
@@ -2798,6 +2798,7 @@ static netdev_tx_t vxlan_xmit(struct sk_ (ntohs(eth->h_proto) == ETH_P_IP || ntohs(eth->h_proto) == ETH_P_IPV6)) { did_rsc =route_shortcircuit (dev, skb); + eth =eth_hdr (skb);if (did_rsc) f =vxlan_find_mac_tx (vxlan, eth->h_dest, vni); }
Greg Kroah-Hartman
maintainerPATCH 246/396 vxlan: unclone skb head before modifying eth header in route_shortcircuit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 760d36e737f2b3867762f42af36c663f55babcc4 upstream.
When route_shortcircuit() performs L3 short-circuit routing, it modifies the Ethernet header of the skb in-place:
memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, dev->addr_len);
memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);If the incoming skb is cloned (for example by packet sockets, tcpdump, or dev_queue_xmit), modifying the Ethernet header without uncloning can corrupt the packet header for other readers holding a reference to the cloned skb.
Ensure the skb header is writable and unshared by calling skb_cow_head(skb, 0) prior to updating the Ethernet header. If skb_cow_head() fails, abort short-circuiting and return false to allow standard packet processing fallback.
--- drivers/net/vxlan/vxlan_core.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/vxlan/vxlan_core.c +4 -0
@@ -2167,6 +2167,10 @@ static bool route_shortcircuit(struct ne diff = !ether_addr_equal (eth_hdr (skb)->h_dest, n->ha);if (diff) { +if (skb_cow_head (skb,0 )) { +neigh_release (n); +return false; + }memcpy (eth_hdr (skb)->h_source,eth_hdr (skb)->h_dest, dev->addr_len);memcpy (eth_hdr (skb)->h_dest, n->ha, dev->addr_len);
Greg Kroah-Hartman
maintainerPATCH 247/396 vxlan: use neigh_ha_snapshot() in route_shortcircuit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 8eca411347e1d38964f9ed2c8d3b6ab0e7e4473d upstream.
The neighbour hardware address n->ha can be updated asynchronously by the neighbour subsystem, protected by n->ha_lock seqlock. Reading n->ha without holding the seqlock loop can lead to torn reads or reading a partially updated MAC address.
Use neigh_ha_snapshot() in route_shortcircuit() to safely copy n->ha under read_seqbegin()/read_seqretry() lock protection before using it.
Note that arp_reduce() and neigh_reduce() seem to have the same issue left for future patches.
--- drivers/net/vxlan/vxlan_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +4 -2
@@ -2163,9 +2163,11 @@ static bool route_shortcircuit(struct ne }if (n) { +u8 haddr[ETH_ALEN ];bool diff; - diff = !ether_addr_equal (eth_hdr (skb)->h_dest, n->ha); +neigh_ha_snapshot (haddr, n, dev); + diff = !ether_addr_equal_unaligned (eth_hdr (skb)->h_dest, haddr);if (diff) {if (skb_cow_head (skb,0 )) {neigh_release (n);
@@ -2173,7 +2175,7 @@ static bool route_shortcircuit(struct ne }memcpy (eth_hdr (skb)->h_source,eth_hdr (skb)->h_dest, dev->addr_len); -memcpy (eth_hdr (skb)->h_dest, n->ha, dev->addr_len); +memcpy (eth_hdr (skb)->h_dest, haddr, dev->addr_len); }neigh_release (n);return diff;
Greg Kroah-Hartman
maintainerPATCH 248/396 vxlan: use pskb_network_may_pull() for transmit path header pulls
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit b9553558b48db54ac9273e6b98d7263ef5c1a329 upstream.
In vxlan_xmit(), arp_reduce(), and vxlan_mdb_entry_skb_get(), pskb_may_pull() was being called to verify the availability of network layer headers (ARP, IPv6/ND, IP/IPv6 MDB keys).
However, during transmit skb->data points to the MAC header, so skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, len) only checks len bytes from skb->data rather than skb_network_offset(skb) + len, which can leave part of the network header in non-linear frags.
Replace these remaining pskb_may_pull() calls with pskb_network_may_pull() to properly account for the MAC header offset.
--- drivers/net/vxlan/vxlan_core.c | 6 +++--- drivers/net/vxlan/vxlan_mdb.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/vxlan/vxlan_core.c +3 -3
@@ -1852,7 +1852,7 @@ static int arp_reduce(struct net_deviceif (dev->flags &IFF_NOARP ) goto out; -if (!pskb_may_pull (skb,arp_hdr_len (dev))) { +if (!pskb_network_may_pull (skb,arp_hdr_len (dev))) {dev_dstats_tx_dropped (dev);vxlan_vnifilter_count (vxlan, vni,NULL ,VXLAN_VNI_STATS_TX_DROPS ,0 );
@@ -2765,8 +2765,8 @@ static netdev_tx_t vxlan_xmit(struct sk_return arp_reduce (dev, skb, vni); #if IS_ENABLED(CONFIG_IPV6) else if (ntohs(eth->h_proto) == ETH_P_IPV6 && - pskb_may_pull(skb, sizeof(struct ipv6hdr) + - sizeof(struct nd_msg)) && + pskb_network_may_pull(skb, sizeof(struct ipv6hdr) + + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {struct nd_msg *m = (struct nd_msg *)(ipv6_hdr (skb) +1 );
drivers/net/vxlan/vxlan_mdb.c +2 -2
@@ -1631,7 +1631,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_switch (skb->protocol) {case htons (ETH_P_IP ): -if (!pskb_may_pull (skb,sizeof (struct iphdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct iphdr )))return NULL ; group.dst.sa.sa_family =AF_INET ; group.dst.sin.sin_addr.s_addr =ip_hdr (skb)->daddr;
@@ -1640,7 +1640,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_break ;#if IS_ENABLED (CONFIG_IPV6 )case htons (ETH_P_IPV6 ): -if (!pskb_may_pull (skb,sizeof (struct ipv6hdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct ipv6hdr )))return NULL ; group.dst.sa.sa_family =AF_INET6 ; group.dst.sin6.sin6_addr =ipv6_hdr (skb)->daddr;
Greg Kroah-Hartman
maintainerPATCH 249/396 vxlan: use pskb_network_may_pull() in route_shortcircuit()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
commit 26bb2dd0a8839617e2c79ffbbe1923f8e4bab9fb upstream.
route_shortcircuit() currently calls pskb_may_pull(skb, sizeof(struct iphdr)) (or ipv6hdr), which checks if bytes are available starting from skb->data.
However, in vxlan_xmit(), skb->data points to the MAC header, so skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, 20) only checks 20 bytes from skb->data (which is 14 bytes MAC header + 6 bytes of IP header), leaving the rest of the IP header potentially un-pulled in non-linear frags. Subsequent dereferences of ip_hdr(skb)->daddr can read beyond the pulled linear buffer length.
Fix this by using pskb_network_may_pull(), which adds skb_network_offset(skb) to the length check to ensure the full network header is present in the linear buffer.
--- drivers/net/vxlan/vxlan_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/vxlan/vxlan_core.c +2 -2
@@ -2115,7 +2115,7 @@ static bool route_shortcircuit(struct ne {struct iphdr *pip; -if (!pskb_may_pull (skb,sizeof (struct iphdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct iphdr )))return false; pip =ip_hdr (skb); n =neigh_lookup (&arp_tbl, &pip->daddr, dev);
@@ -2141,7 +2141,7 @@ static bool route_shortcircuit(struct ne*/ if (!ipv6_stub->nd_tbl)return false; -if (!pskb_may_pull (skb,sizeof (struct ipv6hdr ))) +if (!pskb_network_may_pull (skb,sizeof (struct ipv6hdr )))return false; pip6 =ipv6_hdr (skb); n =neigh_lookup (ipv6_stub->nd_tbl, &pip6->daddr, dev);
Greg Kroah-Hartman
maintainerPATCH 250/396 ublk: reset kernel-owned dev_info fields in ublk_ctrl_add_dev()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <[email protected]>
commit e65848e4ce352bac9e3465099354c8b8f845391f upstream.
ublk_ctrl_add_dev() memcpy()s the userspace ublksrv_ctrl_dev_info into ub->dev_info and then fixes up the fields the driver owns, but misses ->state and ->ublksrv_pid.
A device added with ->state = UBLK_S_DEV_LIVE passes the "->state != UBLK_S_DEV_DEAD" test that ublk_stop_dev_unlocked() uses as its proxy for "a disk is attached", while ->ub_disk is still NULL, so DEL_DEV right after ADD_DEV oopses in del_gendisk(). UBLK_S_DEV_QUIESCED plus UBLK_F_USER_RECOVERY dies one step earlier, in ublk_force_abort_dev(). A poisoned ->state also gets START_USER_RECOVERY and the char device read/write path onto a device that was never started, and wedges START_DEV at -EEXIST. A poisoned ->ublksrv_pid just makes GET_DEV_INFO report an unrelated task as the ublk server.
Reset both after the memcpy(), as ublk_detach_disk() does. Userspace only ever reads these back, so correcting them silently breaks nothing.
ADD_DEV has copied ->state in unsanitized since ublk was merged, but back then it was harmless: the gendisk was allocated during ADD_DEV, and both teardown and the START_DEV -EEXIST check keyed off disk_live() rather than ->state. The oops became reachable once the disk allocation moved to START_DEV and those checks switched to ->state.
--- drivers/block/ublk_drv.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/block/ublk_drv.c +9 -0
@@ -3288,6 +3288,15 @@ static int ublk_ctrl_add_dev(const struc ub->dev_info.dev_id = ub->ub_number;/* +* ->state and ->ublksrv_pid are owned by the driver and only read back +* by userspace, but they come from the copied-in dev_info, so reset +* them. Otherwise a device added with ->state != DEAD looks live while +* ->ub_disk is still NULL. +*/ + ub->dev_info.state =UBLK_S_DEV_DEAD ; + ub->dev_info.ublksrv_pid =-1 ; + +/* * 64bit flags will be copied back to userspace as feature * negotiation result, so have to clear flags which driver * doesn't support yet, then userspace can get correct flags
Greg Kroah-Hartman
maintainerPATCH 251/396 tracing: Check return value of __register_event() in trace_module_add_events()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit ac8719969e6c3c54e939834df812bc41f25453cf upstream.
trace_module_add_events() ignores the return value of __register_event() and unconditionally calls __add_event_to_tracers() for each event.
If __register_event() fails (for example, if event_init() fails), the trace_event_call is not added to ftrace_events list, but __add_event_to_tracers() still creates a trace_event_file pointing to it. If module loading subsequently fails and module memory is freed, tracing state retains a stale trace_event_call pointer in trace_event_file, leading to a use-after-free when tracefs or tracing subsystem operations are later executed.
Fix this by checking the return value of __register_event() and only calling __add_event_to_tracers() if event registration succeeded.
--- kernel/trace/trace_events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace_events.c +2 -2
@@ -3771,8 +3771,8 @@ static void trace_module_add_events(stru end = mod->trace_events + mod->num_trace_events;for_each_event (call, start, end) { -__register_event (*call, mod); -__add_event_to_tracers (*call); +if (!__register_event (*call, mod)) +__add_event_to_tracers (*call); }update_cache_events (mod);
Greg Kroah-Hartman
maintainerPATCH 252/396 tracing/filters: Fix false positive match in regex_match_full()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit c22c7b735f9810ad276014f788f9aa5c879ec238 upstream.
regex_match_full() calls strncmp(str, r->pattern, len) where len is the target field buffer size. When len is smaller than r->len (the filter pattern length), strncmp() checks only len bytes of r->pattern against str. If those len bytes match, strncmp() returns 0, resulting in a false-positive match where a shorter string in a fixed-size field matches a longer filter pattern.
For example, a 4-byte static string field containing "abcd" matched the filter pattern "abcdefgh" because strncmp("abcd", "abcdefgh", 4) returned 0. In this case, @len does NOT include '\0' because it is fixed-size array.
Fix this by returning 0 (no match) early when len < r->len.
--- kernel/trace/trace_events_filter.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_events_filter.c +3 -0
@@ -1027,6 +1027,9 @@ static int regex_match_full(char *str, sif (!len)return strcmp (str, r->pattern) ==0 ; +if (len < r->len) +return 0 ; +return strncmp (str, r->pattern, len) ==0 ; }
Greg Kroah-Hartman
maintainerPATCH 253/396 spi: spi-qpic-snand: write the feature value before executing SET_FEATURE
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislaw Pal <[email protected]>
commit 8fd62901d6bf03f274a49dd0060793cc07dd51b0 upstream.
qcom_spi_send_cmdaddr() programs NAND_FLASH_CMD/NAND_EXEC_CMD and submits the descriptors, which makes the controller execute the command immediately. For SPINAND_SET_FEATURE the value to be written is only placed into NAND_FLASH_FEATURES afterwards, by qcom_spi_io_op(), in a second submission - so the chip is programmed with whatever that register happened to hold from a previous operation, and the intended value is only applied by the *next* SET_FEATURE.
Measured on a TP-Link Archer AX55 v1 (IPQ5018, ESMT F50L1G41LB): writing 0x40 to the configuration register (0xb0) leaves the chip at 0x00, and the subsequent write of 0x00 leaves it at 0x40 - every write lands one operation late.
This stayed unnoticed until v6.18 added SPI-NAND OTP support together with OTP entries for ESMT chips. spinand_otp_rw() enables OTP mode, reads, and disables it again, and mtd_otp_nvmem_add() does this during MTD registration. With the off-by-one, the "disable" write actually applies the previously requested value, so CFG_OTP_ENABLE ends up set:
the chip stays in OTP mode, every subsequent array read returns the OTP area instead of the array (UBI reports an empty device) and all writes fail with -EIO because the OTP area is write protected. On this board that makes the whole flash unusable and the device unbootable.
Write the feature value into NAND_FLASH_FEATURES as part of the same transaction, before NAND_EXEC_CMD. While at it, copy only the bytes the operation actually carries - the previous code dereferenced a 4-byte pointer on a one-byte buffer (spinand->scratchbuf).
With this patch the flash contents read back bit-identical to a known-good dump of the same board taken under the vendor firmware (md5-verified across partitions), and writes work.
--- drivers/spi/spi-qpic-snand.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/spi/spi-qpic-snand.c +18 -4
@@ -1362,6 +1362,22 @@ static int qcom_spi_send_cmdaddr(struct snandc->regs->addr0 =cpu_to_le32 (op->addr.val); snandc->regs->addr1 =cpu_to_le32 (0 ); +/* +* The feature value has to reach NAND_FLASH_FEATURES before the +* command is executed, otherwise the controller programs the chip +* with whatever the register happened to hold from a previous +* operation. +*/ +if (opcode ==SPINAND_SET_FEATURE ) { +u32 ftr =0 ; + +memcpy (&ftr, op->data.buf.out, +min_t (size_t, op->data.nbytes,sizeof (ftr))); + snandc->regs->flash_feature =cpu_to_le32 (ftr); +qcom_write_reg_dma (snandc, &snandc->regs->flash_feature, +NAND_FLASH_FEATURES ,1 ,NAND_BAM_NEXT_SGL ); + } +qcom_write_reg_dma (snandc, &snandc->regs->cmd,NAND_FLASH_CMD ,3 ,NAND_BAM_NEXT_SGL );qcom_write_reg_dma (snandc, &snandc->regs->exec,NAND_EXEC_CMD ,1 ,NAND_BAM_NEXT_SGL );
@@ -1399,10 +1415,8 @@ static int qcom_spi_io_op(struct qcom_na copy_ftr = true;break ;case SPINAND_SET_FEATURE : - snandc->regs->flash_feature =cpu_to_le32 (*(u32 *)op->data.buf.out); -qcom_write_reg_dma (snandc, &snandc->regs->flash_feature, -NAND_FLASH_FEATURES ,1 ,NAND_BAM_NEXT_SGL ); -break ; +/* fully handled by qcom_spi_send_cmdaddr() */ +return 0 ;case SPINAND_PROGRAM_EXECUTE :case SPINAND_WRITE_EN :case SPINAND_RESET :
Greg Kroah-Hartman
maintainerPATCH 254/396 spi: qcom-qspi: Correct max DMA length to avoid 64K boundary failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vijaya Krishna Nivarthi <[email protected]>
commit 90ef2f2961c2dc55957dafe2f53b3efdb4675efc upstream.
The maximum size for a DMA data descriptor is 64KB-1 because the size field in HW is 16 bits wide. For this reason, transfers fail at 64KB and beyond.
Lower max_dma_len to 60KB so larger transfers are split into multiple DMA blocks and do not hit the failing 64KB boundary. 60KB is chosen as a safe round number below the 64KB-1 hardware limit while satisfying alignment requirements.
Tested on x1e80100 (Hamoa) with SPI-NOR flash (/dev/mtd0):
Without patch:
dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=32768 count=2 # works dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=65536 count=1 # fails
With patch:
dd if=/dev/mtd0 of=/tmp/spi_dump.bin bs=65536 count=1 # works
--- drivers/spi/spi-qcom-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-qcom-qspi.c +2 -1
@@ -759,7 +759,8 @@ static int qcom_qspi_probe(struct platforeturn dev_err_probe (dev, ret,"could not set DMA mask\n" ); host->max_speed_hz =300000000 ; - host->max_dma_len =65536 ;/* as per HPG */ +/* as per HPG, it is 64KB, limit to 60KB to avoid boundary condition failures */ + host->max_dma_len =0xf000 ; host->dma_alignment =QSPI_ALIGN_REQ ; host->num_chipselect =QSPI_NUM_CS ; host->bus_num =-1 ;
Greg Kroah-Hartman
maintainerPATCH 255/396 selftests/mm: fix potential wild pointer access of getline due to missing init
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Gellermann <[email protected]>
commit 9f1d75a4ce04095afdb63d8e540092ff8151dacf upstream.
This is another occurrence of using getline where the code assumes that getline allocates memory to store the line, but the pointer passed to it is uninitialized and potentially a non-null pointer. This violates the Open Group Spec[1] and caused a segfault in a similar situation in selftest/clone3/clone3_set_tid. Fix it by initializing the line pointer to NULL.
The issue has been found by simply grepping through the selftest code after running into the issue in clone3_set_tid. Whether it segfaults in its current state is unknown to me. But it's good to be addressed due to defensive reasons.
--- tools/testing/selftests/mm/mlock-random-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/mm/mlock-random-test.c +1 -1
@@ -84,7 +84,7 @@ int get_proc_locked_vm_size(void)int get_proc_page_size (unsigned long addr) {FILE *smaps; -char *line; +char *line =NULL ;unsigned long mmupage_size =0 ;size_t size;
Greg Kroah-Hartman
maintainerPATCH 256/396 selftests/clone3: fix wild pointer access of getline due to missing init
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Gellermann <[email protected]>
commit 8f6f9fd93cd7a5dd607ad5cd910476dd68fff3ed upstream.
Patch series "selftests: Add missing initalization of pointer passed to getline", v2.
This patch (of 2):
Clone3_set_tid uses getline(&line, ...) in a loop to read the child's process status. The code expects that getline allocates the buffer for the line on the first loop iteration. According to the Open Group Spec[1], char *line has to be null pointer for this:
Quoted 3 lines
ssize_tgetline(char **restrict lineptr, ...);
If *lineptr is a null pointer or if the object pointed to by *lineptr is of insufficient size, an object shall be allocated as if by
malloc()
Quoted 1 line
or the object shall be reallocated as if by realloc()[...].
However, char *line is only declared, leading to an undefined value that is potentially non-null. In an example run with Musl v1.2.6, the realloc call[2] of getdelim, which implements getline, triggers a segfault:
./run_kselftest.sh --test clone3:clone3_set_tid
[ 1366.165898] kselftest: Running tests in clone3 ... [ 1367.799244] clone3_set_tid[811]: unhandled signal 11 code 0x1 at 0x0000000000000000 in libc.so[68184,3fbf69f000+4c000] [ 1367.802808] CPU: 0 UID: 0 PID: 811 Comm: clone3_set_tid Not tainted .. [ 1367.804188] epc: 0x0000003fbf6b0184 [ 1367.804188] ra : 0x0000003fbf6d4664 [ 1367.804188] sp : 0x0000003fce5f2e40 [ 1367.805314] gp : 0x0000002aaab0dfb8 [ 1367.805314] tp : 0x0000003fbf6f14a8 [ 1367.805314] t0 : 0x0000003fbf63d000
...
Looking at the realloc implementation, Musl mallocs for a null pointer memory. But for a non-null pointer, it assumes it's passed a valid pointer to the heap and tries to access its meta-data. This leads to the segfault we see:
void *realloc(void *p, size_t n)
{
if (!p) return malloc(n);
if (size_overflows(n)) return 0;
struct meta *g = get_meta(p);
...
}Fix this by properly initializing the line pointer to NULL.
--- tools/testing/selftests/clone3/clone3_set_tid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/clone3/clone3_set_tid.c +1 -1
@@ -141,7 +141,7 @@ int main(int argc, char *argv[]) {FILE *f;char buf; -char *line; +char *line =NULL ;int status;int ret =-1 ;size_t len =0 ;
Greg Kroah-Hartman
maintainerPATCH 257/396 scsi: scsi_debug: Fix REPORT ZONES alloc_len underflow OOB write
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit 93dde0bf2f39a0f9f57fd610aa3201ce5b753433 upstream.
resp_report_zones() sizes the reply buffer from the CDB allocation length. The v3 fix rounds alloc_len up with ALIGN() before deriving the descriptor count:
rep_max_zones = (ALIGN((u64)alloc_len, RZONES_DESC_HD) - RZONES_DESC_HD) >> ilog2(RZONES_DESC_HD); arr_len = (u64)RZONES_DESC_HD * (rep_max_zones + 1);
For alloc_len in 0xFFFFFFC1..0xFFFFFFFF, ALIGN() rounds up to 0x100000000, so arr_len is 4 GB. On 32-bit, kzalloc()'s size_t is 32-bit and truncates 0x100000000 to 0; kzalloc(0) returns ZERO_SIZE_PTR, which passes the !arr check, and desc = arr + 64 is then dereferenced in the loop -> out-of-bounds write / panic.
Clamp rep_max_zones to devip->nr_zones. The loop already stops at sdebug_capacity (after nr_zones zones), so a report can never hold more than nr_zones descriptors; the clamp does not change the report, it only bounds arr_len to (nr_zones + 1) * RZONES_DESC_HD, a real device property that can never reach 0x100000000.
--- drivers/scsi/scsi_debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/scsi/scsi_debug.c +6 -2
@@ -5896,6 +5896,7 @@ static int resp_report_zones(struct scsiu32 alloc_len, rep_opts, rep_len;bool partial;u64 lba, zs_lba; +u64 arr_len;u8 *arr =NULL , *desc;u8 *cmd = scp->cmnd;struct sdeb_zone_state *zsp =NULL ;
@@ -5917,9 +5918,12 @@ static int resp_report_zones(struct scsireturn check_condition_result; } - rep_max_zones = (alloc_len -64 ) >>ilog2 (RZONES_DESC_HD ); + rep_max_zones = (ALIGN ((u64 )alloc_len,RZONES_DESC_HD ) -RZONES_DESC_HD ) >> +ilog2 (RZONES_DESC_HD ); + rep_max_zones = min_t(unsigned int, rep_max_zones, devip->nr_zones); + arr_len = (u64 )RZONES_DESC_HD * (rep_max_zones +1 ); - arr =kzalloc (alloc_len,GFP_ATOMIC | __GFP_NOWARN); + arr =kzalloc (arr_len,GFP_ATOMIC | __GFP_NOWARN);if (!arr) {mk_sense_buffer (scp,ILLEGAL_REQUEST ,INSUFF_RES_ASC ,INSUFF_RES_ASCQ );
Greg Kroah-Hartman
maintainerPATCH 258/396 sctp: reject stale cookies with mismatched verification tags
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
commit 9d8da8e0a9bce4a340af60dd0446bc7eb8d07587 upstream.
sctp_unpack_cookie() skips cookie expiration checks whenever an association already exists. This is broader than the exception in RFC 9260 Section 5.2.4.
For an existing association, Section 5.2.4 permits an expired State Cookie only when both Verification Tags in the cookie match the current association. Otherwise, the packet SHOULD be discarded and a Stale Cookie ERROR MUST be sent.
The broad check lets an expired Action A restart cookie reach sctp_sf_do_dupcook_a(). In a runtime test with the default 60 second cookie lifetime, replaying such a cookie after 65 seconds returned a COOKIE-ACK and restarted the association.
Check cookie expiration unless both Verification Tags match. This preserves the Action D exception for a lost COOKIE ACK while rejecting expired cookies in all other cases.
--- net/sctp/sm_make_chunk.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
net/sctp/sm_make_chunk.c +7 -4
@@ -1802,9 +1802,9 @@ struct sctp_association *sctp_unpack_coo goto fail; } -/* Check to see if the cookie is stale. If there is already -* an association, there is no need to check cookie's expiration -* for init collision case of lost COOKIE ACK. +/* Check to see if the cookie is stale. RFC 9260 Section 5.2.4 +* exempts an expired cookie only when both Verification Tags match +* the current association. * If skb has been timestamped, then use the stamp, otherwise * use current time. This introduces a small possibility that * a cookie may be considered expired, but this would only slow
@@ -1815,7 +1815,10 @@ struct sctp_association *sctp_unpack_cooelse kt =ktime_get_real (); -if (!asoc &&ktime_before (bear_cookie->expiration, kt)) { +if ((!asoc || + asoc->c.my_vtag != bear_cookie->my_vtag || + asoc->c.peer_vtag != bear_cookie->peer_vtag) && +ktime_before (bear_cookie->expiration, kt)) {suseconds_t usecs =ktime_to_us (ktime_sub (kt, bear_cookie->expiration));__be32 n =htonl (usecs);
Greg Kroah-Hartman
maintainerPATCH 259/396 sctp: prevent peer transport count overflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit bd0e9289e2642f6a5c54faad304ce0f41e926d22 upstream.
sctp_assoc_add_peer() increments the association's 16-bit transport_count for every new unique peer. Adding the 65,536th transport wraps the count to zero.
SCTP sock_diag uses transport_count to reserve the INET_DIAG_PEERS payload, then copies one sockaddr_storage for every entry in transport_addr_list. After the wrap, a diagnostic dump reserves an empty payload and writes 8 MiB of peer addresses past the skb tail.
Reject a new unique peer when transport_count has reached U16_MAX. Perform the check after the existing-peer lookup so a duplicate address continues to return its existing transport at the limit.
--- net/sctp/associola.c | 3 +++ 1 file changed, 3 insertions(+)
net/sctp/associola.c +3 -0
@@ -614,6 +614,9 @@ struct sctp_transport *sctp_assoc_add_pereturn peer; } +if (asoc->peer.transport_count ==U16_MAX ) +return NULL ; + peer =sctp_transport_new (asoc->base.net, addr, gfp);if (!peer)return NULL ;
Greg Kroah-Hartman
maintainerPATCH 260/396 hwmon: (npcm750-pwm-fan): stop fan timer on device detach
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
commit f27f6976ea269219c1259a7c2f8c6dfe782540a3 upstream.
When a fan tach channel is present, npcm7xx_pwm_fan_probe() starts fan_timer. The timer callback polls tach state and rearms the timer, but the driver has no remove callback or devm cleanup action to stop it. On device detach, the devm-managed driver data and I/O mappings can be released while the timer is still pending or running.
Register a devm cleanup action before starting the timer and shut the timer down synchronously from that action.
This issue was found by a static analysis tool.
--- drivers/hwmon/npcm750-pwm-fan.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/hwmon/npcm750-pwm-fan.c +11 -0
@@ -364,6 +364,11 @@ static void npcm7xx_fan_polling(struct tadd_timer (&data->fan_timer); } +static void npcm7xx_fan_cleanup (void *timer) +{ +timer_shutdown_sync (timer); +} +static inline void npcm7xx_fan_compute (struct npcm7xx_pwm_fan_data *data,u8 fan,u8 cmp,u8 fan_id,u8 flag_int,u8 flag_mode,u8 flag_clear)
@@ -1027,6 +1032,12 @@ static int npcm7xx_pwm_fan_probe(structmsecs_to_jiffies (NPCM7XX_FAN_POLL_TIMER_200MS );timer_setup (&data->fan_timer, npcm7xx_fan_polling,0 ); + ret =devm_add_action_or_reset (dev, + npcm7xx_fan_cleanup, + &data->fan_timer); +if (ret) +return ret; +add_timer (&data->fan_timer);break ; }
Greg Kroah-Hartman
maintainerPATCH 261/396 hwmon: (pmbus/core) notify on the hwmon device, not the i2c client
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Jardin <[email protected]>
commit a64a7e8a0b012ba81b0eadbd7afc84ab0dbfd70c upstream.
pmbus_notify() calls sysfs_notify() and kobject_uevent() on the i2c client's kobject, but the alarm attributes live on the hwmon class device registered by pmbus_do_probe(). Notifying the parent i2c device is a no-op for both poll(POLLPRI) waiters and udev listeners: the named attribute does not exist on that kobject.
Notify the hwmon device instead, so poll() wakes up and "change" uevents fire on the inX_alarm/tempX_alarm attributes when SMBALERT# reports a fault.
--- drivers/hwmon/pmbus/pmbus_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +3 -2
@@ -2977,8 +2977,9 @@ static void pmbus_notify(struct pmbus_daif (reg == sreg && page == spage && (smask & flags)) {dev_dbg (data->dev,"sysfs notify: %s" , da->attr.name); -sysfs_notify (&data->dev->kobj,NULL , da->attr.name); -kobject_uevent (&data->dev->kobj,KOBJ_CHANGE ); +sysfs_notify (&data->hwmon_dev->kobj,NULL , + da->attr.name); +kobject_uevent (&data->hwmon_dev->kobj,KOBJ_CHANGE ); flags &= ~smask; }
Greg Kroah-Hartman
maintainerPATCH 262/396 i2c: amd-mp2: Unregister callback on adapter add failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 82048795242f04275a3f49ffc66ad851b6120954 upstream.
amd_mp2_register_cb() stores the platform I2C context in the MP2 PCI driver's callback table before the adapter is registered. If i2c_add_adapter() fails, probe returns and devres frees the context, but the PCI driver can still dereference the stale pointer from its IRQ and system-sleep callbacks.
Unregister the callback before returning the adapter registration error.
--- drivers/i2c/busses/i2c-amd-mp2-plat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-amd-mp2-plat.c +3 -1
@@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platformamd_mp2_pm_runtime_put (mp2_dev); -if (ret <0 ) +if (ret <0 ) {dev_err (&pdev->dev,"i2c add adapter failed = %d\n" , ret); +amd_mp2_unregister_cb (&i2c_dev->common); + }return ret; }
Greg Kroah-Hartman
maintainerPATCH 263/396 gpio: pca953x: fix cache_only and IRQ state on restore_context() failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: bui duc phuc <[email protected]>
commit d233087c19f6607ef926ac3f47d776e2406ffd1f upstream.
When pca953x_restore_context() fails, cache_only is left disabled and the IRQ left enabled, even though register synchronization may not have completed successfully. Restore cache_only and disable the IRQ again on failure, matching the state set by pca953x_save_context().
--- drivers/gpio/gpio-pca953x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/gpio/gpio-pca953x.c +13 -2
@@ -1370,9 +1370,20 @@ static int pca953x_restore_context(strucregcache_mark_dirty (chip->regmap); ret =pca953x_regcache_sync (chip);if (ret) -return ret; + goto err; -return regcache_sync (chip->regmap); + ret =regcache_sync (chip->regmap); +if (ret) + goto err; + +return 0 ; + +err: +if (chip->client->irq >0 ) +disable_irq (chip->client->irq); +regcache_cache_only (chip->regmap, true); + +return ret; }static void pca953x_save_context (struct pca953x_chip *chip)
Greg Kroah-Hartman
maintainerPATCH 264/396 gpio: pch: use raw_spinlock_t for the register lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junjie Cao <[email protected]>
commit a02b8950d619123da64f69b70fe1dadef217dfe4 upstream.
pch_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid.
This was confirmed on a PREEMPT_RT kernel with lockdep (PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP). A grounded PoC mirrored pch_irq_type()'s locking and drove it through the real genirq carrier irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e. the same __irq_set_trigger() edge that __setup_irq() takes for a requested IRQ. With the original spin_lock_irqsave() edge lockdep reported an invalid wait context, immediately followed by:
BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60 rt_spin_lock+0x3a/0x1c0 repro_irq_set_type+0x64/0xa0 [pch_repro] __irq_set_trigger+0x69/0x140 irq_set_irq_type+0x78/0xd0
Switching the mirrored lock to raw_spinlock_t made both splats go away.
Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, but all of those critical sections only perform MMIO register accesses (ioread32()/iowrite32()) and irq_set_handler_locked(); none of them contain sleepable operations. Keeping this register lock non-sleeping is therefore appropriate for the irqchip callbacks and does not change the GPIO-side locking contract.
This is the same class of issue and fix as recently addressed for other GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use raw_spinlock_t in the irq startup path").
--- drivers/gpio/gpio-pch.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/gpio/gpio-pch.c +14 -14
@@ -96,7 +96,7 @@ struct pch_gpio {struct pch_gpio_reg_data pch_gpio_reg;int irq_base;enum pch_type_t ioh; -spinlock_t spinlock; +raw_spinlock_t spinlock; };static int pch_gpio_set (struct gpio_chip *gpio,unsigned int nr,int val)
@@ -105,7 +105,7 @@ static int pch_gpio_set(struct gpio_chipstruct pch_gpio *chip =gpiochip_get_data (gpio);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); reg_val =ioread32 (&chip->reg->po);if (val) reg_val |=BIT (nr);
@@ -113,7 +113,7 @@ static int pch_gpio_set(struct gpio_chip reg_val &= ~BIT (nr);iowrite32 (reg_val, &chip->reg->po); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -133,7 +133,7 @@ static int pch_gpio_direction_output(stru32 reg_val;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); reg_val =ioread32 (&chip->reg->po);if (val)
@@ -147,7 +147,7 @@ static int pch_gpio_direction_output(str pm |=BIT (nr);iowrite32 (pm, &chip->reg->pm); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -158,12 +158,12 @@ static int pch_gpio_direction_input(struu32 pm;unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags); pm =ioread32 (&chip->reg->pm); pm &=BIT (gpio_pins[chip->ioh]) -1 ; pm &= ~BIT (nr);iowrite32 (pm, &chip->reg->pm); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -265,7 +265,7 @@ static int pch_irq_type(struct irq_datareturn 0 ; } -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);/* Set interrupt mode */ im =ioread32 (im_reg) & ~(PCH_IM_MASK << (im_pos *4 ));
@@ -277,7 +277,7 @@ static int pch_irq_type(struct irq_dataelse if (type &IRQ_TYPE_EDGE_BOTH )irq_set_handler_locked (d, handle_edge_irq); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -374,7 +374,7 @@ static int pch_gpio_probe(struct pci_dev chip->ioh = id->driver_data; chip->reg = chip->base;pci_set_drvdata (pdev, chip); -spin_lock_init (&chip->spinlock); +raw_spin_lock_init (&chip->spinlock);pch_gpio_setup (chip); ret =devm_gpiochip_add_data (dev, &chip->gpio, chip);
@@ -407,9 +407,9 @@ static int __maybe_unused pch_gpio_suspestruct pch_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);pch_gpio_save_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
@@ -419,11 +419,11 @@ static int __maybe_unused pch_gpio_resumstruct pch_gpio *chip =dev_get_drvdata (dev);unsigned long flags; -spin_lock_irqsave (&chip->spinlock, flags); +raw_spin_lock_irqsave (&chip->spinlock, flags);iowrite32 (0x01 , &chip->reg->reset);iowrite32 (0x00 , &chip->reg->reset);pch_gpio_restore_reg_conf (chip); -spin_unlock_irqrestore (&chip->spinlock, flags); +raw_spin_unlock_irqrestore (&chip->spinlock, flags);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 265/396 cifs: add fscache_resize_cookie() to cifs_setsize()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <[email protected]>
commit fa724e235cfdb0fb0bb427d0f9dfe864ae27403e upstream.
Several code paths update the VFS inode size by calling netfs_resize_file() and cifs_setsize(), but omit the corresponding fscache_resize_cookie() call, leaving the fscache cookie out of sync with the actual file size:
- cifs_file_set_size() in inode.c: server-side truncation via setattr
- cifs_do_truncate() in file.c: truncates to zero on O_TRUNC open
- smb2_duplicate_extents() in smb2ops.c: file clone extending EOF
- smb3_simple_falloc() in smb2ops.c: two branches that extend EOF via write-range and SMB2_set_eof respectively
Since every caller of cifs_setsize() must resize the fscache cookie, add the call to cifs_setsize() itself, consistent with how truncate_pagecache() is already consolidated there.
--- fs/smb/client/inode.c | 1 + 1 file changed, 1 insertion(+)
fs/smb/client/inode.c +1 -0
@@ -3039,6 +3039,7 @@ void cifs_setsize(struct inode *inode, linode_set_mtime_to_ts (inode,inode_set_ctime_current (inode));truncate_pagecache (inode, offset);netfs_wait_for_outstanding_io (inode); +fscache_resize_cookie (cifs_inode_cookie (inode), offset); } int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
Greg Kroah-Hartman
maintainerPATCH 266/396 cpufreq: powernow-k8: Fix possible memory leak in powernowk8_cpu_init()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit d5f8e5f6040d052d44fcbf4f31dd35145c0c8d7d upstream.
The memory allocated for data->powernow_table inside powernow_k8_cpu_init_acpi() or find_psb_table() is not freed in one of the error paths in powernowk8_cpu_init(). Fix that by adding a kfree().
--- drivers/cpufreq/powernow-k8.c | 1 + 1 file changed, 1 insertion(+)
drivers/cpufreq/powernow-k8.c +1 -0
@@ -1083,6 +1083,7 @@ static int powernowk8_cpu_init(struct cp err_out_exit_acpi:powernow_k8_cpu_exit_acpi (data); +kfree (data->powernow_table); err_out:kfree (data);
Greg Kroah-Hartman
maintainerPATCH 267/396 cpufreq: schedutil: Publish util hooks only after all sg_cpu are initialized
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhongqiu Han <[email protected]>
commit f0a3f042293a8c5a2152346b3637ea60866c503a upstream.
Commit 16a03c71bba0 ("cpufreq: schedutil: Merge initialization code of sg_cpu in single loop") merged the per-CPU initialization and the utilization-hook registration into a single loop in sugov_start().
For a shared cpufreq policy this re-introduces the race originally fixed by commit ab2f7cf141aa ("cpufreq: schedutil: Fix sugov_start() versus sugov_update_shared() race").
The scheduler's util path reaches the hook under RCU-sched and never takes policy->rwsem, so the rwsem held across sugov_start() cannot serialize the two. Once the first CPU's hook is published, sugov_update_shared() may run and, via sugov_next_freq_shared(), read/write each sibling sugov_cpu (iowait_boost, util, bw_min, ...) concurrently with the memset() still initializing them, with no lock common to both sides: the update side holds sg_policy->update_lock while the init side holds only policy->rwsem, which the scheduler's util path never takes.
The walk only accesses scalar members, never a pointer like ->sg_policy, so it does not crash today; it merely uses stale (or zero on first start) values that skew the frequency selection and tracepoints. It is still a genuine data race, and a latent crash once any pointer member is dereferenced there.
Restore the two-phase approach: initialize all per-CPU structures first, and only then publish the per-CPU utilization update hooks.
--- kernel/sched/cpufreq_schedutil.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
kernel/sched/cpufreq_schedutil.c +11 -0
@@ -870,8 +870,19 @@ static int sugov_start(struct cpufreq_pomemset (sg_cpu,0 ,sizeof (*sg_cpu)); sg_cpu->cpu = cpu; sg_cpu->sg_policy = sg_policy; + } + +/* +* Publish the hooks only after all per-CPU data is initialized, so a +* shared policy's sugov_update_shared() never reads an uninitialized +* sibling sugov_cpu. +*/ +for_each_cpu (cpu, policy->cpus) { +struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); +cpufreq_add_update_util_hook (cpu, &sg_cpu->update_util, uu); } +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 268/396 power: supply: bq25890: fix the -10 C NTC lookup entry
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 160a783aa65b74782bc17cb874af1a6d3f5fba3c upstream.
The TSPCT lookup table is monotonically decreasing except for ADC code 121, where the sequence reads -9.0 C, -1.0 C, -12.0 C. This makes the reported battery temperature jump upward by eight degrees for one code and then downward by eleven degrees for the next code.
The entry is a missing zero: use -10.0 C so the sequence remains monotonic between -9.0 C and -12.0 C.
--- drivers/power/supply/bq25890_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/bq25890_charger.c +1 -1
@@ -320,7 +320,7 @@ static const u32 bq25890_tspct_tbl[] = {145 ,140 ,130 ,120 ,115 ,110 ,100 ,90 ,80 ,70 ,60 ,50 ,40 ,30 ,20 ,10 ,0 ,-10 ,-20 ,-30 ,-40 ,-60 ,-70 ,-80 , - -90, -10, -120, -140, -150, -170, -190, -210, + -90, -100, -120, -140, -150, -170, -190, -210, };#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl)
Greg Kroah-Hartman
maintainerPATCH 269/396 power: supply: max17040: handle missing status supplier
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianing Li <[email protected]>
commit 725668c6b6aa3971fe850659102c250d0d676e18 upstream.
MAX17040 does not report charger state itself, so the driver forwards POWER_SUPPLY_PROP_STATUS to a supplier power supply. If no supplier is registered, power_supply_get_property_from_supplier() returns -ENODEV and leaves the output value untouched.
max17040_get_property() currently ignores that error and returns success, so userspace can read an uninitialized status value from the battery power supply. This happens on systems that use the fuel gauge without a charger supplier relationship in firmware.
Return POWER_SUPPLY_STATUS_UNKNOWN when no supplier provides STATUS, and propagate other supplier lookup errors.
--- drivers/power/supply/max17040_battery.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/power/supply/max17040_battery.c +5 -1
@@ -405,7 +405,11 @@ static int max17040_get_property(struct val->intval = chip->low_soc_alert;break ;case POWER_SUPPLY_PROP_STATUS : -power_supply_get_property_from_supplier (psy, psp, val); + ret =power_supply_get_property_from_supplier (psy, psp, val); +if (ret == -ENODEV ) + val->intval =POWER_SUPPLY_STATUS_UNKNOWN ; +else if (ret) +return ret;break ;case POWER_SUPPLY_PROP_TEMP :if (!chip->channel_temp)
Greg Kroah-Hartman
maintainerPATCH 270/396 s390/pci: Fix s390_pci_mmio_write syscall error return without MIO
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Schnelle <[email protected]>
commit b7ab86bdc65eadcfc43a0e3faf682a3f750cfb96 upstream.
On a machine without PCI memory-I/O (MIO) support or when running with pci=nomio the s390 specific PCI MMIO write syscall checks if the MMIO cookie is above ZPCI_IOMAP_ADDR_BASE as a sanity check before even trying to perform the MMIO. If this check fails the return value was left unchanged and thus 0 from prior operations falsely indicating success. This could potentially confuse user-space into falsely believing the MMIO, on a mapping not valid for MMIO was successful.
Fix this by setting the return value to -EFAULT prior to the check following the same pattern as elsewhere in the same function.
--- arch/s390/pci/pci_mmio.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/pci/pci_mmio.c +1 -0
@@ -188,6 +188,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, uns goto out_unlock_mmap; } + ret = -EFAULT ; io_addr = (void __iomem *)((args.pfn <<PAGE_SHIFT ) | (mmio_addr & ~PAGE_MASK ));
Greg Kroah-Hartman
maintainerPATCH 271/396 s390/qeth: Check CAP_NET_ADMIN for private ioctls
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aswin Karuvally <[email protected]>
commit d211028bac1bd0fff0026bfa2a8328e5b78cd0e6 upstream.
Gate the SIOCDEVPRIVATE ioctl commands SIOC_QETH_ADP_SET_SNMP_CONTROL, SIOC_QETH_GET_CARD_TYPE and SIOC_QETH_QUERY_OAT with CAP_NET_ADMIN capable check to ensure unprivileged users cannot invoke them.
--- drivers/s390/net/qeth_core_main.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/net/qeth_core_main.c +3 -0
@@ -6528,6 +6528,9 @@ int qeth_siocdevprivate(struct net_devicstruct qeth_card *card = dev->ml_priv;int rc =0 ; +if (!capable (CAP_NET_ADMIN )) +return -EPERM ; +switch (cmd) {case SIOC_QETH_ADP_SET_SNMP_CONTROL : rc =qeth_snmp_command (card, data);
Greg Kroah-Hartman
maintainerPATCH 272/396 s390/dasd: Fix potential NULL pointer dereference
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Höppner <[email protected]>
commit 9973026f572db6b67570cadc30942f3014e41079 upstream.
dasd_release_space() checks the implementation of the is_ese() discipline function before calling it to determine if a given device is an ESE DASD.
The current usage of the logical AND operator will lead to a NULL pointer dereference as the function is called even if the function pointer is NULL.
Fix this by using the logical OR operator.
--- drivers/s390/block/dasd_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/block/dasd_ioctl.c +1 -1
@@ -325,7 +325,7 @@ out_err:static int dasd_release_space (struct dasd_device *device,struct format_data_t *rdata) { -if (!device->discipline->is_ese && !device->discipline->is_ese (device)) +if (!device->discipline->is_ese || !device->discipline->is_ese (device))return -ENOTSUPP ;if (!device->discipline->release_space)return -ENOTSUPP ;
Greg Kroah-Hartman
maintainerPATCH 273/396 s390/dasd: Fix undersized format-check buffer
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Haberland <[email protected]>
commit 7f40b346462f563a0d6e841a77b5163d2a882a04 upstream.
fmt_buffer_size in dasd_eckd_check_device_format() is declared as int, even though one of the multiplicands, sizeof(struct eckd_count), is a size_t. The expression
trkcount * rpt_max * sizeof(struct eckd_count)
is therefore correctly evaluated at 64-bit width, but the result is silently truncated when it is stored back into the 32-bit fmt_buffer_size variable. For a sufficiently large track range (start_unit/stop_unit are caller-controlled) this truncation yields a buffer size far smaller than the number of tracks actually requested. kzalloc() then succeeds with an undersized allocation, while the subsequent channel program build still operates on the untruncated track count and writes past the end of that buffer.
Compute the buffer size with check_mul_overflow() and keep it in a size_t, so that a value that no longer fits results in -EINVAL instead of a silently truncated allocation size.
--- drivers/s390/block/dasd_eckd.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/s390/block/dasd_eckd.c +7 -4
@@ -21,6 +21,7 @@#include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/io.h> +#include <linux/overflow.h> #include <asm/css_chars.h> #include <asm/machine.h>
@@ -3476,11 +3477,11 @@ static int dasd_eckd_check_device_format {struct dasd_eckd_private *private = base->private;struct eckd_count *fmt_buffer; -struct irb irb; +size_t fmt_buffer_size; +unsigned int trkcount;int rpt_max, rpt_exp; -int fmt_buffer_size; +struct irb irb;int trk_per_cyl; -int trkcount;int tpm =0 ;int rc;
@@ -3491,7 +3492,9 @@ static int dasd_eckd_check_device_format rpt_exp =recs_per_track (&private->rdc_data,0 , cdata->expect.blksize); trkcount = cdata->expect.stop_unit - cdata->expect.start_unit +1 ; - fmt_buffer_size = trkcount * rpt_max *sizeof (struct eckd_count ); +if (check_mul_overflow (trkcount, rpt_max, &fmt_buffer_size) || +check_mul_overflow (fmt_buffer_size,sizeof (struct eckd_count ), &fmt_buffer_size)) +return -EINVAL ; fmt_buffer =kzalloc (fmt_buffer_size,GFP_KERNEL |GFP_DMA );if (!fmt_buffer)
Greg Kroah-Hartman
maintainerPATCH 274/396 s390/zcrypt: Fix wrong domain value verification with EP11 CPRBs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
commit 983279d7f86ade73db86f886e09172dd567031b5 upstream.
There is a wrong upper limit check for the domain value when an EP11 CPRB is processed for sending to a crypto card. This check is only active on custom device nodes but may lead to access heap memory behind perms->adm when an administrative CPRB is sent. Add correct limit (AP_DOMAINS = 256) checking to fix this.
--- drivers/s390/crypto/zcrypt_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/crypto/zcrypt_api.c +1 -1
@@ -1083,7 +1083,7 @@ static long _zcrypt_send_ep11_cprb(u32 xprint_hex_dump_debug ("ep11req: " ,DUMP_PREFIX_ADDRESS ,16 ,1 , ap_msg.msg, ap_msg.len, false); -if (perms != &ap_perms && domain <AUTOSEL_DOM ) { +if (perms != &ap_perms && domain <AP_DOMAINS ) {if (ap_msg.flags &AP_MSG_FLAG_ADMIN ) {if (!test_bit_inv (domain, perms->adm)) { rc = -ENODEV ;
Greg Kroah-Hartman
maintainerPATCH 275/396 s390/zcrypt: Fix buffer over-read in cca_cipher2protkey
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
commit 36b230835b8a008266aad22168ca52afacc8a58d upstream.
Add validation of both the actual key buffer size and token length fields in all the cca_check_sec*token() functions. Additionally check in cca_gencipherkey() for possible underflow with returned key size.
The CCA token structures contain user-controlled len fields that were used in operations without proper validation against both the actual buffer size and minimum token structure size. An attacker could set this field larger than the actual buffer size, leading to reading beyond buffer boundaries. This may result in a kernel crash or exposure of memory via sending this as part of a request down to the crypto card. Also an attacker could have used a very small len value and thus enforce a buffer under-run which may produce similar effects as a over-read.
So now a key must
- key buf length must be at least sizeof the token struct
- the key len field inside the token must fit into the range of sizeof key token struct ... key buf length
--- drivers/s390/crypto/pkey_cca.c | 15 ++------ drivers/s390/crypto/zcrypt_ccamisc.c | 64 +++++++++++++++++++++++++++++------ drivers/s390/crypto/zcrypt_ccamisc.h | 6 +-- 3 files changed, 62 insertions(+), 23 deletions(-)
drivers/s390/crypto/pkey_cca.c +5 -10
@@ -233,22 +233,16 @@ static int cca_key2protkey(const structif (hdr->type ==TOKTYPE_CCA_INTERNAL && hdr->version ==TOKVER_CCA_AES ) {/* CCA AES data key */ -if (keylen <sizeof (struct secaeskeytoken )) -return -EINVAL ; -if (cca_check_secaeskeytoken (pkey_dbf_info,3 , key,0 )) +if (cca_check_secaeskeytoken (pkey_dbf_info,3 , key, keylen,0 ))return -EINVAL ; }else if (hdr->type ==TOKTYPE_CCA_INTERNAL && hdr->version ==TOKVER_CCA_VLSC ) {/* CCA AES cipher key */ -if (keylen < hdr->len) -return -EINVAL ;if (cca_check_secaescipherkey (pkey_dbf_info, -3 , key,0 ,1 )) +3 , key, keylen,0 ,1 ))return -EINVAL ; }else if (hdr->type ==TOKTYPE_CCA_INTERNAL_PKA ) {/* CCA ECC (private) key */ -if (keylen <sizeof (struct eccprivkeytoken )) -return -EINVAL ;if (cca_check_sececckeytoken (pkey_dbf_info,3 , key, keylen,1 ))return -EINVAL ; }else {
@@ -476,7 +470,7 @@ static int cca_verifykey(const u8 *key, hdr->version == TOKVER_CCA_AES) {struct secaeskeytoken *t = (struct secaeskeytoken *)key; - rc =cca_check_secaeskeytoken (pkey_dbf_info,3 , key,0 ); + rc =cca_check_secaeskeytoken (pkey_dbf_info,3 , key, keylen,0 );if (rc) goto out; *keytype =PKEY_TYPE_CCA_DATA ;
@@ -504,7 +498,8 @@ static int cca_verifykey(const u8 *key, hdr->version == TOKVER_CCA_VLSC) {struct cipherkeytoken *t = (struct cipherkeytoken *)key; - rc =cca_check_secaescipherkey (pkey_dbf_info,3 , key,0 ,1 ); + rc =cca_check_secaescipherkey (pkey_dbf_info,3 , + key, keylen,0 ,1 );if (rc) goto out; *keytype =PKEY_TYPE_CCA_CIPHER ;
drivers/s390/crypto/zcrypt_ccamisc.c +54 -10
141 lines not on this page · raw message
drivers/s390/crypto/zcrypt_ccamisc.h +3 -3
@@ -136,7 +136,7 @@ struct eccprivkeytoken {* also checked. Returns 0 on success or errno value on failure. */ int cca_check_secaeskeytoken (debug_info_t *dbg,int dbflvl, -const u8 *token,int keybitsize); +const u8 *token,u32 keysize,int keybitsize);/* * Simple check if the token is a valid CCA secure AES cipher key
@@ -146,8 +146,8 @@ int cca_check_secaeskeytoken(debug_info_* Returns 0 on success or errno value on failure. */ int cca_check_secaescipherkey (debug_info_t *dbg,int dbflvl, -const u8 *token,int keybitsize, -int checkcpacfexport); +const u8 *token,u32 keysize, +int keybitsize,int checkcpacfexport);/* * Simple check if the token is a valid CCA secure ECC private
Greg Kroah-Hartman
maintainerPATCH 276/396 s390/zcrypt: Fix missing mem scrub at clear key import in cca_clr2cipherkey()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <[email protected]>
commit 01476391aecef36a3b789ee844357b22fbc90665 upstream.
The helper function _ip_cprb_helper() uses internal buffer memory for building and processing CPRBs. After use this buffer was never scrubbed which could lead to leaving for example clear key material in memory which could be exposed via tricky reuse of this same memory.
Extend the _ip_cprb_helper() function with another parameter 'scrub' used to steer scrubbing of this buffer. So now the caller has the opportunity to decide if scrubbing is needed or not.
Extend the clear key to secure key token import process in function cca_clr2cipherkey() to tell the helper function from above to scrub the cprb buffer when the clear key value is part of the request data.
Add explicit scrubbing on return from function cca_clr2cipherkey() for the random EXOR buffer and the cprb buffer.
Overall this cleans the internal used buffer in case of clear key import to prevent sensitive data to get exposed.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/s390/crypto/zcrypt_ccamisc.c +13 -6
@@ -1016,7 +1016,8 @@ static int _ip_cprb_helper(u16 cardnr, uint clr_key_bit_size, u8 *key_token, int *key_token_size, - u32 xflags) + u32 xflags, + bool scrub) { int rc, n;u8 *mem, *ptr;
@@ -1156,7 +1157,7 @@ static int _ip_cprb_helper(u16 cardnr, u *key_token_size = t->len; out: -free_cprbmem (mem,PARMBSIZE , false, xflags); +free_cprbmem (mem,PARMBSIZE , scrub, xflags);return rc; }
@@ -1207,28 +1208,32 @@ int cca_clr2cipherkey(u16 card, u16 dom,* 4/4 COMPLETE the secure cipher key import */ rc =_ip_cprb_helper (card, dom,"AES " ,"FIRST " ,"MIN3PART" , - exorbuf, keybitsize, token, &tokensize, xflags); + exorbuf, keybitsize, token, &tokensize, + xflags, true);if (rc) {ZCRYPT_DBF_ERR ("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n" , __func__, rc); goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"ADD-PART" ,NULL , - clrkey, keybitsize, token, &tokensize, xflags); + clrkey, keybitsize, token, &tokensize, + xflags, true);if (rc) {ZCRYPT_DBF_ERR ("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n" , __func__, rc); goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"ADD-PART" ,NULL , - exorbuf, keybitsize, token, &tokensize, xflags); + exorbuf, keybitsize, token, &tokensize, + xflags, true);if (rc) {ZCRYPT_DBF_ERR ("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n" , __func__, rc); goto out; } rc =_ip_cprb_helper (card, dom,"AES " ,"COMPLETE" ,NULL , -NULL , keybitsize, token, &tokensize, xflags); +NULL , keybitsize, token, &tokensize, + xflags, true);if (rc) {ZCRYPT_DBF_ERR ("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n" , __func__, rc);
@@ -1245,6 +1250,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, *keybufsize = tokensize; out: +memzero_explicit (exorbuf,sizeof (exorbuf)); +memzero_explicit (mem,CPRB_MEMPOOL_ITEM_SIZE );mempool_free (mem, cprb_mempool);return rc; }
Greg Kroah-Hartman
maintainerPATCH 277/396 s390/zcrypt: Validate length for CCA AES cipher key requests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
commit 06afe425d5283b9764303de47f554da5a808ce8a upstream.
cca_cipher2protkey() derives the copy length for the CPRB parameter block directly from the length field in the key token. Reject the request early if the token length exceeds the available space in the parameter block.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/crypto/zcrypt_ccamisc.c +3 -0
@@ -1313,6 +1313,9 @@ int cca_cipher2protkey(u16 cardnr, u16 d }__packed * prepparm;int keytoklen = ((struct cipherkeytoken *)ckey)->len; +if (keytoklen >PARMBSIZE -sizeof (struct aureqparm )) +return -EINVAL ; +/* get already prepared memory for 2 cprbs with param block each */ rc =alloc_and_prep_cprbmem (PARMBSIZE , &mem, &preqcblk, &prepcblk, xflags);
Greg Kroah-Hartman
maintainerPATCH 278/396 s390/zcrypt: Validate length for CCA ECC private key requests
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Holger Dengler <[email protected]>
commit a9ae0f6dd45c3ccc1d69363f7aea8af179122730 upstream.
cca_ecc2protkey() derives the copy length for the CPRB parameter block directly from the length field in the key token. Reject the request early if the token length exceeds the available space in the parameter block.
--- drivers/s390/crypto/zcrypt_ccamisc.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/crypto/zcrypt_ccamisc.c +3 -0
@@ -1480,6 +1480,9 @@ int cca_ecc2protkey(u16 cardnr, u16 doma }__packed * prepparm;int keylen = ((struct eccprivkeytoken *)key)->len; +if (keylen >PARMBSIZE -sizeof (struct aureqparm )) +return -EINVAL ; +/* get already prepared memory for 2 cprbs with param block each */ rc =alloc_and_prep_cprbmem (PARMBSIZE , &mem, &preqcblk, &prepcblk, xflags);