6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 385/1887 usb: ohci-spear: Remove unnecessary NULL check before clk_disable_unprepare()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ni <[email protected]>
[ Upstream commit a891b9aebcc7406fe2f439d184bac3948fb08645 ]
clk_disable_unprepare() already checks NULL by using IS_ERR_OR_NULL. Remove unneeded NULL check for clk here.
Stable-dep-of: b1b0f8bdbbc8 ("usb: ohci-spear: disable controller wakeup on removal")
--- drivers/usb/host/ohci-spear.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/host/ohci-spear.c +1 -2
@@ -104,8 +104,7 @@ static int spear_ohci_hcd_drv_remove(struct platform_device *pdev)struct spear_ohci *sohci_p =to_spear_ohci (hcd);usb_remove_hcd (hcd); -if (sohci_p->clk) -clk_disable_unprepare (sohci_p->clk); +clk_disable_unprepare (sohci_p->clk);usb_put_hcd (hcd);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 386/1887 usb: ohci-spear: disable controller wakeup on removal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit b1b0f8bdbbc891a4ee7f3b1a878c633e02b7bbeb ]
Probe enables controller wakeup after the OHCI core marks controllers with RemoteWakeupConnected as wakeup-capable. Removal does not undo this, so the wakeup source can remain attached after driver unbind.
Disable controller wakeup after removing the HCD.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/host/ohci-spear.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/ohci-spear.c +1 -0
@@ -104,6 +104,7 @@ static int spear_ohci_hcd_drv_remove(struct platform_device *pdev)struct spear_ohci *sohci_p =to_spear_ohci (hcd);usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller);clk_disable_unprepare (sohci_p->clk);usb_put_hcd (hcd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 387/1887 USB: dwc2: shut down wakeup timer before freeing HCD state
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit fd772af9512cdecb83de34a461801533828e77fd ]
dwc2_wakeup_detected() accesses the DWC2 host state and can rearm the wakeup timer. dwc2_hcd_free() currently deletes the timer only after freeing host-owned state, and timer_delete() does not synchronize a callback or prevent it from being queued again.
Stop and shut down the timer in dwc2_hcd_release(), before the HCD resources are freed. This covers both the HCD initialization error path and normal HCD removal.
--- drivers/usb/dwc2/hcd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/dwc2/hcd.c +1 -2
@@ -5082,14 +5082,13 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) }cancel_work_sync (&hsotg->phy_reset_work); - -del_timer (&hsotg->wkp_timer); }static void dwc2_hcd_release (struct dwc2_hsotg *hsotg) {/* Turn off all host-specific interrupts */ dwc2_disable_host_interrupts (hsotg); +timer_shutdown_sync (&hsotg->wkp_timer);dwc2_hcd_free (hsotg); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 388/1887 usb: typec: ucsi: acpi: Assume UCSI 1.2 on Acer Nitro ANV15-41
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pannarat Wiriyaarritham <[email protected]>
[ Upstream commit 8c51ea651d043c786c37668c51624bd6b338a0ef ]
The Acer Nitro ANV15-41 exposes a functional UCSI ACPI PPM but reports a UCSI VERSION value of zero.
ucsi_register() rejects a zero version with -ENODEV, leaving the system without registered USB Type-C connectors.
The PPM works correctly when using the UCSI 1.2 layout. With UCSI 1.2 assumed, both Type-C connectors register correctly and USB Power Delivery negotiation works.
Add a DMI-specific UCSI operation for the Acer Nitro ANV15-41 that substitutes UCSI 1.2 only when firmware reports a zero version. Preserve any valid non-zero firmware version.
Tested on an Acer Nitro ANV15-41 with BIOS V1.51.
--- drivers/usb/typec/ucsi/ucsi_acpi.c | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
drivers/usb/typec/ucsi/ucsi_acpi.c +32 -0
@@ -106,6 +106,31 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_write = ucsi_acpi_async_write }; +static int ucsi_acer_read (struct ucsi *ucsi,unsigned int offset, +void *val,size_t val_len) +{ +struct ucsi_acpi *ua =ucsi_get_drvdata (ucsi); +u16 *version = val; +int ret; + + ret =ucsi_acpi_read (ucsi, offset, val, val_len); +if (ret) +return ret; + +if (offset ==UCSI_VERSION && val_len ==sizeof (*version) && !*version) { +dev_warn (ua->dev,"UCSI version is zero, assuming 1.2\n" ); + *version =0x0120 ; + } + +return 0 ; +} + +static const struct ucsi_operations ucsi_acer_ops = { + .read = ucsi_acer_read, + .sync_write = ucsi_acpi_sync_write, + .async_write = ucsi_acpi_async_write +}; +static int ucsi_zenbook_read (struct ucsi *ucsi,unsigned int offset,void *val,size_t val_len) {
@@ -173,6 +198,13 @@ static const struct ucsi_operations ucsi_dell_ops = { };static const struct dmi_system_id ucsi_acpi_quirks[] = { + { + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Acer" ), +DMI_MATCH (DMI_PRODUCT_NAME ,"Nitro ANV15-41" ), + }, + .driver_data = (void *)&ucsi_acer_ops, + }, { .matches = {DMI_MATCH (DMI_SYS_VENDOR ,"ASUSTeK COMPUTER INC." ),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 389/1887 tty: tty_port: restore TTY_IO_ERROR on activation failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 56964f6a31238fb41d5830bb42520c5b10ff7d8f ]
Make sure to restore the TTY_IO_ERROR flag if activation fails to prevent I/O attempts on a port that is gone or powered down.
This specifically avoids issues like kernel panic due to unclocked accesses or NULL-pointer dereferences when accessing powered down or deregistered ports when a TTY ioctl races with hangup and open.
Note that the flag is set again in tty_port_close() but not restoring it on activation failure leaves a window where drivers fail to handle the ioctl-hangup race.
--- drivers/tty/tty_port.c | 1 + 1 file changed, 1 insertion(+)
drivers/tty/tty_port.c +1 -0
@@ -783,6 +783,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,int retval = port->ops->activate (port, tty);if (retval) { +set_bit (TTY_IO_ERROR , &tty->flags);mutex_unlock (&port->mutex);return retval; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 390/1887 tty: serial: max3100: shut down timer before freeing port
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit db0949bbd06db0a75b4b1076f1e25194be7d956a ]
max3100_shutdown() stops the polling timer but returns early during system suspend. If the SPI device is unbound before resume, the serial core does not call max3100_shutdown() again, so max3100_remove() frees the port while the timer remains armed. max3100_timeout() may then access the freed port and re-arm the timer.
Add final timer teardown to max3100_remove() and use timer_shutdown_sync() to prevent a racing callback from re-arming it. Also free the IRQ and destroy the workqueue there before freeing the port. Keep timer_delete_sync() in max3100_shutdown() so that a subsequent open() can re-arm the timer.
The workqueue is created before request_irq() and destroyed on both request_irq() failure and normal shutdown. Its presence at remove thus identifies the IRQ left registered when suspend bypasses shutdown.
Free the IRQ before destroying the workqueue, in both max3100_shutdown() and max3100_remove(), and cancel the pending work in between. free_irq() waits for a running interrupt handler to finish and no new handler can start afterwards, so a racing handler cannot queue work on a workqueue that is being destroyed; the force_end_work check in max3100_dowork() only narrows that window, as a handler delayed between the check and queue_work() could still run after the teardown has cleared the workqueue pointer. Cancelling the work also keeps destroy_workqueue() from waiting on a queued work item in case remove() ever runs while the freezable workqueue is still frozen, e.g. device removal during the resume window, before workqueues are thawed.
This issue was found by an in-house static analysis tool.
--- drivers/tty/serial/max3100.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/tty/serial/max3100.c +11 -2
@@ -568,11 +568,11 @@ static void max3100_shutdown(struct uart_port *port)del_timer_sync (&s->timer);if (s->workqueue) { +free_irq (s->irq, s); +cancel_work_sync (&s->work);destroy_workqueue (s->workqueue); s->workqueue =NULL ; } -if (s->irq) -free_irq (s->irq, s);/* set shutdown mode to save power */ if (s->max3100_hw_suspend)
@@ -831,6 +831,15 @@ static void max3100_remove(struct spi_device *spi)if (max3100s[i] == s) {dev_dbg (&spi->dev,"%s: removing port %d\n" , __func__, i);uart_remove_one_port (&max3100_uart_driver, &max3100s[i]->port); + + s->force_end_work =1 ; +timer_shutdown_sync (&s->timer); +if (s->workqueue) { +free_irq (s->irq, s); +cancel_work_sync (&s->work); +destroy_workqueue (s->workqueue); + s->workqueue =NULL ; + }kfree (max3100s[i]); max3100s[i] =NULL ;break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 391/1887 serial: fix TIOCMIWAIT race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 40adffec8c0090533dfaa863ced7901b60bbf1dc ]
The task state must be updated before checking the wakeup condition to avoid missing a racing modem status update.
--- drivers/tty/serial/serial_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/tty/serial/serial_core.c +2 -2
@@ -1222,12 +1222,12 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg)add_wait_queue (&port->delta_msr_wait, &wait);for (;;) { +set_current_state (TASK_INTERRUPTIBLE ); +spin_lock_irq (&uport->lock);memcpy (&cnow, &uport->icount,sizeof (struct uart_icount ));spin_unlock_irq (&uport->lock); -set_current_state (TASK_INTERRUPTIBLE ); - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 392/1887 drm/amd/display: Mark DCE 6.4 as not APU
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 3a52d587d1fc8e8bf94ba1b07374f7ec91aaffb4 ]
DCE 6.4 is found in Oland chips, which were advertised as low-end gaming GPUs in 2013~2015 and then have been sold as low-end workstation GPUs until 2017~2019.
These are not APUs.
--- drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c +0 -1
@@ -1355,7 +1355,6 @@ static bool dce64_construct( dc->caps.max_downscale_ratio =200 ; dc->caps.i2c_speed_in_khz =40 ; dc->caps.max_cursor_size =64 ; - dc->caps.is_apu = true;/************************************************* * Create resources *
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 393/1887 mtd: spinand: fix NULL pointer dereference with no ECC engine
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuno Sá <[email protected]>
[ Upstream commit b890e6163761ddb580cc74f43e15f8bbde15647e ]
When "nand-no-ecc-engine" is set in DT, nanddev_get_ecc_engine() takes the NAND_ECC_ENGINE_TYPE_NONE path and returns success while leaving nand->ecc.engine NULL. The SPI-NAND code nevertheless dereferences it unconditionally to test for a pipelined engine, so probing such a device oopses immediately.
Rather than open-coding the test three times, add a nand_ecc_is_pipelined() helper to the NAND core that folds the NULL check into the integration comparison, and use it everywhere. Future callers then cannot reintroduce the problem.
--- drivers/mtd/nand/spi/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/mtd/nand/spi/core.c +2 -1
@@ -884,7 +884,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].rdesc = desc; -if (nand->ecc.engine->integration !=NAND_ECC_ENGINE_INTEGRATION_PIPELINED ) { +if (!nand->ecc.engine || + nand->ecc.engine->integration !=NAND_ECC_ENGINE_INTEGRATION_PIPELINED ) { spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 394/1887 wifi: mac80211: shut down RX BA session timer on teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit e588e83e5c7a0f6d7a77dbbb58927c8c8cfd598e ]
Tearing down an RX BA session can leave the session timer queued on a freed tid_rx. Later timer-wheel processing and the timer callback itself then run against freed memory.
An RX BAR handler can dereference tid_rx under RCU before teardown unpublishes it and stay in its read-side critical section while teardown deletes the session timer. The stale handler can then rearm the timer after timer_delete_sync() returns and before the RCU callback frees tid_rx.
Use timer_shutdown_sync() so rearm attempts become ineffective once teardown starts. Keep reorder_timer unchanged: teardown marks the session removed under reorder_lock and its release path checks that state before rearming. session_timer has no equivalent guard because ieee80211_rx_h_ctrl() rearms it before taking reorder_lock.
--- net/mac80211/agg-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mac80211/agg-rx.c +1 -1
@@ -103,7 +103,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,if (!tid_rx)return ; -del_timer_sync (&tid_rx->session_timer); +timer_shutdown_sync (&tid_rx->session_timer);/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ spin_lock_bh (&tid_rx->reorder_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 395/1887 wifi: mac80211: keep fallback association elements alive
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit a10a2f80476d166fd81c361ec0319493671b694e ]
Associating to a non-transmitted MBSSID profile reads freed memory while determining the operating channel and applying HT capabilities.
When an association response omits WMM, HT, or VHT information, ieee80211_assoc_config_link() parses the cached BSS IEs and copies the missing element pointers out of that fallback parse. For a non-transmitted MBSSID profile those pointers refer to merged-profile storage owned by the parse object, and the fallback block frees that object at its end. The copied pointers are used afterwards to determine the operating channel, configure bandwidth, and apply HT capabilities.
Keep the fallback parse result alive until association setup finishes.
--- net/mac80211/mlme.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/mac80211/mlme.c +2 -3
@@ -4023,6 +4023,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,bool is_6ghz = cbss->channel->band ==NL80211_BAND_6GHZ ;bool is_s1g = cbss->channel->band ==NL80211_BAND_S1GHZ ;const struct cfg80211_bss_ies *bss_ies =NULL ; +struct ieee802_11_elems *bss_elems =NULL ;struct ieee80211_supported_band *sband;struct ieee802_11_elems *elems;u16 capab_info;
@@ -4059,7 +4060,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT) && (!elems->vht_cap_elem || !elems->vht_operation)))) {const struct cfg80211_bss_ies *ies; -struct ieee802_11_elems *bss_elems;rcu_read_lock (); ies =rcu_dereference (cbss->ies);
@@ -4115,8 +4115,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,sdata_info (sdata,"AP bug: VHT operation missing from AssocResp\n" ); } - -kfree (bss_elems); }/*
@@ -4343,6 +4341,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, ret = true; out:kfree (elems); +kfree (bss_elems);kfree (bss_ies);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 396/1887 USB: serial: return errors from break handling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 6ff58ae17fd9523246a260434133ed9ab7f56df2 ]
Start propagating errors to user space when setting the break state fails.
This will be used by follow-on changes to also report when a driver or device does not support break control.
Stable-dep-of: ae0e61d95677 ("USB: serial: fix ioctl hangup race")
--- drivers/usb/serial/ark3116.c | 7 +++-- drivers/usb/serial/belkin_sa.c | 12 ++++++--- drivers/usb/serial/ch341.c | 37 +++++++++++++++++---------- drivers/usb/serial/cp210x.c | 8 +++--- drivers/usb/serial/digi_acceleport.c | 7 ++--- drivers/usb/serial/f81232.c | 4 ++- drivers/usb/serial/f81534.c | 4 ++- drivers/usb/serial/ftdi_sio.c | 10 +++++--- drivers/usb/serial/io_edgeport.c | 6 +++-- drivers/usb/serial/io_ti.c | 9 +++++-- drivers/usb/serial/keyspan.c | 5 +++- drivers/usb/serial/keyspan_pda.c | 8 ++++-- drivers/usb/serial/mct_u232.c | 6 ++--- drivers/usb/serial/mos7720.c | 9 ++++--- drivers/usb/serial/mos7840.c | 7 ++--- drivers/usb/serial/mxuport.c | 6 ++--- drivers/usb/serial/pl2303.c | 14 ++++++---- drivers/usb/serial/quatech2.c | 8 ++++-- drivers/usb/serial/ti_usb_3410_5052.c | 10 +++++--- drivers/usb/serial/upd78f0730.c | 7 +++-- drivers/usb/serial/usb-serial.c | 2 +- drivers/usb/serial/usb_debug.c | 13 +++++++--- drivers/usb/serial/whiteheat.c | 7 ++--- drivers/usb/serial/xr_serial.c | 4 +-- include/linux/usb/serial.h | 2 +- 25 files changed, 140 insertions(+), 72 deletions(-)
drivers/usb/serial/ark3116.c +5 -2
@@ -433,10 +433,11 @@ static int ark3116_tiocmset(struct tty_struct *tty,return 0 ; } -static void ark3116_break_ctl (struct tty_struct *tty,int break_state) +static int ark3116_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct ark3116_private *priv =usb_get_serial_port_data (port); +int ret;/* LCR is also used for other things: protect access */ mutex_lock (&priv->hw_lock);
@@ -446,9 +447,11 @@ static void ark3116_break_ctl(struct tty_struct *tty, int break_state)else priv->lcr &= ~UART_LCR_SBC ; -ark3116_write_reg (port->serial,UART_LCR , priv->lcr); + ret =ark3116_write_reg (port->serial,UART_LCR , priv->lcr);mutex_unlock (&priv->hw_lock); + +return ret; }static void ark3116_update_msr (struct usb_serial_port *port,__u8 msr)
drivers/usb/serial/belkin_sa.c +9 -3
@@ -46,7 +46,7 @@ static void belkin_sa_process_read_urb(struct urb *urb);static void belkin_sa_set_termios (struct tty_struct *tty,struct usb_serial_port *port,const struct ktermios *old_termios); -static void belkin_sa_break_ctl (struct tty_struct *tty,int break_state); +static int belkin_sa_break_ctl (struct tty_struct *tty,int break_state);static int belkin_sa_tiocmget (struct tty_struct *tty);static int belkin_sa_tiocmset (struct tty_struct *tty,unsigned int set,unsigned int clear);
@@ -402,13 +402,19 @@ static void belkin_sa_set_termios(struct tty_struct *tty,spin_unlock_irqrestore (&priv->lock, flags); } -static void belkin_sa_break_ctl (struct tty_struct *tty,int break_state) +static int belkin_sa_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct usb_serial *serial = port->serial; +int ret; -if (BSA_USB_CMD (BELKIN_SA_SET_BREAK_REQUEST , break_state ?1 :0 ) <0 ) + ret =BSA_USB_CMD (BELKIN_SA_SET_BREAK_REQUEST , break_state ?1 :0 ); +if (ret <0 ) {dev_err (&port->dev,"Set break_ctl %d\n" , break_state); +return ret; + } + +return 0 ; }static int belkin_sa_tiocmget (struct tty_struct *tty)
drivers/usb/serial/ch341.c +23 -14
@@ -562,12 +562,12 @@ static void ch341_set_termios(struct tty_struct *tty,* TCSBRKP. Due to how the simulation is implemented the duration can't be * controlled. The duration is always about (1s / 46bd * 9bit) = 196ms. */ -static void ch341_simulate_break (struct tty_struct *tty,int break_state) +static int ch341_simulate_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct ch341_private *priv =usb_get_serial_port_data (port);unsigned long now, delay; -int r; +int r, r2;if (break_state !=0 ) {dev_dbg (&port->dev,"enter break state requested\n" );
@@ -599,7 +599,7 @@ static void ch341_simulate_break(struct tty_struct *tty, int break_state)*/ priv->break_end = jiffies + (11 *HZ /CH341_MIN_BPS ); -return ; +return 0 ; }dev_dbg (&port->dev,"leave break state requested\n" );
@@ -615,17 +615,22 @@ static void ch341_simulate_break(struct tty_struct *tty, int break_state)schedule_timeout_interruptible (delay); } + r =0 ; restore:/* Restore original baud rate */ - r =ch341_set_baudrate_lcr (port->serial->dev, priv, priv->baud_rate, - priv->lcr); -if (r <0 ) + r2 =ch341_set_baudrate_lcr (port->serial->dev, priv, priv->baud_rate, + priv->lcr); +if (r2 <0 ) {dev_err (&port->dev,"restoring original baud rate of %u failed: %d\n" , - priv->baud_rate, r); + priv->baud_rate, r2); +return r2; + } + +return r; } -static void ch341_break_ctl (struct tty_struct *tty,int break_state) +static int ch341_break_ctl (struct tty_struct *tty,int break_state) {const uint16_t ch341_break_reg = ((uint16_t )CH341_REG_LCR <<8 ) |CH341_REG_BREAK ;
@@ -635,17 +640,17 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)uint16_t reg_contents;uint8_t break_reg[2 ]; -if (priv->quirks &CH341_QUIRK_SIMULATE_BREAK ) { -ch341_simulate_break (tty, break_state); -return ; - } +if (priv->quirks &CH341_QUIRK_SIMULATE_BREAK ) +return ch341_simulate_break (tty, break_state); r =ch341_control_in (port->serial->dev,CH341_REQ_READ_REG , ch341_break_reg,0 , break_reg,2 );if (r) {dev_err (&port->dev,"%s - USB control read error (%d)\n" , __func__, r); -return ; +if (r >0 ) + r = -EIO ; +return r; }dev_dbg (&port->dev,"%s - initial ch341 break register contents - reg1: %x, reg2: %x\n" , __func__, break_reg[0 ], break_reg[1 ]);
@@ -663,9 +668,13 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) reg_contents =get_unaligned_le16 (break_reg); r =ch341_control_out (port->serial->dev,CH341_REQ_WRITE_REG , ch341_break_reg, reg_contents); -if (r <0 ) +if (r <0 ) {dev_err (&port->dev,"%s - USB control write error (%d)\n" , __func__, r); +return r; + } + +return 0 ; } static int ch341_tiocmset(struct tty_struct *tty,
drivers/usb/serial/cp210x.c +5 -3
@@ -39,7 +39,7 @@ static int cp210x_tiocmget(struct tty_struct *);static int cp210x_tiocmset (struct tty_struct *,unsigned int ,unsigned int );static int cp210x_tiocmset_port (struct usb_serial_port *port,unsigned int ,unsigned int ); -static void cp210x_break_ctl (struct tty_struct *,int ); +static int cp210x_break_ctl (struct tty_struct *,int );static int cp210x_attach (struct usb_serial *);static void cp210x_disconnect (struct usb_serial *);static void cp210x_release (struct usb_serial *);
@@ -1430,7 +1430,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)return result; } -static void cp210x_break_ctl (struct tty_struct *tty,int break_state) +static int cp210x_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;u16 state;
@@ -1439,9 +1439,11 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state) state =BREAK_OFF ; else state =BREAK_ON ; +dev_dbg (&port->dev,"%s - turning break %s\n" , __func__, state ==BREAK_OFF ?"off" :"on" ); -cp210x_write_u16_reg (port,CP210X_SET_BREAK , state); + +return cp210x_write_u16_reg (port,CP210X_SET_BREAK , state); }#ifdef CONFIG_GPIOLIB
drivers/usb/serial/digi_acceleport.c +4 -3
@@ -217,7 +217,7 @@ static void digi_rx_unthrottle(struct tty_struct *tty);static void digi_set_termios (struct tty_struct *tty,struct usb_serial_port *port,const struct ktermios *old_termios); -static void digi_break_ctl (struct tty_struct *tty,int break_state); +static int digi_break_ctl (struct tty_struct *tty,int break_state);static int digi_tiocmget (struct tty_struct *tty);static int digi_tiocmset (struct tty_struct *tty,unsigned int set,unsigned int clear);
@@ -846,7 +846,7 @@ static void digi_set_termios(struct tty_struct *tty, } -static void digi_break_ctl (struct tty_struct *tty,int break_state) +static int digi_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;unsigned char buf[4 ];
@@ -855,7 +855,8 @@ static void digi_break_ctl(struct tty_struct *tty, int break_state) buf[1 ] =2 ;/* length */ buf[2 ] = break_state ?1 :0 ; buf[3 ] =0 ;/* pad */ -digi_write_inb_command (port, buf,4 ,0 ); + +return digi_write_inb_command (port, buf,4 ,0 ); }
drivers/usb/serial/f81232.c +3 -1
@@ -447,7 +447,7 @@ static void f81534a_process_read_urb(struct urb *urb)tty_flip_buffer_push (&port->port); } -static void f81232_break_ctl (struct tty_struct *tty,int break_state) +static int f81232_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct f81232_private *priv =usb_get_serial_port_data (port);
@@ -466,6 +466,8 @@ static void f81232_break_ctl(struct tty_struct *tty, int break_state)dev_err (&port->dev,"set break failed: %d\n" , status);mutex_unlock (&priv->lock); + +return status; }static int f81232_find_clk (speed_t baudrate)
drivers/usb/serial/f81534.c +3 -1
@@ -656,7 +656,7 @@ static int f81534_set_port_config(struct usb_serial_port *port,return status; } -static void f81534_break_ctl (struct tty_struct *tty,int break_state) +static int f81534_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct f81534_port_private *port_priv =usb_get_serial_port_data (port);
@@ -675,6 +675,8 @@ static void f81534_break_ctl(struct tty_struct *tty, int break_state)dev_err (&port->dev,"set break failed: %d\n" , status);mutex_unlock (&port_priv->lcr_mutex); + +return status; } static int f81534_update_mctrl(struct usb_serial_port *port, unsigned int set,
drivers/usb/serial/ftdi_sio.c +7 -3
@@ -2550,11 +2550,12 @@ static void ftdi_process_read_urb(struct urb *urb)tty_flip_buffer_push (&port->port); } -static void ftdi_break_ctl (struct tty_struct *tty,int break_state) +static int ftdi_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct ftdi_private *priv =usb_get_serial_port_data (port);u16 value; +int ret;/* break_state = -1 to turn on break, and 0 to turn off break */ /* see drivers/char/tty_io.c to see it used */
@@ -2565,19 +2566,22 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)else value = priv->last_set_data_value; -if (usb_control_msg (port->serial->dev, + ret =usb_control_msg (port->serial->dev,usb_sndctrlpipe (port->serial->dev,0 ),FTDI_SIO_SET_DATA_REQUEST ,FTDI_SIO_SET_DATA_REQUEST_TYPE , value, priv->channel, -NULL ,0 ,WDR_TIMEOUT ) <0 ) { +NULL ,0 ,WDR_TIMEOUT ); +if (ret <0 ) {dev_err (&port->dev,"%s FAILED to enable/disable break state (state was %d)\n" , __func__, break_state); +return ret; }dev_dbg (&port->dev,"%s break state is %d - urb is %d\n" , __func__, break_state, value); +return 0 ; }static bool ftdi_tx_empty (struct usb_serial_port *port)
drivers/usb/serial/io_edgeport.c +4 -2
@@ -1564,12 +1564,12 @@ static int edge_ioctl(struct tty_struct *tty,* SerialBreak * this function sends a break to the port *****************************************************************************/ -static void edge_break (struct tty_struct *tty,int break_state) +static int edge_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct edgeport_port *edge_port =usb_get_serial_port_data (port);struct edgeport_serial *edge_serial =usb_get_serial_data (port->serial); -int status; +int status =0 ;if (!edge_serial->is_epic || edge_serial->epic_descriptor.Supports.IOSPChase) {
@@ -1601,6 +1601,8 @@ static void edge_break(struct tty_struct *tty, int break_state)dev_dbg (&port->dev,"%s - error sending break set/clear command.\n" , __func__); } + +return status; }
drivers/usb/serial/io_ti.c +7 -2
@@ -2432,7 +2432,7 @@ static int edge_tiocmget(struct tty_struct *tty)return result; } -static void edge_break (struct tty_struct *tty,int break_state) +static int edge_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct edgeport_port *edge_port =usb_get_serial_port_data (port);
@@ -2441,10 +2441,15 @@ static void edge_break(struct tty_struct *tty, int break_state)if (break_state ==-1 ) bv =1 ;/* On */ + status =ti_do_config (edge_port,UMPC_SET_CLR_BREAK , bv); -if (status) +if (status) {dev_dbg (&port->dev,"%s - error %d sending break set/clear command.\n" , __func__, status); +return status; + } + +return 0 ; }static void edge_heartbeat_schedule (struct edgeport_serial *edge_serial)
drivers/usb/serial/keyspan.c +4 -1
@@ -599,7 +599,7 @@ struct keyspan_port_private {#include "keyspan_usa67msg.h" -static void keyspan_break_ctl (struct tty_struct *tty,int break_state) +static int keyspan_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct keyspan_port_private *p_priv;
@@ -611,7 +611,10 @@ static void keyspan_break_ctl(struct tty_struct *tty, int break_state)else p_priv->break_on =0 ; +/* FIXME: return errors */ keyspan_send_setup (port,0 ); + +return 0 ; }
drivers/usb/serial/keyspan_pda.c +6 -2
@@ -323,7 +323,7 @@ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)return baud; } -static void keyspan_pda_break_ctl (struct tty_struct *tty,int break_state) +static int keyspan_pda_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct usb_serial *serial = port->serial;
@@ -339,9 +339,13 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state)4 ,/* set break */ USB_TYPE_VENDOR |USB_RECIP_INTERFACE |USB_DIR_OUT , value, 0, NULL, 0, 2000); -if (result <0 ) +if (result <0 ) {dev_dbg (&port->dev,"%s - error %d from usb_control_msg\n" , __func__, result); +return result; + } + +return 0 ; } static void keyspan_pda_set_termios(struct tty_struct *tty,
drivers/usb/serial/mct_u232.c +3 -3
@@ -47,7 +47,7 @@ static void mct_u232_read_int_callback(struct urb *urb);static void mct_u232_set_termios (struct tty_struct *tty,struct usb_serial_port *port,const struct ktermios *old_termios); -static void mct_u232_break_ctl (struct tty_struct *tty,int break_state); +static int mct_u232_break_ctl (struct tty_struct *tty,int break_state);static int mct_u232_tiocmget (struct tty_struct *tty);static int mct_u232_tiocmset (struct tty_struct *tty,unsigned int set,unsigned int clear);
@@ -683,7 +683,7 @@ static void mct_u232_set_termios(struct tty_struct *tty,spin_unlock_irqrestore (&priv->lock, flags); }/* mct_u232_set_termios */ -static void mct_u232_break_ctl (struct tty_struct *tty,int break_state) +static int mct_u232_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct mct_u232_private *priv =usb_get_serial_port_data (port);
@@ -697,7 +697,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) lcr |=MCT_U232_SET_BREAK ;spin_unlock_irqrestore (&priv->lock, flags); -mct_u232_set_line_ctrl (port, lcr); +return mct_u232_set_line_ctrl (port, lcr); }/* mct_u232_break_ctl */
drivers/usb/serial/mos7720.c +5 -4
@@ -996,7 +996,7 @@ static void mos7720_close(struct usb_serial_port *port) mos7720_port->open =0 ; } -static void mos7720_break (struct tty_struct *tty,int break_state) +static int mos7720_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;unsigned char data;
@@ -1007,7 +1007,7 @@ static void mos7720_break(struct tty_struct *tty, int break_state) mos7720_port =usb_get_serial_port_data (port);if (mos7720_port ==NULL ) -return ; +return -ENODEV ;if (break_state ==-1 ) data = mos7720_port->shadowLCR |UART_LCR_SBC ;
@@ -1015,8 +1015,9 @@ static void mos7720_break(struct tty_struct *tty, int break_state) data = mos7720_port->shadowLCR & ~UART_LCR_SBC ; mos7720_port->shadowLCR = data; -write_mos_reg (serial, port->port_number,MOS7720_LCR , - mos7720_port->shadowLCR); + +return write_mos_reg (serial, port->port_number,MOS7720_LCR , + mos7720_port->shadowLCR); }/*
drivers/usb/serial/mos7840.c +4 -3
@@ -787,7 +787,7 @@ static void mos7840_close(struct usb_serial_port *port)* mos7840_break * this function sends a break to the port *****************************************************************************/ -static void mos7840_break (struct tty_struct *tty,int break_state) +static int mos7840_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct moschip_port *mos7840_port =usb_get_serial_port_data (port);
@@ -801,8 +801,9 @@ static void mos7840_break(struct tty_struct *tty, int break_state)/* FIXME: no locking on shadowLCR anywhere in driver */ mos7840_port->shadowLCR = data;dev_dbg (&port->dev,"%s mos7840_port->shadowLCR is %x\n" , __func__, mos7840_port->shadowLCR); -mos7840_set_uart_reg (port,LINE_CONTROL_REGISTER , - mos7840_port->shadowLCR); + +return mos7840_set_uart_reg (port,LINE_CONTROL_REGISTER , + mos7840_port->shadowLCR); }/*****************************************************************************
drivers/usb/serial/mxuport.c +3 -3
@@ -1238,7 +1238,7 @@ static void mxuport_close(struct usb_serial_port *port) }/* Send a break to the port. */ -static void mxuport_break_ctl (struct tty_struct *tty,int break_state) +static int mxuport_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct usb_serial *serial = port->serial;
@@ -1252,8 +1252,8 @@ static void mxuport_break_ctl(struct tty_struct *tty, int break_state)dev_dbg (&port->dev,"%s - clearing break\n" , __func__); } -mxuport_send_ctrl_urb (serial,RQ_VENDOR_SET_BREAK , - enable, port->port_number); +return mxuport_send_ctrl_urb (serial,RQ_VENDOR_SET_BREAK , + enable, port->port_number); }static int mxuport_resume (struct usb_serial *serial)
drivers/usb/serial/pl2303.c +9 -5
@@ -174,7 +174,7 @@ MODULE_DEVICE_TABLE(usb, id_table);#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c -static void pl2303_set_break (struct usb_serial_port *port,bool enable); +static int pl2303_set_break (struct usb_serial_port *port,bool enable);enum pl2303_type {TYPE_H ,
@@ -1063,7 +1063,7 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)return 0 ; } -static void pl2303_set_break (struct usb_serial_port *port,bool enable) +static int pl2303_set_break (struct usb_serial_port *port,bool enable) {struct usb_serial *serial = port->serial;u16 state;
@@ -1080,15 +1080,19 @@ static void pl2303_set_break(struct usb_serial_port *port, bool enable) result =usb_control_msg (serial->dev,usb_sndctrlpipe (serial->dev,0 ),BREAK_REQUEST ,BREAK_REQUEST_TYPE , state,0 ,NULL ,0 ,100 ); -if (result) +if (result) {dev_err (&port->dev,"error sending break = %d\n" , result); +return result; + } + +return 0 ; } -static void pl2303_break_ctl (struct tty_struct *tty,int state) +static int pl2303_break_ctl (struct tty_struct *tty,int state) {struct usb_serial_port *port = tty->driver_data; -pl2303_set_break (port, state); +return pl2303_set_break (port, state); } static void pl2303_update_line_status(struct usb_serial_port *port,
drivers/usb/serial/quatech2.c +6 -2
@@ -762,7 +762,7 @@ static int qt2_tiocmset(struct tty_struct *tty,return update_mctrl (port_priv, set, clear); } -static void qt2_break_ctl (struct tty_struct *tty,int break_state) +static int qt2_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct qt2_port_private *port_priv;
@@ -775,10 +775,14 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state) status =qt2_control_msg (port->serial->dev,QT2_BREAK_CONTROL , val, port_priv->device_port); -if (status <0 ) +if (status <0 ) {dev_warn (&port->dev,"%s - failed to send control message: %i\n" , __func__, status); +return status; + } + +return 0 ; }
drivers/usb/serial/ti_usb_3410_5052.c +7 -3
@@ -319,7 +319,7 @@ static void ti_set_termios(struct tty_struct *tty,static int ti_tiocmget (struct tty_struct *tty);static int ti_tiocmset (struct tty_struct *tty,unsigned int set,unsigned int clear); -static void ti_break (struct tty_struct *tty,int break_state); +static int ti_break (struct tty_struct *tty,int break_state);static void ti_interrupt_callback (struct urb *urb);static void ti_bulk_in_callback (struct urb *urb);static void ti_bulk_out_callback (struct urb *urb);
@@ -1071,7 +1071,7 @@ static int ti_tiocmset(struct tty_struct *tty, } -static void ti_break (struct tty_struct *tty,int break_state) +static int ti_break (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct ti_port *tport =usb_get_serial_port_data (port);
@@ -1083,8 +1083,12 @@ static void ti_break(struct tty_struct *tty, int break_state) tport->tp_uart_base_addr +TI_UART_OFFSET_LCR , TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); -if (status) +if (status) {dev_dbg (&port->dev,"%s - error setting break, %d\n" , __func__, status); +return status; + } + +return 0 ; }static int ti_get_port_from_code (unsigned char code)
drivers/usb/serial/upd78f0730.c +5 -2
@@ -238,12 +238,13 @@ static int upd78f0730_tiocmset(struct tty_struct *tty,return res; } -static void upd78f0730_break_ctl (struct tty_struct *tty,int break_state) +static int upd78f0730_break_ctl (struct tty_struct *tty,int break_state) {struct upd78f0730_port_private *private;struct usb_serial_port *port = tty->driver_data;struct upd78f0730_set_dtr_rts request;struct device *dev = &port->dev; +int res; private =usb_get_serial_port_data (port);
@@ -258,8 +259,10 @@ static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) request.opcode =UPD78F0730_CMD_SET_DTR_RTS ; request.params = private->line_signals; -upd78f0730_send_ctl (port, &request,sizeof (request)); + res =upd78f0730_send_ctl (port, &request,sizeof (request));mutex_unlock (&private->lock); + +return res; }static void upd78f0730_dtr_rts (struct usb_serial_port *port,int on)
drivers/usb/serial/usb-serial.c +1 -1
@@ -538,7 +538,7 @@ static int serial_break(struct tty_struct *tty, int break_state)dev_dbg (&port->dev,"%s\n" , __func__);if (port->serial->type->break_ctl) - port->serial->type->break_ctl (tty, break_state); +return port->serial->type->break_ctl (tty, break_state);return 0 ; }
drivers/usb/serial/usb_debug.c +10 -3
@@ -47,12 +47,19 @@ MODULE_DEVICE_TABLE(usb, id_table_combined);/* This HW really does not support a serial break, so one will be * emulated when ever the break state is set to true. */ -static void usb_debug_break_ctl (struct tty_struct *tty,int break_state) +static int usb_debug_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data; +int ret; +if (!break_state) -return ; -usb_serial_generic_write (tty, port,USB_DEBUG_BRK ,USB_DEBUG_BRK_SIZE ); +return 0 ; + + ret =usb_serial_generic_write (tty, port,USB_DEBUG_BRK ,USB_DEBUG_BRK_SIZE ); +if (ret <0 ) +return ret; + +return 0 ; }static void usb_debug_process_read_urb (struct urb *urb)
drivers/usb/serial/whiteheat.c +4 -3
@@ -87,7 +87,7 @@ static void whiteheat_set_termios(struct tty_struct *tty,static int whiteheat_tiocmget (struct tty_struct *tty);static int whiteheat_tiocmset (struct tty_struct *tty,unsigned int set,unsigned int clear); -static void whiteheat_break_ctl (struct tty_struct *tty,int break_state); +static int whiteheat_break_ctl (struct tty_struct *tty,int break_state);static struct usb_serial_driver whiteheat_fake_device = { .driver = {
@@ -449,10 +449,11 @@ static void whiteheat_set_termios(struct tty_struct *tty,firm_setup_port (tty); } -static void whiteheat_break_ctl (struct tty_struct *tty,int break_state) +static int whiteheat_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data; -firm_set_break (port, break_state); + +return firm_set_break (port, break_state); }
drivers/usb/serial/xr_serial.c +2 -2
@@ -503,7 +503,7 @@ static void xr_dtr_rts(struct usb_serial_port *port, int on)xr_tiocmset_port (port,0 ,TIOCM_DTR |TIOCM_RTS ); } -static void xr_break_ctl (struct tty_struct *tty,int break_state) +static int xr_break_ctl (struct tty_struct *tty,int break_state) {struct usb_serial_port *port = tty->driver_data;struct xr_data *data =usb_get_serial_port_data (port);
@@ -517,7 +517,7 @@ static void xr_break_ctl(struct tty_struct *tty, int break_state)dev_dbg (&port->dev,"Turning break %s\n" , state ==0 ?"off" :"on" ); -xr_set_reg_uart (port, type->tx_break, state); +return xr_set_reg_uart (port, type->tx_break, state); }/* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */
include/linux/usb/serial.h +1 -1
@@ -278,7 +278,7 @@ struct usb_serial_driver {int (*set_serial)(struct tty_struct *tty,struct serial_struct *ss);void (*set_termios)(struct tty_struct *tty,struct usb_serial_port *port,const struct ktermios *old); -void (*break_ctl)(struct tty_struct *tty,int break_state); +int (*break_ctl)(struct tty_struct *tty,int break_state);unsigned int (*chars_in_buffer)(struct tty_struct *tty);void (*wait_until_sent)(struct tty_struct *tty,long timeout);bool (*tx_empty)(struct usb_serial_port *port);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 397/1887 USB: serial: report unsupported break signalling
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit c9d934053d9e850bc901b6425eacb5fe3d4b1738 ]
Instead of returning success when a driver does not support break signalling, return an error to let user space know and to avoid waiting when break is not supported.
Stable-dep-of: ae0e61d95677 ("USB: serial: fix ioctl hangup race")
--- drivers/usb/serial/usb-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/serial/usb-serial.c +1 -1
@@ -540,7 +540,7 @@ static int serial_break(struct tty_struct *tty, int break_state)if (port->serial->type->break_ctl)return port->serial->type->break_ctl (tty, break_state); -return 0 ; +return -ENOTTY ; }static int serial_proc_show (struct seq_file *m,void *v)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 398/1887 USB: serial: fix ioctl hangup race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit ae0e61d95677efa778379853e495d748e6efbf95 ]
The tty ioctls can race with hangup and end up calling into a tty driver for a device that is already gone or powered down.
Serialise the callbacks using the tty port mutex and add the missing checks to make sure the port has not been hung up before accessing port driver data or hardware.
This specifically avoids dereferencing a NULL-pointer if a device is disconnected during lengthy break signalling.
Note that TIOCGICOUNT and TIOCMIWAIT do not access port driver data or hardware and are therefore not affected by the race.
--- drivers/usb/serial/generic.c | 10 +++- drivers/usb/serial/usb-serial.c | 94 ++++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 21 deletions(-)
drivers/usb/serial/generic.c +9 -1
@@ -268,6 +268,7 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);void usb_serial_generic_wait_until_sent (struct tty_struct *tty,long timeout) {struct usb_serial_port *port = tty->driver_data; +struct tty_port *tport = &port->port;unsigned int bps;unsigned long period;unsigned long expire;
@@ -287,7 +288,14 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) __func__,jiffies_to_msecs (timeout), jiffies_to_msecs(period)); expire = jiffies + timeout; -while (!port->serial->type->tx_empty (port)) { +for (;;) { +mutex_lock (&tport->mutex); +if (tty_io_error (tty) || port->serial->type->tx_empty (port)) { +mutex_unlock (&tport->mutex); +break ; + } +mutex_unlock (&tport->mutex); +schedule_timeout_interruptible (period);if (signal_pending (current))break ;
drivers/usb/serial/usb-serial.c +74 -20
178 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 399/1887 mtd: block2mtd: Fix divide error when erase_size is zero
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pei Xiao <[email protected]>
[ Upstream commit b5965c4221165045e19736794ca5f48ae3d67142 ]
The erase size is parsed from the "block2mtd" module parameter and can be set to zero. add_device() then evaluates
if (size % erase_size)
with a zero divisor, which triggers a divide error:
divide error: 0000 [#1] PREEMPT SMP PTI
RIP: 0010:add_device drivers/mtd/devices/block2mtd.c:296 [inline] RIP: 0010:block2mtd_setup2+0x592/0xda0 drivers/mtd/devices/block2mtd.c:459 Call Trace: block2mtd_setup+0x27/0xe0 drivers/mtd/devices/block2mtd.c:476 param_attr_store+0x214/0x310 kernel/params.c:589 module_attr_store+0x65/0x90 kernel/params.c:904 kernfs_fop_write_iter+0x3a4/0x540 fs/kernfs/file.c:345
...
Reject a zero erase size before performing the modulo operation so the existing "erasesize must be a divisor of device size" error path reports the invalid argument and frees the device.
--- drivers/mtd/devices/block2mtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/devices/block2mtd.c +1 -1
@@ -272,7 +272,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, goto err_free_block2mtd; } -if ((long )dev->blkdev->bd_inode->i_size % erase_size) { +if (!erase_size || (long )dev->blkdev->bd_inode->i_size % erase_size) {pr_err ("erasesize must be a divisor of device size\n" ); goto err_free_block2mtd; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 400/1887 mtd: spinand: Enable QE on all dies
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Han Xu <[email protected]>
[ Upstream commit 63d6cace2c4a7f36c1cb44f1bb5e0f3ef19e5c7f ]
The QUAD ENABLE (QE) bit is stored in a per-die configuration register on some SPI-NAND devices. When a device contains multiple dies, updating the QE bit only on the currently selected die can leave the remaining dies operating in non-quad mode.
Iterate over all targets and update the QE setting on each die during initialization to ensure consistent quad I/O operation across the entire device.
Tested on ISSI IS38SMW04G8B.
--- drivers/mtd/nand/spi/core.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
drivers/mtd/nand/spi/core.c +19 -2
@@ -179,7 +179,10 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)static int spinand_init_quad_enable (struct spinand_device *spinand) { +struct nand_device *nand =spinand_to_nand (spinand); +unsigned int target;bool enable = false; +int ret;if (!(spinand->flags &SPINAND_HAS_QE_BIT ))return 0 ;
@@ -189,8 +192,22 @@ static int spinand_init_quad_enable(struct spinand_device *spinand) spinand->op_templates.update_cache->data.buswidth == 4) enable = true; -return spinand_upd_cfg (spinand,CFG_QUAD_ENABLE , - enable ?CFG_QUAD_ENABLE :0 ); +/* +* QE is a per-die setting on some devices. Program each target +* individually when enabling or disabling quad I/O mode. +*/ +for (target =0 ; target < nand->memorg.ntargets; target++) { + ret =spinand_select_target (spinand, target); +if (ret) +return ret; + + ret =spinand_upd_cfg (spinand,CFG_QUAD_ENABLE , + enable ?CFG_QUAD_ENABLE :0 ); +if (ret) +return ret; + } + +return 0 ; } static int spinand_ecc_enable(struct spinand_device *spinand,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 401/1887 wifi: mac80211: account proxy paths against the mesh path limit
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit a5f35d4b112af1415ff06bd501c8cc26cc08aa8b ]
Proxy-path churn can drive the interface path counter negative and let later mesh path additions exceed MESH_MAX_MPATHS.
mesh_path_free_rcu() decrements the interface mpaths counter for entries from both the mesh and proxy path tables, but mpp_path_add() never reserves a slot in that counter. Removing or expiring a proxy path therefore returns a slot that was never charged.
mesh_path_add() uses the same counter to enforce MESH_MAX_MPATHS, so once it falls below the number of installed paths the limit no longer holds.
Reserve the shared quota before allocating a proxy path and release it on every unsuccessful addition. Mesh and proxy paths now share one 1024-entry budget, so mpp_path_add() can return -ENOSPC at that limit.
--- net/mac80211/mesh_pathtbl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
net/mac80211/mesh_pathtbl.c +9 -2
@@ -449,10 +449,15 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,if (is_multicast_ether_addr (dst))return -ENOTSUPP ; +if (!atomic_add_unless (&sdata->u.mesh.mpaths,1 ,MESH_MAX_MPATHS )) +return -ENOSPC ; + new_mpath =mesh_path_new (sdata, dst,GFP_ATOMIC ); -if (!new_mpath) +if (!new_mpath) { +atomic_dec (&sdata->u.mesh.mpaths);return -ENOMEM ; + }memcpy (new_mpath->mpp, mpp,ETH_ALEN ); tbl = &sdata->u.mesh.mpp_paths;
@@ -465,8 +470,10 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,hlist_add_head_rcu (&new_mpath->walk_list, &tbl->walk_head);spin_unlock_bh (&tbl->walk_lock); -if (ret) +if (ret) {kfree (new_mpath); +atomic_dec (&sdata->u.mesh.mpaths); + } sdata->u.mesh.mpp_paths_generation++;return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 402/1887 bnxt_en: fix DMA mapping length for padded small packets
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a51d233ccd4889aadb71dace863525cc2b00271e ]
Stefan Fleischmann reported Intel IOMMU DMA Read faults on BCM57412 NetXtreme-E NICs when transmitting packets on VLAN/macvlan interfaces:
DMAR: [DMA Read NO_PASID] Request device [18:00.0] fault addr 0xfc499000
[fault reason 0x06] PTE Read access is not set
bnxt_en 0000:18:00.0 eno1np0: Abandoning msg {0xb4 0x41a} len: 0 due to firmware status: 0x2000001
...
NETDEV WATCHDOG: eno1np0 (bnxt_en): transmit queue 0 timed out
The fault address (0xfc499000) is on an exact 4KB page boundary, pointing to a DMA read buffer overrun.
In bnxt_start_xmit(), packets smaller than BNXT_MIN_PKT_SIZE (52 bytes), such as 42-byte untagged ARP frames, are padded:
if (length < BNXT_MIN_PKT_SIZE) {
pad = BNXT_MIN_PKT_SIZE - length;
if (skb_pad(skb, pad))
goto tx_kick_pending;
length = BNXT_MIN_PKT_SIZE;
}
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
...
dma_unmap_len_set(tx_buf, len, len);However, 'len' was initialized earlier to skb_headlen(skb) (e.g. 42 bytes) and is left unadjusted after padding. Consequently, dma_map_single() and dma_unmap_len_set() map and track only 42 bytes.
Later, the hardware TX buffer descriptor is programmed with the padded length:
txbd->tx_bd_len_flags_type =
cpu_to_le32(((len + pad) << TX_BD_LEN_SHIFT) | flags |
TX_BD_FLAGS_PACKET_END);The NIC DMA engine is thus instructed to read 52 bytes from a region where only 42 bytes were DMA-mapped. If skb->data ends near the boundary of a 4KB page (within 'pad' bytes of the next page), the hardware DMA read overruns into the unmapped adjacent page, triggering an IOMMU fault.
This issue was exposed after commit 447cbe95ebb9 ("vlan: fix skb_under_panic and races when toggling HW VLAN offload") because reserving extra VLAN headroom rounded LL_RESERVED_SPACE from 48 up to 64 bytes, shifting skb->data offsets and potentially causing small frames to land right against page boundaries.
Fix this by using skb_put_padto(skb, BNXT_MIN_PKT_SIZE) in bnxt_start_xmit(), before skb_shinfo(skb)->nr_frags is sampled, because padding might linearize the skb.
This ensures skb->len and skb_headlen(skb) reflect the padded size so that dma_map_single() maps the full buffer and the descriptor length is consistent. This also removes the temporary 'pad' variable and masking logic.
The padding is done after the SW USO branch, otherwise bnxt_sw_udp_gso_xmit() would account the padding as UDP payload and send it in extra segments.
Note that SW USO segments are still not padded: with IPv4, a segment carrying less than 10 bytes of UDP payload (small gso_size, or a short last segment) is sent as a frame shorter than BNXT_MIN_PKT_SIZE. This is a separate issue, left for a followup patch.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +10 -13
@@ -392,7 +392,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)struct netdev_queue *txq;int i;dma_addr_t mapping; -unsigned int length, pad =0 ; +unsigned int length;u32 len, free_size, vlan_tag_flags, cfa_action, flags;u16 prod, last_frag;struct pci_dev *pdev = bp->pdev;
@@ -411,6 +411,14 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txr = &bp->tx_ring[bp->tx_ring_map[i]]; prod = txr->tx_prod; +/* Must be done before skb_shinfo(skb)->nr_frags is sampled, +* because skb_put_padto() might linearize the skb. +*/ +if (skb_put_padto (skb,BNXT_MIN_PKT_SIZE )) { +/* SKB already freed. */ + goto tx_kick_pending; + } + free_size =bnxt_tx_avail (bp, txr);if (unlikely (free_size <skb_shinfo (skb)->nr_frags +2 )) {/* We must have raced with NAPI cleanup */
@@ -539,14 +547,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) } normal_tx: -if (length <BNXT_MIN_PKT_SIZE ) { - pad =BNXT_MIN_PKT_SIZE - length; -if (skb_pad (skb, pad)) -/* SKB already freed. */ - goto tx_kick_pending; - length =BNXT_MIN_PKT_SIZE ; - } - mapping =dma_map_single (&pdev->dev, skb->data, len,DMA_TO_DEVICE );if (unlikely (dma_mapping_error (&pdev->dev, mapping)))
@@ -618,10 +618,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_len_flags_type =cpu_to_le32 (flags); } - flags &= ~TX_BD_LEN ; - txbd->tx_bd_len_flags_type = -cpu_to_le32 (((len + pad) <<TX_BD_LEN_SHIFT ) | flags | -TX_BD_FLAGS_PACKET_END ); + txbd->tx_bd_len_flags_type |=cpu_to_le32 (TX_BD_FLAGS_PACKET_END );netdev_tx_sent_queue (txq, skb->len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 403/1887 tty: port: fix tty_port_tty_vhangup() race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit b48820de8c1a596c5b99775524dfce73c6576c5d ]
Drivers rely on tty_port_tty_vhangup() to synchronously hang up their ports before tearing down resources as part of deregistration (e.g. on physical disconnect).
If tty_port_tty_vhangup() races with another hangup it may however return before the port has been shut down. This is in turn can lead to use-after-free and NULL-pointer dereferences in racing ioctls (including a synchronous hangup) and in processing of racing asynchronous hangups (carrier loss).
Add the missing serialisation to tty_port_tty_vhangup() and tty_port_hangup() so that the former does not return until the port has been shut down also when there is a racing hangup.
Note that serial core does not use tty_port_hangup(), but it already holds the port mutex when clearing port->tty and shutting down the port in uart_hangup().
[ Ting-Han: use mutex_lock()/spin_lock_irqsave() instead of guard(),
scoped_guard() and the tty_port_tty class, matching the existing code in this version of tty_port.c ]
--- drivers/tty/tty_port.c | 74 +++++++++++++++++++++++++++------------- include/linux/tty_port.h | 22 ++---------- 2 files changed, 53 insertions(+), 43 deletions(-)
drivers/tty/tty_port.c +51 -23
@@ -350,21 +350,12 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) }EXPORT_SYMBOL (tty_port_tty_set); -/** -* tty_port_shutdown - internal helper to shutdown the device -* @port: tty port to be shut down -* @tty: the associated tty -* -* It is used by tty_port_hangup() and tty_port_close(). Its task is to -* shutdown the device if it was initialized (note consoles remain -* functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes -* @port->ops->shutdown(). -*/ -static void tty_port_shutdown (struct tty_port *port,struct tty_struct *tty) +static void tty_port_shutdown_locked (struct tty_port *port,struct tty_struct *tty) { -mutex_lock (&port->mutex); +lockdep_assert_held (&port->mutex); +if (port->console) - goto out; +return ;if (tty_port_initialized (port)) {tty_port_set_initialized (port,0 );
@@ -378,7 +369,22 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)if (port->ops->shutdown) port->ops->shutdown (port); } -out: +} + +/** +* tty_port_shutdown - internal helper to shutdown the device +* @port: tty port to be shut down +* @tty: the associated tty +* +* It is used by tty_port_hangup() and tty_port_close(). Its task is to +* shutdown the device if it was initialized (note consoles remain +* functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes +* @port->ops->shutdown(). +*/ +static void tty_port_shutdown (struct tty_port *port,struct tty_struct *tty) +{ +mutex_lock (&port->mutex); +tty_port_shutdown_locked (port, tty);mutex_unlock (&port->mutex); }
@@ -396,6 +402,7 @@ void tty_port_hangup(struct tty_port *port)struct tty_struct *tty;unsigned long flags; +mutex_lock (&port->mutex);spin_lock_irqsave (&port->lock, flags); port->count =0 ; tty = port->tty;
@@ -404,26 +411,47 @@ void tty_port_hangup(struct tty_port *port) port->tty =NULL ;spin_unlock_irqrestore (&port->lock, flags);tty_port_set_active (port,0 ); -tty_port_shutdown (port, tty); +tty_port_shutdown_locked (port, tty); +mutex_unlock (&port->mutex);tty_kref_put (tty);wake_up_interruptible (&port->open_wait);wake_up_interruptible (&port->delta_msr_wait); }EXPORT_SYMBOL (tty_port_hangup); -void __tty_port_tty_hangup (struct tty_port *port,bool check_clocal,bool async) +/** +* tty_port_tty_hangup - helper to hang up a tty asynchronously +* @port: tty port +* @check_clocal: hang only ttys with %CLOCAL unset? +*/ +void tty_port_tty_hangup (struct tty_port *port,bool check_clocal) {struct tty_struct *tty =tty_port_tty_get (port); -if (tty && (!check_clocal || !C_CLOCAL (tty))) { -if (async) -tty_hangup (tty); -else -tty_vhangup (tty); - } +if (tty && (!check_clocal || !C_CLOCAL (tty))) +tty_hangup (tty);tty_kref_put (tty); } -EXPORT_SYMBOL_GPL (__tty_port_tty_hangup); +EXPORT_SYMBOL_GPL (tty_port_tty_hangup); + +/** +* tty_port_tty_vhangup - helper to hang up a tty synchronously +* @port: tty port +*/ +void tty_port_tty_vhangup (struct tty_port *port) +{ +struct tty_struct *tty; + +mutex_lock (&port->mutex); + tty =tty_port_tty_get (port); +mutex_unlock (&port->mutex); + +if (tty) { +tty_vhangup (tty); +tty_kref_put (tty); + } +} +EXPORT_SYMBOL_GPL (tty_port_tty_vhangup);/** * tty_port_tty_wakeup - helper to wake up a tty
include/linux/tty_port.h +2 -20
@@ -234,7 +234,8 @@ int tty_port_carrier_raised(struct tty_port *port);void tty_port_raise_dtr_rts (struct tty_port *port);void tty_port_lower_dtr_rts (struct tty_port *port);void tty_port_hangup (struct tty_port *port); -void __tty_port_tty_hangup (struct tty_port *port,bool check_clocal,bool async); +void tty_port_tty_hangup (struct tty_port *port,bool check_clocal); +void tty_port_tty_vhangup (struct tty_port *port);void tty_port_tty_wakeup (struct tty_port *port);int tty_port_block_til_ready (struct tty_port *port,struct tty_struct *tty,struct file *filp);
@@ -253,23 +254,4 @@ static inline int tty_port_users(struct tty_port *port) return port->count + port->blocked_open; } -/** -* tty_port_tty_hangup - helper to hang up a tty asynchronously -* @port: tty port -* @check_clocal: hang only ttys with %CLOCAL unset? -*/ -static inline void tty_port_tty_hangup (struct tty_port *port,bool check_clocal) -{ -__tty_port_tty_hangup (port, check_clocal, true); -} - -/** -* tty_port_tty_vhangup - helper to hang up a tty synchronously -* @port: tty port -*/ -static inline void tty_port_tty_vhangup (struct tty_port *port) -{ -__tty_port_tty_hangup (port, false, false); -} -#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 404/1887 wifi: mac80211: keep paired old chanctx alive
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
[ Upstream commit 3412e9a800786d1dec4a58367db1cba275e7ef11 ]
An in-place replacement keeps reciprocal replace_ctx pointers between the old WILL_BE_REPLACED chanctx and the new REPLACES_OTHER chanctx. However, the early free paths only consider assigned and reserved link users when deciding whether to free the old chanctx.
That lets the old chanctx be freed too early while the replacement partner still points back to it, either when the last assigned link is released or when that link successfully reassigns to another existing context. Later unreserve and switch-finalization paths can then follow a stale replace_ctx pointer.
Keep a paired old chanctx alive until the replacement pair has been torn down. Apply the same check to both __ieee80211_link_release_channel() and ieee80211_link_use_reserved_reassign(). If the replacement is later abandoned, ieee80211_link_unreserve_chanctx() already tears down the pairing before freeing the old chanctx once no users remain.
--- net/mac80211/chan.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
net/mac80211/chan.c +12 -2
@@ -1062,6 +1062,7 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) {struct ieee80211_sub_if_data *sdata = link->sdata;struct ieee80211_chanctx *ctx = link->reserved_chanctx; +struct ieee80211_chanctx *old_ctx =NULL ;lockdep_assert_held (&sdata->local->chanctx_mtx);
@@ -1076,6 +1077,7 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)if (WARN_ON (!ctx->replace_ctx))return -EINVAL ; + old_ctx = ctx->replace_ctx;WARN_ON (ctx->replace_ctx->replace_state !=IEEE80211_CHANCTX_WILL_BE_REPLACED );WARN_ON (ctx->replace_ctx->replace_ctx != ctx);
@@ -1086,6 +1088,10 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)list_del_rcu (&ctx->list);kfree_rcu (ctx, rcu_head); + +if (ieee80211_chanctx_refcount (sdata->local, + old_ctx) ==0 ) +ieee80211_free_chanctx (sdata->local, old_ctx); }else {ieee80211_free_chanctx (sdata->local, ctx); }
@@ -1317,7 +1323,9 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)ieee80211_check_fast_xmit_iface (sdata); -if (ieee80211_chanctx_refcount (local, old_ctx) ==0 ) +if (ieee80211_chanctx_refcount (local, old_ctx) ==0 && + !(old_ctx->replace_state ==IEEE80211_CHANCTX_WILL_BE_REPLACED && + old_ctx->replace_ctx))ieee80211_free_chanctx (local, old_ctx);ieee80211_recalc_chanctx_min_def (local, new_ctx,NULL );
@@ -1797,7 +1805,9 @@ static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) }ieee80211_assign_link_chanctx (link,NULL ); -if (ieee80211_chanctx_refcount (local, ctx) ==0 ) +if (ieee80211_chanctx_refcount (local, ctx) ==0 && + !(ctx->replace_state ==IEEE80211_CHANCTX_WILL_BE_REPLACED && + ctx->replace_ctx))ieee80211_free_chanctx (local, ctx); link->radar_required = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 405/1887 wifi: mac80211: count only matching reservations in reserved switch
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
[ Upstream commit 437f3727b4fd715266c296435c116288f82666fd ]
ieee80211_vif_use_reserved_switch() validates a replacement by counting assigned links on ctx->replace_ctx and treating reservations too broadly. A link can still be assigned to the old channel context while holding a reservation that belongs to a different replacement operation.
That can make the current replacement appear complete too early. If another link finalizes first, the function can free the WILL_BE_REPLACED chanctx while the unmatched link and driver still use it, leading to a use-after-free in later beacon generation.
Require an in-place reservation to point at the current replacement context, and require the reserved and assigned contexts to be the matching replacement pair, before counting or moving the link.
--- net/mac80211/chan.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
net/mac80211/chan.c +17 -6
@@ -1389,7 +1389,8 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) }static bool -ieee80211_link_has_in_place_reservation (struct ieee80211_link_data *link) +ieee80211_link_has_in_place_reservation (struct ieee80211_link_data *link, +struct ieee80211_chanctx *ctx) {struct ieee80211_sub_if_data *sdata = link->sdata;struct ieee80211_chanctx *old_ctx, *new_ctx;
@@ -1399,6 +1400,9 @@ ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) new_ctx = link->reserved_chanctx; old_ctx =ieee80211_link_get_chanctx (link); +if (new_ctx != ctx) +return false; +if (!old_ctx)return false;
@@ -1411,6 +1415,12 @@ ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)if (new_ctx->replace_state !=IEEE80211_CHANCTX_REPLACES_OTHER )return false; +if (new_ctx->replace_ctx != old_ctx) +return false; + +if (old_ctx->replace_ctx != new_ctx) +return false; +return true; }
@@ -1460,7 +1470,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,list_for_each_entry (link, &ctx->reserved_links, reserved_chanctx_list) { -if (!ieee80211_link_has_in_place_reservation (link)) +if (!ieee80211_link_has_in_place_reservation (link, ctx))continue ; old_ctx =ieee80211_link_get_chanctx (link);
@@ -1569,7 +1579,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)list_for_each_entry (link, &ctx->replace_ctx->assigned_links, assigned_chanctx_list) { n_assigned++; -if (link->reserved_chanctx) { +if (ieee80211_link_has_in_place_reservation (link, ctx)) { n_reserved++;if (link->reserved_ready) n_ready++;
@@ -1590,7 +1600,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ctx->conf.radar_enabled = false;list_for_each_entry (link, &ctx->reserved_links, reserved_chanctx_list) { -if (ieee80211_link_has_in_place_reservation (link) && +if (ieee80211_link_has_in_place_reservation (link, ctx) && !link->reserved_ready)return -EAGAIN ;
@@ -1664,7 +1674,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)struct ieee80211_bss_conf *link_conf = link->conf;u32 changed =0 ; -if (!ieee80211_link_has_in_place_reservation (link)) +if (!ieee80211_link_has_in_place_reservation (link, ctx))continue ; rcu_assign_pointer(link_conf->chanctx_conf,
@@ -1717,7 +1727,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)*/ list_for_each_entry_safe (link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { -if (WARN_ON (ieee80211_link_has_in_place_reservation (link))) +if (WARN_ON (ieee80211_link_has_in_place_reservation (link, + ctx)))continue ;if (WARN_ON (link->reserved_chanctx != ctx))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 406/1887 fs: Free any excess xarray nodes in clear_inode()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit ee3f011250104129893d8e9599147e457d4d7280 ]
For many years we've had a hard to hit leak of xarray nodes. Hugh documented it well in commit 786b31121a2c. Recently people and syzbot have found ways to force it to happen with madvise. Rather than fix the leaks where they happen, just call xa_destroy() which has the side-effect of cycling the i_pages lock.
--- fs/inode.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
fs/inode.c +10 -13
@@ -642,21 +642,18 @@ void dump_mapping(const struct address_space *mapping)void clear_inode (struct inode *inode) {/* -* We have to cycle the i_pages lock here because reclaim can be in the -* process of removing the last page (in __filemap_remove_folio()) -* and we must not free the mapping under it. +* We have to cycle the i_pages lock here because reclaim +* can be in the process of removing the last page (in +* __filemap_remove_folio()) and we must not free the mapping +* under it. We also remove nodes which are empty; these +* can occur in two different ways. The first is that radix +* tree expansion can fail partway and the second is that THP +* collapse_file() can allocate some temporary nodes and not +* clean them up. */ -xa_lock_irq (&inode->i_data.i_pages); +xa_destroy (&inode->i_data.i_pages); +BUG_ON (inode->i_data.nrpages); -/* -* Almost always, mapping_empty(&inode->i_data) here; but there are -* two known and long-standing ways in which nodes may get left behind -* (when deep radix-tree node allocation failed partway; or when THP -* collapse_file() failed). Until those two known cases are cleaned up, -* or a cleanup function is called here, do not BUG_ON(!mapping_empty), -* nor even WARN_ON(!mapping_empty). -*/ -xa_unlock_irq (&inode->i_data.i_pages);BUG_ON (!list_empty (&inode->i_data.private_list));BUG_ON (!(inode->i_state &I_FREEING ));BUG_ON (inode->i_state &I_CLEAR );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 407/1887 mm/hugetlb: fix avoid_reserve to allow taking folio from subpool
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Xu <[email protected]>
commit 58db7c5fbe7daa42098d4965133a864f98ba90ba upstream.
Patch series "mm/hugetlb: Refactor hugetlb allocation resv accounting", v2.
This is a follow up on Ackerley's series here as replacement:
https://lore.kernel.org/r/[email protected]
The goal of this series is to cleanup hugetlb resv accounting, especially during folio allocation, to decouple a few things:
- Hugetlb folios v.s. Hugetlbfs: IOW, the hope is in the future hugetlb folios can be allocated completely without hugetlbfs.
- Decouple VMA v.s. hugetlb folio allocations: allocating a hugetlb folio should not always require a hugetlbfs VMA. For example, either it got allocated from the inode level (see hugetlbfs_fallocate() where it used a pesudo VMA for allocation), or it can be allocated by other kernel subsystems.
It paves way for other users to allocate hugetlb folios out of either system reservations, or subpools (instead of hugetlbfs, as a file system). For longer term, this prepares hugetlb as a separate concept versus hugetlbfs, so that hugetlb folios can be allocated by not only hugetlbfs and other things.
Tests I've done:
- I had a reproducer in patch 1 for the bug I found, this will start to work after patch 1 or the whole set applied.
- Hugetlb regression tests (on x86_64 2MBs), includes:
- All vmtests on hugetlbfs
- libhugetlbfs test suite (which may fail some tests, but no new failures will be introduced by this series, so all such failures happen before this series so shouldn't be relevant).
This patch (of 7):
Since commit 04f2cbe35699 ("hugetlb: guarantee that COW faults for a process that called mmap(MAP_PRIVATE) on hugetlbfs will succeed"), avoid_reserve was introduced for a special case of CoW on hugetlb private mappings, and only if the owner VMA is trying to allocate yet another hugetlb folio that is not reserved within the private vma reserved map.
Later on, in commit d85f69b0b533 ("mm/hugetlb: alloc_huge_page handle areas hole punched by fallocate"), alloc_huge_page() enforced to not consume any global reservation as long as avoid_reserve=true. This operation doesn't look correct, because even if it will enforce the allocation to not use global reservation at all, it will still try to take one reservation from the spool (if the subpool existed). Then since the spool reserved pages take from global reservation, it'll also take one reservation globally.
Logically it can cause global reservation to go wrong.
I wrote a reproducer below, trigger this special path, and every run of such program will cause global reservation count to increment by one, until it hits the number of free pages:
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#define MSIZE (2UL << 20)
int main(int argc, char *argv[])
{
const char *path;
int *buf;
int fd, ret;
pid_t child; if (argc < 2) {
printf("usage: %s <hugetlb_file>\n", argv[0]);
return -1;
}
path = argv[1];
fd = open(path, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
perror("open failed");
return -1;
}
ret = fallocate(fd, 0, 0, MSIZE);
if (ret != 0) {
perror("fallocate");
return -1;
}
buf = mmap(NULL, MSIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED) {
perror("mmap() failed");
return -1;
}
/* Allocate a page */
*buf = 1;
child = fork();
if (child == 0) {
/* child doesn't need to do anything */
exit(0);
}
/* Trigger CoW from owner */
*buf = 2;
munmap(buf, MSIZE);
close(fd);
unlink(path);
return 0;}
It can only reproduce with a sub-mount when there're reserved pages on the spool, like:
# sysctl vm.nr_hugepages=128 # mkdir ./hugetlb-pool # mount -t hugetlbfs -o min_size=8M,pagesize=2M none ./hugetlb-pool
Then run the reproducer on the mountpoint:
# ./reproducer ./hugetlb-pool/test
Fix it by taking the reservation from spool if available. In general, avoid_reserve is IMHO more about "avoid vma resv map", not spool's.
I copied stable, however I have no intention for backporting if it's not a clean cherry-pick, because private hugetlb mapping, and then fork() on top is too rare to hit.
[ Karl Mehltretter: The upstream changes map directly to this stable tree's
page-based HugeTLB helpers. The backport retains this stable tree's direct -ENOSPC return instead of importing the later out_end_reservation path; the functional changes otherwise match upstream. ]
--- mm/hugetlb.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-)
mm/hugetlb.c +3 -19
@@ -1397,8 +1397,7 @@ static unsigned long available_huge_pages(struct hstate *h)static struct page *dequeue_huge_page_vma (struct hstate *h,struct vm_area_struct *vma, -unsigned long address,int avoid_reserve, -long chg) +unsigned long address,long chg) {struct page *page =NULL ;struct mempolicy *mpol;
@@ -1414,10 +1413,6 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,if (!vma_has_reserves (vma, chg) && !available_huge_pages (h)) goto err; -/* If reserves cannot be used, ensure enough pages are in the pool */ -if (avoid_reserve && !available_huge_pages (h)) - goto err; - gfp_mask =htlb_alloc_mask (h); nid =huge_node (vma, address, gfp_mask, &mpol, &nodemask);
@@ -1431,7 +1426,7 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,if (!page) page =dequeue_huge_page_nodemask (h, gfp_mask, nid, nodemask); -if (page && !avoid_reserve &&vma_has_reserves (vma, chg)) { +if (page &&vma_has_reserves (vma, chg)) {SetHPageRestoreReserve (page); h->resv_huge_pages--; }
@@ -3114,17 +3109,6 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,vma_end_reservation (h, vma, addr);return ERR_PTR (-ENOSPC ); } - -/* -* Even though there was no reservation in the region/reserve -* map, there could be reservations associated with the -* subpool that can be used. This would be indicated if the -* return value of hugepage_subpool_get_pages() is zero. -* However, if avoid_reserve is specified we still avoid even -* the subpool reservations. -*/ -if (avoid_reserve) - gbl_chg =1 ; }/* If this allocation is not consuming a reservation, charge it now.
@@ -3147,7 +3131,7 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,* from the global free pool (global change). gbl_chg == 0 indicates * a reservation exists for the allocation. */ - page =dequeue_huge_page_vma (h, vma, addr, avoid_reserve, gbl_chg); + page =dequeue_huge_page_vma (h, vma, addr, gbl_chg);if (!page) {spin_unlock_irq (&hugetlb_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 408/1887 KVM: SVM: Use the active VMCBs MSR bitmap when checking if MSR is intercepted
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
[ Upstream commit 9e06bbb9ade7cdf28d4a3b5b14e5812881c8df85 ]
Use the MSR permission bitmap of the active VMCB instead of assuming that KVM is always using vmcb02's bitmap when L2 is active, as KVM uses msrpm02 if and only if L1 wants to intercept MSR accesses, i.e. if and only if KVM needs to merge msprm01 with msrpm12.
Don't bother tracking the virtual address of the bitmap that's being used, as __va() is cheap on x86, and caching the virtual address would introduce yet another source of potentially stale information.
Message-ID: <[email protected]>
--- arch/x86/kvm/svm/svm.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-)
arch/x86/kvm/svm/svm.c +1 -11
@@ -732,17 +732,7 @@ static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)u32 offset;u32 *msrpm; -/* -* For non-nested case: -* If the L01 MSR bitmap does not intercept the MSR, then we need to -* save it. -* -* For nested case: -* If the L02 MSR bitmap does not intercept the MSR, then we need to -* save it. -*/ - msrpm =is_guest_mode (vcpu) ?to_svm (vcpu)->nested.msrpm: -to_svm (vcpu)->msrpm; + msrpm =__va (__sme_clr (to_svm (vcpu)->vmcb->control.msrpm_base_pa)); offset =svm_msrpm_offset (msr); bit_write =2 * (msr &0x0f ) +1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 409/1887 wifi: mac80211: set info->band for 802.3 encap offload frames
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 4febc02cd02f021f2b6d0768332be643ef14a12d ]
Unlike the 802.11 TX paths, ieee80211_8023_xmit() does not set info->band from the channel context on non-MLD interfaces. It stays at 0, so ieee80211_get_tx_rates() uses the wrong band for these frames.
Set it the same way as ieee80211_build_hdr(): drop the frame if there is no channel context, and leave the band at 0 on MLD interfaces.
--- net/mac80211/tx.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/mac80211/tx.c +11 -0
@@ -4545,6 +4545,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, {struct ieee80211_tx_info *info;struct ieee80211_local *local = sdata->local; +struct ieee80211_chanctx_conf *chanctx_conf;struct tid_ampdu_tx *tid_tx;u8 tid;
@@ -4602,6 +4603,16 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, sdata =container_of (sdata->bss, struct ieee80211_sub_if_data, u.ap); +/* MLD transmissions must not rely on the band */ +if (!sdata->vif.valid_links) { + chanctx_conf =rcu_dereference (sdata->vif.bss_conf.chanctx_conf); +if (unlikely (!chanctx_conf)) { +kfree_skb (skb); +return ; + } + info->band = chanctx_conf->def.chan->band; + } + info->flags |=IEEE80211_TX_CTL_HW_80211_ENCAP ; info->control.vif = &sdata->vif;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 410/1887 smb: client: discard post-EOF pagecache when extending a file via zero range
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <[email protected]>
[ Upstream commit da4fe97fb6c730d9c94a115c7bfa6f98e0d578d0 ]
smb3_zero_range() removed the pagecache only for the range being zeroed, so when it extends the file the folio straddling the old EOF - which may hold data dirtied past EOF through an mmap - was never dropped and became visible as file content once the file was extended.
Lower the discard boundary to the smaller of the zero-range offset and the old EOF.
--- fs/smb/client/smb2ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/smb/client/smb2ops.c +4 -1
@@ -3542,8 +3542,11 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,/* * We zero the range through ioctl, so we need remove the page caches * first, otherwise the data may be inconsistent with the server. +* +* Start at the old EOF when extending so the folio straddling it, which +* may hold data written past EOF through an mmap, is dropped too. */ -truncate_pagecache_range (inode, offset, offset + len -1 ); +truncate_pagecache_range (inode,min (offset, i_size), offset + len -1 );/* if file not oplocked can't be sure whether asking to extend size */ rc = -EOPNOTSUPP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 411/1887 iio: adc: ad_sigma_delta: fix use-after-free on unbind
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit 9ee8306121495d2a25aa5d1bfd519f2748786b83 ]
ad_sd_buffer_postenable() allocates sigma_delta->samples_buf with devm_krealloc() at runtime, so its devres entry sits after all probe-time entries of the driver. devm resources are released in reverse allocation order, which means unbind frees samples_buf before iio_device_unregister() disables the buffers and detaches the trigger pollfunc. The data ready IRQ is still enabled at that point, so ad_sd_trigger_handler() can still run and memcpy() incoming samples into the freed samples_buf.
Fix this by preallocating the buffer in devm_ad_sd_setup_buffer_and_trigger(), before the triggered buffer and the IRQ are set up, so it is freed only after iio_device_unregister() has drained the trigger handler via free_irq(). Size it for the worst case of all sequencer slots being active; ad_sd_validate_scan_mask() already caps the number of active channels at num_slots.
This issue was found by an in-house static analysis tool.
--- drivers/iio/adc/ad_sigma_delta.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-)
drivers/iio/adc/ad_sigma_delta.c +15 -11
@@ -343,9 +343,8 @@ EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, IIO_AD_SIGMA_DELTA);static int ad_sd_buffer_postenable (struct iio_dev *indio_dev) {struct ad_sigma_delta *sigma_delta =iio_device_get_drvdata (indio_dev); -unsigned int i, slot, samples_buf_size; +unsigned int i, slot;unsigned int channel; -uint8_t *samples_buf;int ret;if (sigma_delta->num_slots ==1 ) {
@@ -378,15 +377,6 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)return ret; } - samples_buf_size =ALIGN (slot * indio_dev->channels[0 ].scan_type.storagebits /8 ,8 ); - samples_buf_size +=sizeof (int64_t ); - samples_buf =devm_krealloc (&sigma_delta->spi->dev, sigma_delta->samples_buf, - samples_buf_size,GFP_KERNEL ); -if (!samples_buf) -return -ENOMEM ; - - sigma_delta->samples_buf = samples_buf; -spi_bus_lock (sigma_delta->spi->master); sigma_delta->bus_locked = true; sigma_delta->keep_cs_asserted = true;
@@ -620,6 +610,7 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_deint devm_ad_sd_setup_buffer_and_trigger (struct device *dev,struct iio_dev *indio_dev) {struct ad_sigma_delta *sigma_delta =iio_device_get_drvdata (indio_dev); +unsigned int samples_buf_size;int ret; sigma_delta->slots = devm_kcalloc(dev, sigma_delta->num_slots,
@@ -627,6 +618,19 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indiif (!sigma_delta->slots)return -ENOMEM ; +/* +* Worst-case size: all sequencer slots can be active, capped +* at num_slots by ad_sd_validate_scan_mask(). +*/ + samples_buf_size = +ALIGN (sigma_delta->num_slots * +BITS_TO_BYTES (indio_dev->channels[0 ].scan_type.storagebits), +sizeof (s64)); + samples_buf_size +=sizeof (s64); + sigma_delta->samples_buf =devm_kzalloc (dev, samples_buf_size,GFP_KERNEL ); +if (!sigma_delta->samples_buf) +return -ENOMEM ; + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &ad_sd_trigger_handler,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 412/1887 iio: adc: aspeed: Simplify with dev_err_probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <[email protected]>
[ Upstream commit dcc3ac29f46fff6775c0a945afc68fd9dece6d34 ]
Use dev_err_probe() to make error code handling simpler and handle deferred probe nicely (avoid spamming logs).
Stable-dep-of: 95e4eb426b4b ("iio: adc: aspeed: propagate reset deassert errors")
--- drivers/iio/adc/aspeed_adc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/iio/adc/aspeed_adc.c +4 -5
@@ -549,11 +549,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)return PTR_ERR (data->clk_scaler); data->rst =devm_reset_control_get_shared (&pdev->dev,NULL ); -if (IS_ERR (data->rst)) { -dev_err (&pdev->dev, -"invalid or missing reset controller device tree entry" ); -return PTR_ERR (data->rst); - } +if (IS_ERR (data->rst)) +return dev_err_probe (&pdev->dev,PTR_ERR (data->rst), +"invalid or missing reset controller device tree entry" ); +reset_control_deassert (data->rst); ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 413/1887 iio: adc: aspeed: propagate reset deassert errors
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 95e4eb426b4bd666fa2f37886c0ddf74a0cc6167 ]
aspeed_adc_probe() continues to register ADC resources after deasserting the shared reset, even if the reset controller reports a failure.
A failed deassertion leaves the hardware unavailable, so stop probing before installing the cleanup action and enabling the ADC.
--- drivers/iio/adc/aspeed_adc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iio/adc/aspeed_adc.c +3 -1
@@ -553,7 +553,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)return dev_err_probe (&pdev->dev,PTR_ERR (data->rst),"invalid or missing reset controller device tree entry" ); -reset_control_deassert (data->rst); + ret =reset_control_deassert (data->rst); +if (ret) +return ret; ret =devm_add_action_or_reset (data->dev, aspeed_adc_reset_assert, data->rst);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 414/1887 iio: adc: max1363: sign-extend bipolar differential channel reads
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
[ Upstream commit 91908c0a78baddc8572aa3ab69e62ee2eb496ba4 ]
MAX1363 differential channels are bipolar, but max1363_read_single_chan() masks the raw value to the ADC resolution without sign-extending it. Negative differential readings are therefore reported to userspace as large positive values (e.g. -1 as 4095 on a 12-bit part).
Sign-extend the masked value from the resolution bit for differential channels. Single-ended channels are unipolar and are left unchanged.
--- drivers/iio/adc/max1363.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/iio/adc/max1363.c +8 -0
@@ -408,6 +408,14 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, } data = rxbuf[0 ]; } + +/* +* Differential channels are bipolar and the device returns the sample +* in two's complement, so sign-extend it from the resolution bit. +*/ +if (chan->differential) + data =sign_extend32 (data, st->chip_info->bits -1 ); + *val = data; error_ret:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 415/1887 iio: adc: axp288: Add TS bias override for Haier HV103H
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladyslav Ivashchenko <[email protected]>
[ Upstream commit 0f300db7b7315b2c7ea0e2d4437b88de162d191f ]
The Haier HV103H firmware configures the AXP288 TS pin bias current to 60 uA. This causes the battery temperature reading to cross the charging temperature threshold under load, incorrectly stopping battery charging.
Setting the TS bias current to 80 uA fixes the temperature measurement and prevents charging from being incorrectly disabled.
Add a DMI quirk to use the 80 uA TS bias current on the Haier HV103H.
--- drivers/iio/adc/axp288_adc.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/iio/adc/axp288_adc.c +8 -0
@@ -204,6 +204,14 @@ static const struct dmi_system_id axp288_adc_ts_bias_override[] = { }, .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA, }, + { + /* Haier HV103H */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Haier"), + DMI_MATCH(DMI_PRODUCT_NAME, "HV103H"), + }, + .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA, + }, {} };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 416/1887 iio: adc: stm32-adc: fix possible division by zero in processed channel
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabrice Gasnier <[email protected]>
[ Upstream commit c5de6a6f855fdcf1e0ea549fb227a316db51c405 ]
In case the conversion has failed or returned zero, processing *val can lead to a division by zero. Need to check for errors, or converted value is zero, before processing the data. In case the converted value is zero, e.g. the Vrefint channel, this should be considered as invalid in all cases.
--- drivers/iio/adc/stm32-adc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/iio/adc/stm32-adc.c +7 -2
@@ -1372,11 +1372,16 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, ret =stm32_adc_single_conv (indio_dev, chan, val); else ret = -EINVAL ; +iio_device_release_direct_mode (indio_dev); +if (ret <0 ) +return ret; -if (mask ==IIO_CHAN_INFO_PROCESSED ) +if (mask ==IIO_CHAN_INFO_PROCESSED ) { +if (*val ==0 ) +return -EINVAL ; *val =STM32_ADC_VREFINT_VOLTAGE * adc->vrefint.vrefint_cal / *val; + } -iio_device_release_direct_mode (indio_dev);return ret;case IIO_CHAN_INFO_SCALE :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 417/1887 iio: cdc: ad7150: fix OF matching and publish module aliases
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 52da294027f53e7084c18dd4b4f73354a40382f3 ]
The OF match entries use positional initializers, which initialize the name field rather than compatible. Consequently the advertised AD7150, AD7151 and AD7156 compatible strings do not describe OF compatible matches. The table is also not exported for module alias generation.
Use designated compatible initializers and publish the OF table. Keep the existing I2C ID table and its device-variant selection unchanged.
The issue was found by our static-analysis tool.
--- drivers/iio/cdc/ad7150.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/iio/cdc/ad7150.c +5 -3
@@ -653,11 +653,13 @@ static const struct i2c_device_id ad7150_id[] = {MODULE_DEVICE_TABLE (i2c, ad7150_id);static const struct of_device_id ad7150_of_match[] = { - {"adi,ad7150" }, - {"adi,ad7151" }, - {"adi,ad7156" }, + { .compatible ="adi,ad7150" }, + { .compatible ="adi,ad7151" }, + { .compatible ="adi,ad7156" }, {} }; +MODULE_DEVICE_TABLE (of, ad7150_of_match); +static struct i2c_driver ad7150_driver = { .driver = { .name ="ad7150" ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 418/1887 fs/ntfs3: Add more checks in mi_enum_attr (part 2)
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
[ Upstream commit a8f659ce14f8f734894227ba2c5ca78c8451501e ]
Add offset check before access to attr->non_res field as mentioned in [1].
[1] https://lore.kernel.org/ntfs3/[email protected]/
--- fs/ntfs3/record.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
fs/ntfs3/record.c +13 -3
@@ -206,7 +206,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)return NULL ;if (off >= used || off <MFTRECORD_FIXUP_OFFSET_1 || - !IS_ALIGNED (off,4 )) { + !IS_ALIGNED (off,8 )) {return NULL ; }
@@ -230,8 +230,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) off += asize; } -/* Can we use the first field (attr->type). */ -/* NOTE: this code also checks attr->size availability. */ +/* +* Can we use the first fields: +* attr->type, +* attr->size +*/ if (off +8 > used) {static_assert (ALIGN (sizeof (enum ATTR_TYPE ),8 ) ==8 );return NULL ;
@@ -253,10 +256,17 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) asize =le32_to_cpu (attr->size); +if (!IS_ALIGNED (asize,8 )) +return NULL ; +/* Check overflow and boundary. */ if (off + asize < off || off + asize > used)return NULL ; +/* Can we use the field attr->non_res. */ +if (off +9 > used) +return NULL ; +/* Check size of attribute. */ if (!attr->non_res) {/* Check resident fields. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 419/1887 fs/ntfs3: Mark inode as bad as soon as error detected in mi_enum_attr()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
[ Upstream commit 2afd4d267e6dbaec8d3ccd4f5396cb84bc67aa2e ]
Extended the mi_enum_attr() function interface with an additional parameter, struct ntfs_inode *ni, to allow marking the inode as bad as soon as an error is detected.
[ Backport to 6.1.y: passed ni to an extra mi_find_attr() caller that mainline had refactored differently. mi_find_attr()'s name_len argument is kept as 6.1.y's size_t. Kept 6.1.y's last resident fields check in mi_enum_attr() but replaced return NULL with goto out. ]
--- fs/ntfs3/attrib.c | 11 ++++--- fs/ntfs3/frecord.c | 59 ++++++++++++++++++---------------- fs/ntfs3/ntfs_fs.h | 21 ++++++------ fs/ntfs3/record.c | 79 ++++++++++++++++++++++++---------------------- 4 files changed, 90 insertions(+), 80 deletions(-)
fs/ntfs3/attrib.c +6 -5
@@ -815,7 +815,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,if (err) goto out; - attr =mi_find_attr (mi,NULL , type, name, name_len, &le->id); + attr =mi_find_attr (ni, mi,NULL , type, name, name_len, + &le->id);if (!attr) { err = -EINVAL ; goto bad_inode;
@@ -1166,7 +1167,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, goto out; } - attr =mi_find_attr (mi,NULL ,ATTR_DATA ,NULL ,0 , + attr =mi_find_attr (ni, mi,NULL ,ATTR_DATA ,NULL ,0 , &le->id);if (!attr) { err = -EINVAL ;
@@ -1786,7 +1787,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, goto out; } - attr =mi_find_attr (mi,NULL ,ATTR_DATA ,NULL ,0 , + attr =mi_find_attr (ni, mi,NULL ,ATTR_DATA ,NULL ,0 , &le->id);if (!attr) { err = -EINVAL ;
@@ -2031,8 +2032,8 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) }/* Look for required attribute. */ - attr =mi_find_attr (mi,NULL ,ATTR_DATA ,NULL , -0 , &le->id); + attr =mi_find_attr (ni, mi,NULL ,ATTR_DATA , +NULL ,0 , &le->id);if (!attr) { err = -EINVAL ; goto out;
fs/ntfs3/frecord.c +31 -28
226 lines not on this page · raw message
fs/ntfs3/ntfs_fs.h +11 -10
@@ -733,23 +733,24 @@ int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi);void mi_put (struct mft_inode *mi);int mi_init (struct mft_inode *mi,struct ntfs_sb_info *sbi,CLST rno);int mi_read (struct mft_inode *mi,bool is_mft); -struct ATTRIB *mi_enum_attr (struct mft_inode *mi,struct ATTRIB *attr); -// TODO: id? -struct ATTRIB *mi_find_attr (struct mft_inode *mi,struct ATTRIB *attr, -enum ATTR_TYPE type,const __le16 *name, -size_t name_len,const __le16 *id); -static inline struct ATTRIB *rec_find_attr_le (struct mft_inode *rec, +struct ATTRIB *mi_enum_attr (struct ntfs_inode *ni,struct mft_inode *mi, +struct ATTRIB *attr); +struct ATTRIB *mi_find_attr (struct ntfs_inode *ni,struct mft_inode *mi, +struct ATTRIB *attr,enum ATTR_TYPE type, +const __le16 *name,size_t name_len,const __le16 *id); +static inline struct ATTRIB *rec_find_attr_le (struct ntfs_inode *ni, +struct mft_inode *rec,struct ATTR_LIST_ENTRY *le) { -return mi_find_attr (rec,NULL , le->type,le_name (le), le->name_len, +return mi_find_attr (ni, rec,NULL , le->type,le_name (le), le->name_len, &le->id); }int mi_write (struct mft_inode *mi,int wait);int mi_format_new (struct mft_inode *mi,struct ntfs_sb_info *sbi,CLST rno,__le16 flags,bool is_mft); -struct ATTRIB *mi_insert_attr (struct mft_inode *mi,enum ATTR_TYPE type, -const __le16 *name,u8 name_len,u32 asize, -u16 name_off); +struct ATTRIB *mi_insert_attr (struct ntfs_inode *ni,struct mft_inode *mi, +enum ATTR_TYPE type,const __le16 *name, +u8 name_len,u32 asize,u16 name_off);bool mi_remove_attr (struct ntfs_inode *ni,struct mft_inode *mi,struct ATTRIB *attr);
fs/ntfs3/record.c +42 -37
216 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 420/1887 fs/ntfs3: fix KMSAN uninit-value in ni_create_attr_list
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nirbhay Sharma <[email protected]>
[ Upstream commit 5f33da04e6ceee849e76e6592cc283c72fef7af9 ]
The call to kmalloc() to allocate the attribute list buffer is given a size of al_aligned(rs). This size can be larger than the data subsequently copied into the buffer, leaving trailing bytes uninitialized.
This can trigger a KMSAN "uninit-value" warning if that memory is later accessed.
Fix this by using kzalloc() instead, which ensures the entire allocated buffer is zero-initialized, preventing the warning.
[ Backport to 6.1.y: only kmalloc -> kzalloc applied; 6.1.y lacks
14f527d44de6 ("fs/ntfs3: Correct checking while generating attr_list") error-path rework. ]
--- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ntfs3/frecord.c +1 -1
@@ -819,7 +819,7 @@ int ni_create_attr_list(struct ntfs_inode *ni)* Skip estimating exact memory requirement. * Looks like one record_size is always enough. */ - le =kmalloc (al_aligned (rs),GFP_NOFS ); + le =kzalloc (al_aligned (rs),GFP_NOFS );if (!le) { err = -ENOMEM ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 421/1887 fs/ntfs3: fix slab-out-of-bounds write in ni_create_attr_list()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HE WEI(ギカク) <[email protected]>
[ Upstream commit 7c4841e2a62794a3bab7c1ff0540580f387e377f ]
ni_create_attr_list() allocates a fixed buffer of al_aligned(record_size) (== record_size) bytes and then walks every attribute of the primary MFT record, writing one ATTR_LIST_ENTRY per attribute and advancing the cursor by le_size(name_len), with no check against the end of the buffer; the total size is only computed after the loop.
A minimum-size resident attribute occupies SIZEOF_RESIDENT (0x18 = 24) bytes on disk, but an unnamed attribute expands to le_size(0) (0x20 = 32) bytes in the list. Because the number of attributes in a record is not bounded (mi_enum_attr() accepts arbitrarily many equal-type, nameless minimum-size attributes), a crafted record packed with such attributes produces a list larger than record_size and overflows the heap buffer.
This is reachable from a crafted, loop-mounted NTFS image: opening the file and adding an attribute (e.g. via setxattr) drives ntfs_set_ea() -> ni_insert_resident() -> ni_insert_attr() -> ni_ins_attr_ext() -> ni_create_attr_list().
BUG: KASAN: slab-out-of-bounds in ni_create_attr_list+0xc48/0x1058 Write of size 4 at addr ffff000008984c00 by task setfattr/345 ni_create_attr_list+0xc48/0x1058 ni_ins_attr_ext+0x510/0x7c0 ni_insert_attr+0x3f8/0x70c ni_insert_resident+0xc8/0x3b0 ntfs_set_ea+0x66c/0xd28 ntfs_setxattr+0x4d8/0x5b0 __arm64_sys_setxattr+0xa4/0x124 Allocated by task 345: ni_create_attr_list+0x188/0x1058 The buggy address belongs to the cache kmalloc-1k of size 1024 (the write lands at object+1024).
Size the buffer from the actual attributes instead of assuming a single record_size is always enough.
--- fs/ntfs3/frecord.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
fs/ntfs3/frecord.c +16 -4
@@ -816,10 +816,23 @@ int ni_create_attr_list(struct ntfs_inode *ni) rs = sbi->record_size;/* -* Skip estimating exact memory requirement. -* Looks like one record_size is always enough. +* Compute the exact size of the attribute list. Each attribute in the +* record yields one ATTR_LIST_ENTRY of le_size(name_len) bytes. The +* minimum on-disk attribute is SIZEOF_RESIDENT (0x18) bytes, but an +* unnamed one expands to le_size(0) (0x20) here, so a record crafted +* with many such attributes needs more than a single record_size; the +* previous fixed kzalloc(record_size) could therefore be overflowed by +* an attacker-controlled record. */ - le =kzalloc (al_aligned (rs),GFP_NOFS ); + lsize =0 ; + attr =NULL ; +while ((attr =mi_enum_attr (ni, &ni->mi, attr))) + lsize +=le_size (attr->name_len); + +if (!lsize) +return -EINVAL ; + + le =kzalloc (al_aligned (lsize),GFP_NOFS );if (!le) { err = -ENOMEM ; goto out;
@@ -831,7 +844,6 @@ int ni_create_attr_list(struct ntfs_inode *ni) attr =NULL ; nb =0 ; free_b =0 ; - attr =NULL ;for (; (attr =mi_enum_attr (ni, &ni->mi, attr)); le =Add2Ptr (le, sz)) { sz =le_size (attr->name_len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 422/1887 scsi: lpfc: Fix use-after-free of mboxq in lpfc_sli4_driver_resource_setup()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrey Misiurov <[email protected]>
The 6.1.y backport of upstream commit 1bd28625e25b ("scsi: lpfc: Fix memory leak in lpfc_sli4_driver_resource_setup()") added the new mempool_free() of mboxq in the wrong place. Upstream frees mboxq after the error handling of lpfc_get_sli4_parameters(). In 6.1.y the hunk landed before that call, right after the NVMET WWN loop:
mempool_free(mboxq, phba->mbox_mem_pool); lpfc_nvme_mod_param_dep(phba); rc = lpfc_get_sli4_parameters(phba, mboxq);
mbox_mem_pool is created a few lines earlier in the same function, so the pool is full and mempool_free() really kfree()s mboxq. lpfc_get_sli4_parameters() then builds and issues a mailbox command in freed memory. This happens on every SLI4 probe. Its error paths also free mboxq a second time.
Move the mempool_free() to where upstream and the other stable trees have it.
--- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/lpfc/lpfc_init.c +1 -1
@@ -8175,7 +8175,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) } } } -mempool_free (mboxq, phba->mbox_mem_pool);lpfc_nvme_mod_param_dep (phba);
@@ -8209,6 +8208,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_free_bsmbx; } } +mempool_free (mboxq, phba->mbox_mem_pool);/* * 1 for cmd, 1 for rsp, NVME adds an extra one
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 423/1887 HID: core: introduce hid_safe_input_report()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 206342541fc887ae919774a43942dc883161fece ]
hid_input_report() is used in too many places to have a commit that doesn't cross subsystem borders. Instead of changing the API, introduce a new one when things matters in the transport layers:
- usbhid
- i2chid
This effectively revert to the old behavior for those two transport layers.
[Lee: Implement hid_safe_input_report() directly and wrap it from
hid_input_report() as 67eccf151d76 ("HID: add source argument to HID low level functions") is not present]
--- drivers/hid/hid-core.c | 26 ++++++++++++++++++++++++-- drivers/hid/i2c-hid/i2c-hid-core.c | 7 ++++--- drivers/hid/usbhid/hid-core.c | 11 ++++++----- include/linux/hid.h | 2 ++ 4 files changed, 36 insertions(+), 10 deletions(-)
drivers/hid/hid-core.c +24 -2
@@ -2085,14 +2085,36 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);* @interrupt: distinguish between interrupt and control transfers * * This is data entry for lower layers. +* Legacy, please use hid_safe_input_report() instead. */ int hid_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data,u32 size,int interrupt) +{ +return hid_safe_input_report (hid, type, data, size, size, interrupt); +} +EXPORT_SYMBOL_GPL (hid_input_report); + +/** +* hid_safe_input_report - report data from lower layer (usb, bt...) +* +* @hid: hid device +* @type: HID report type (HID_*_REPORT) +* @data: report contents +* @bufsize: allocated size of the data buffer +* @size: useful size of data parameter +* @interrupt: distinguish between interrupt and control transfers +* +* This is data entry for lower layers. +* Please use this function instead of the non safe version because we provide +* here the size of the buffer, allowing hid-core to make smarter decisions +* regarding the incoming buffer. +*/ +int hid_safe_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data, +size_t bufsize,u32 size,int interrupt) {struct hid_report_enum *report_enum;struct hid_driver *hdrv;struct hid_report *report; -size_t bufsize = size;int ret =0 ;if (!hid)
@@ -2137,7 +2159,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *dataup (&hid->driver_input_lock);return ret; } -EXPORT_SYMBOL_GPL (hid_input_report); +EXPORT_SYMBOL_GPL (hid_safe_input_report);bool hid_match_one_id (const struct hid_device *hdev,const struct hid_device_id *id)
drivers/hid/i2c-hid/i2c-hid-core.c +4 -3
@@ -539,9 +539,10 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)if (ihid->hid->group !=HID_GROUP_RMI )pm_wakeup_event (&ihid->client->dev,0 ); -hid_input_report (ihid->hid,HID_INPUT_REPORT , - ihid->inbuf +sizeof (__le16), - ret_size -sizeof (__le16),1 ); +hid_safe_input_report (ihid->hid,HID_INPUT_REPORT , + ihid->inbuf +sizeof (__le16), + ihid->bufsize -sizeof (__le16), + ret_size -sizeof (__le16),1 ); }return ;
drivers/hid/usbhid/hid-core.c +6 -5
@@ -281,9 +281,9 @@ static void hid_irq_in(struct urb *urb)break ;usbhid_mark_busy (usbhid);if (!test_bit (HID_RESUME_RUNNING , &usbhid->iofl)) { -hid_input_report (urb->context,HID_INPUT_REPORT , - urb->transfer_buffer, - urb->actual_length,1 ); +hid_safe_input_report (urb->context,HID_INPUT_REPORT , + urb->transfer_buffer, urb->transfer_buffer_length, + urb->actual_length,1 );/* * autosuspend refused while keys are pressed * because most keyboards don't wake up when
@@ -480,9 +480,10 @@ static void hid_ctrl(struct urb *urb)switch (status) {case 0 :/* success */ if (usbhid->ctrl[usbhid->ctrltail].dir ==USB_DIR_IN ) -hid_input_report (urb->context, +hid_safe_input_report (urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, - urb->transfer_buffer, urb->actual_length,0 ); + urb->transfer_buffer, urb->transfer_buffer_length, + urb->actual_length,0 );break ;case -ESHUTDOWN :/* unplug */ unplug =1 ;
include/linux/hid.h +2 -0
@@ -960,6 +960,8 @@ extern void hidinput_disconnect(struct hid_device *);int hid_set_field (struct hid_field *,unsigned ,__s32 );int hid_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data,u32 size,int interrupt); +int hid_safe_input_report (struct hid_device *hid,enum hid_report_type type,u8 *data, +size_t bufsize,u32 size,int interrupt);struct hid_field *hidinput_get_led_field (struct hid_device *hid);unsigned int hidinput_count_leds (struct hid_device *hid);__s32 hidinput_calc_abs_res (const struct hid_field *field,__u16 code);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 424/1887 HID: uhid: convert to hid_safe_input_report()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Llamas <[email protected]>
[ Upstream commit 63a694c51bf120a37550890b8e7736b4888985e9 ]
Commit 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()"), added a check in hid_report_raw_event() to reject reports if the received data size is smaller than expected. This was intended to prevent OOB errors by no longer allowing zeroing-out of shorter reports due to the lack of buffer size information.
However, this leads to regressions in hid_report_raw_event(), where shorter than expected reports are rejected, even though their buffers are sufficiently large to be zero-padded.
To solve this issue, Benjamin introduced a safer alternative in commit 206342541fc8 ("HID: core: introduce hid_safe_input_report()"), which forwards the buffer size and allows hid_report_raw_event() to safely zero-pad the data.
Convert uhid to use hid_safe_input_report() and pass UHID_DATA_MAX as the buffer size. This prevents the reported regressions [1], allowing hid core to zero-pad the shorter reports safely as expected.
--- drivers/hid/uhid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/hid/uhid.c +4 -4
@@ -597,8 +597,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)if (!READ_ONCE (uhid->running))return -EINVAL ; -hid_input_report (uhid->hid,HID_INPUT_REPORT , ev->u.input.data, -min_t (size_t, ev->u.input.size,UHID_DATA_MAX ),0 ); +hid_safe_input_report (uhid->hid,HID_INPUT_REPORT , ev->u.input.data,UHID_DATA_MAX , +min_t (size_t, ev->u.input.size,UHID_DATA_MAX ),0 );return 0 ; }
@@ -608,8 +608,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)if (!READ_ONCE (uhid->running))return -EINVAL ; -hid_input_report (uhid->hid,HID_INPUT_REPORT , ev->u.input2.data, -min_t (size_t, ev->u.input2.size,UHID_DATA_MAX ),0 ); +hid_safe_input_report (uhid->hid,HID_INPUT_REPORT , ev->u.input2.data,UHID_DATA_MAX , +min_t (size_t, ev->u.input2.size,UHID_DATA_MAX ),0 );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 425/1887 mm/damon/core: do non-safe region walk on kdamond_apply_schemes()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <[email protected]>
[ Upstream commit 1745ccbd2907db2bdaa843e4abccde4fdaccbe5d ]
kdamond_apply_schemes() is using damon_for_each_region_safe(), which is safe for deallocation of the region inside the loop. However, the loop internal logic does not deallocate regions. Hence it is only wasting the next pointer. Also, it causes a problem.
When an address filter is applied, and there is a region that intersects with the filter, the filter splits the region on the filter boundary. The intention is to let DAMOS apply action to only filtered-in address ranges. However, it is using damon_for_each_region_safe(), which sets the next region before the execution of the iteration. Hence, the region that split and now will be next to the previous region, is simply ignored. As a result, DAMOS applies the action to target regions bit slower than expected, when the address filter is used. Shouldn't be a big problem but definitely better to be fixed. damos_skip_charged_region() was working around the issue using a double pointer hack.
Use damon_for_each_region(), which is safe for this use case. And drop the work around in damos_skip_charged_region().
--- mm/damon/core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
mm/damon/core.c +3 -4
@@ -788,8 +788,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c, sz =DAMON_MIN_REGION ; }damon_split_region_at (t, r, sz); - r =damon_next_region (r); - sz =damon_sz_region (r); +continue ; } quota->charge_target_from =NULL ; quota->charge_addr_from =0 ;
@@ -858,7 +857,7 @@ static void damos_set_effective_quota(struct damos_quota *quota)static void kdamond_apply_schemes (struct damon_ctx *c) {struct damon_target *t; -struct damon_region *r, *next_r; +struct damon_region *r;struct damos *s;damon_for_each_scheme (s, c) {
@@ -912,7 +911,7 @@ static void kdamond_apply_schemes(struct damon_ctx *c) }damon_for_each_target (t, c) { -damon_for_each_region_safe (r, next_r, t) +damon_for_each_region (r, t)damon_do_apply_schemes (c, t, r); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 426/1887 mm/damon/core: fix unconditionally skip last region
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liew Rui Yan <[email protected]>
[ Upstream commit b3723b596b548c837a766aae3553c14a7b15af2b ]
Once quota set, the charge_{target,addr}_from unconditionally skips and resets at the last region of the tracked target, so the last region can be skipped even when it has not been processed.
Example:
1. Target has 2 regions: R1 (0-100 bytes) and R2 (100-200 bytes).
2. Quota is configured to process only 100 bytes per window.
3. Window 1: Processes R1 (0-100). Quota is full. charge_{target, addr}_from is saved at (Target, 100).
4. Window 2: The loop reaches R2. Because R2 is damon_last_region(t), the old code unconditionally returns true, skipping R2 entirely and resetting the charge_{target,addr}_from.
Result: R2 is permanently skipped even though it has never been processed.
However, it is important to note that this is a very minor issue. This is because it is triggered only when the previous window saved/kept charge_{target,addr}_from, and in the next window, all regions except the last region were skipped by damos_skip_charged_region().
Fix this by only resetting the charge_{target,addr}_from when last region is reached, only skipping when it is applied or cannot split.
--- mm/damon/core.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
mm/damon/core.c +15 -10
@@ -756,6 +756,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c,unsigned long sz =damon_sz_region (r);struct timespec64 begin, end;unsigned long sz_applied =0 ; +bool skip = false;if (!s->wmarks.activated)continue ;
@@ -768,14 +769,11 @@ static void damon_do_apply_schemes(struct damon_ctx *c,if (quota->charge_target_from) {if (t != quota->charge_target_from)continue ; -if (r ==damon_last_region (t)) { - quota->charge_target_from =NULL ; - quota->charge_addr_from =0 ; -continue ; - }if (quota->charge_addr_from && - r->ar.end <= quota->charge_addr_from) -continue ; + r->ar.end <= quota->charge_addr_from) { + skip = true; + goto clean_charge_from_skip; + }if (quota->charge_addr_from && r->ar.start < quota->charge_addr_from) {
@@ -783,16 +781,23 @@ static void damon_do_apply_schemes(struct damon_ctx *c, r->ar.start, DAMON_MIN_REGION);if (!sz) {if (damon_sz_region (r) <= -DAMON_MIN_REGION ) -continue ; +DAMON_MIN_REGION ) { + skip = true; + goto clean_charge_from_skip; + } sz =DAMON_MIN_REGION ; }damon_split_region_at (t, r, sz); -continue ; + skip = true; } + } +clean_charge_from_skip: +if (r ==damon_last_region (t)) { quota->charge_target_from =NULL ; quota->charge_addr_from =0 ; } +if (skip) +continue ;if (!damos_valid_target (c, t, r, s))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 427/1887 Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit 96d006ae6445679436b945593950fd465eba7e76 ]
When hci_inquiry_complete_evt is called between le_scan_disable and le_set_scan_enable_complete and no remote name needs to be resolved, the interleaved discovery with SIMULTANEOUS quirk gets stuck in DISCOVERY_FINDING. le_set_scan_enable_complete does not check inquiry state. No one sets DISCOVERY_STOPPED in this process.
Add state check in le_set_scan_enable_complete and change state if the state is DISCOVERY_FINDING. Tested with AX201 (8087:0026) in Dell Vostro 13. Discovering disabled MGMT Event below is reported when running into the above condition.
@ MGMT Command: Start Discovery (0x0023) {0x0001} [hci0] 10885.970873
Address type: 0x07
BR/EDR
LE Public
LE Random
...
< HCI Command: LE Set Extended Scan Enable #38205 [hci0] 10886.131438
Extended scan: Enabled (0x01)
Filter duplicates: Enabled (0x01)
Duration: 0 msec (0x0000)
Period: 0.00 sec (0x0000)Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #38206 [hci0] 10886.133295
LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
Status: Success (0x00)
@ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10886.133414
Address type: 0x07
BR/EDR
LE Public
LE Random
Discovery: Enabled (0x01)
< HCI Command: Inquiry (0x01|0x0001) plen 5 #38207 [hci0] 10886.133528
Access code: 0x9e8b33 (General Inquiry)
Length: 10.24s (0x08)
Num responses: 0Quoted 1 line
HCI Event: Command Status (
0x0f) plen 4 #38208 [hci0] 10886.141333
Inquiry (0x01|0x0001) ncmd 2
Status: Success (0x00)
...
< HCI Command: LE Set Extended Scan Enable #38242 [hci0] 10896.381802
Extended scan: Disabled (0x00)
Filter duplicates: Disabled (0x00)
Duration: 0 msec (0x0000)
Period: 0.00 sec (0x0000)Quoted 1 line
HCI Event: Inquiry Complete (
0x01) plen 1 #38243 [hci0] 10896.383419
Status: Success (0x00)
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #38244 [hci0] 10896.394378
LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
Status: Success (0x00)
@ MGMT Event: Device Found (0x0012) plen 22 {0x0001} [hci0] 10896.394497
LE Address: 88:12:AC:92:43:69
RSSI: -101 dBm (0x9b)
Flags: 0x00000004
Not Connectable
Data length: 8
Company: Xiaomi Inc. (911)
Data[0]:
16-bit Service UUIDs (complete): 1 entry
Xiaomi Inc. (0xfdaa)
@ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10896.394506
Address type: 0x07
BR/EDR
LE Public
LE Random
Discovery: Disabled (0x00)[ Iaroslav: test the quirk with test_bit() on hdev->quirks, as
this branch does elsewhere; hci_test_quirk() does not exist here ]
--- net/bluetooth/hci_event.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/bluetooth/hci_event.c +7 -0
@@ -1748,6 +1748,13 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)hci_dev_clear_flag (hdev,HCI_LE_SCAN ); +if (hdev->discovery.type ==DISCOV_TYPE_INTERLEAVED && +test_bit (HCI_QUIRK_SIMULTANEOUS_DISCOVERY , &hdev->quirks) && + !test_bit (HCI_INQUIRY , &hdev->flags) && + hdev->discovery.state ==DISCOVERY_FINDING ) { +hci_discovery_set_state (hdev,DISCOVERY_STOPPED ); + } +/* The HCI_LE_SCAN_INTERRUPTED flag indicates that we * interrupted scanning due to a connect request. Mark * therefore discovery as stopped.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 428/1887 netfilter: nft_set_pipapo: restore cloned mapping table memcg accounting
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
The 6.1.y backport of commit 69e687cea79f
("netfilter: nf_tables: missing objects with no memcg accounting") changed the pipapo_clone() mapping-table allocation to GFP_KERNEL_ACCOUNT.
The later stable backport of commit 07ace0bbe03b ("netfilter:nft_set_pipapo: do not rely on ZERO_SIZE_PTR") rewrote this allocation and changed the flag back to GFP_KERNEL. Upstream applied the ZERO_SIZE_PTR change before the memcg accounting change and retains GFP_KERNEL_ACCOUNT after both.
nft_pipapo_deactivate() clones a populated set before looking up an element to delete. If the element is absent, priv->dirty remains false and the clone is retained. Its mapping tables therefore remain allocated without being charged to the requesting memory cgroup.
Restore GFP_KERNEL_ACCOUNT for the cloned mapping table.
--- net/netfilter/nft_set_pipapo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nft_set_pipapo.c +1 -1
@@ -1466,7 +1466,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) goto out_mt; dst->mt =kvmalloc_array (src->rules,sizeof (*src->mt), -GFP_KERNEL ); +GFP_KERNEL_ACCOUNT );if (!dst->mt) goto out_mt;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 429/1887 crypto: drbg - Fix ineffective sanity check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 040ad83b0e8aa065fd2fc641cacba8491a8b186d upstream.
Fix drbg_healthcheck_sanity() to correctly check the return value of drbg_generate(). drbg_generate() returns 0 on success, or a negative errno value on failure. drbg_healthcheck_sanity() incorrectly assumed that it returned a positive value on success.
This didn't make the sanity check fail, but it made it ineffective.
--- crypto/drbg.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
crypto/drbg.c +5 -6
@@ -2001,7 +2001,6 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,*/ static inline int __init drbg_healthcheck_sanity (void ) { -int len =0 ;#define OUTBUFLEN 16unsigned char buf[OUTBUFLEN ];struct drbg_state *drbg =NULL ;
@@ -2043,12 +2042,12 @@ static inline int __init drbg_healthcheck_sanity(void) max_addtllen =drbg_max_addtl (drbg); max_request_bytes =drbg_max_request_bytes (drbg);drbg_string_fill (&addtl, buf, max_addtllen +1 ); -/* overflow addtllen with additonal info string */ - len =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); -BUG_ON (0 < len); +/* overflow addtllen with additional info string */ + ret =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); +BUG_ON (ret ==0 );/* overflow max_bits */ - len =drbg_generate (drbg, buf, (max_request_bytes +1 ),NULL ); -BUG_ON (0 < len); + ret =drbg_generate (drbg, buf, max_request_bytes +1 ,NULL ); +BUG_ON (ret ==0 );/* overflow max addtllen with personalization string */ ret =drbg_seed (drbg, &addtl, false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 430/1887 ipv4: stop PMTU walk when nexthop group shrinks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit 6619e01855e65ef35723685a557e3eb106f4ecf5 upstream.
Commit 7d3f3b4367f3 ("net: ipv4: Cache pmtu for all packet paths if multipath enabled") made __ip_rt_update_pmtu() update every path.
For nexthop objects, fib_info_num_path() and fib_info_nhc() independently load nh->nh_grp. RCU protects each group's lifetime but does not make the loads observe the same group. If replacement shrinks the group after the loop accepts an index, fib_info_nhc() returns NULL and update_or_create_fnhe() dereferences it.
A deterministic probe only widened the existing window between the real operations. On v7.2, an RTM_NEWNEXTHOP replacement published a one-member group after the PMTU reader accepted index 1 from a two-member group, producing:
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: update_or_create_fnhe+0x45/0x15b0
Stop when the indexed path is absent. Groups are dense, so no later index exists in that snapshot. The same real-writer window completed 114,423 PMTU iterations without an oops with this check. A reproducer is available on request.
Replacement requires CAP_NET_ADMIN in the network namespace. Where unprivileged user namespaces are permitted, a local user can obtain it in a new user and network namespace.
--- net/ipv4/route.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv4/route.c +2 -0
@@ -1089,6 +1089,8 @@ static void __ip_rt_update_pmtu(struct rfor (nhsel =0 ; nhsel <fib_info_num_path (res.fi); nhsel++) { nhc =fib_info_nhc (res.fi, nhsel); +if (!nhc) +break ;update_or_create_fnhe (nhc, fl4->daddr,0 , mtu, lock, jiffies + net->ipv4.ip_rt_mtu_expires); }
Greg Kroah-Hartman
maintainerPATCH 431/1887 ipv4: stop route notification sizing when nexthop group shrinks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit d3daa33c7af92e38f2274bbd2576f58bfbaf89e6 upstream.
Commit 680aea08e78c ("net: ipv4: Emit notification when fib hardware flags are changed") added an RCU-only fib_nlmsg_size() call for asynchronous hardware flag notifications.
fib_nlmsg_size() checks fib_info_num_path() before each iteration, then fib_info_nhc() independently reloads nh->nh_grp. If RTM_NEWNEXTHOP replaces a group with fewer paths between those loads, fib_info_nhc() returns NULL and fib_nexthop_nlmsg_size() dereferences it.
Stop sizing when the indexed path is absent. Nexthop groups are dense, so the current snapshot has no later path.
--- net/ipv4/fib_semantics.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/fib_semantics.c +3 -0
@@ -514,6 +514,9 @@ size_t fib_nlmsg_size(struct fib_info *fstruct fib_nh_common *nhc =fib_info_nhc (fi, i);size_t nhsize; +if (!nhc) +break ; + nhsize =fib_nexthop_nlmsg_size (nhc, nhs !=1 );if (nhs !=1 )
Greg Kroah-Hartman
maintainerPATCH 432/1887 ipv4: do not warn on route notification size race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit e02a5b6588161673ef75a4bc5cdfb62bd493374d upstream.
Commit 680aea08e78c ("net: ipv4: Emit notification when fib hardware flags are changed") added asynchronous route notifications for hardware flag changes.
fib_alias_hw_flags_set() sizes the skb with fib_nlmsg_size() and later fills it with fib_dump_info() while holding only RCU. With nexthop compatibility mode enabled, a concurrent replacement can grow the group between these independent snapshots. fib_dump_info() can then legitimately return -EMSGSIZE, so the warning does not prove a sizing bug.
Remove the warning. The existing error path still frees the skb and reports the error to listeners.
--- net/ipv4/fib_trie.c | 2 -- 1 file changed, 2 deletions(-)
net/ipv4/fib_trie.c +0 -2
@@ -1084,8 +1084,6 @@ void fib_alias_hw_flags_set(struct net * err =fib_dump_info (skb,0 ,0 ,RTM_NEWROUTE , fri,0 );if (err <0 ) { -/* -EMSGSIZE implies BUG in fib_nlmsg_size() */ -WARN_ON (err == -EMSGSIZE );kfree_skb (skb); goto errout; }
Greg Kroah-Hartman
maintainerPATCH 433/1887 ipv6: do not warn on route notification size race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit c97426ec649d99596d8969e1a052c16b14b7b485 upstream.
fib6_info_hw_flags_set() sizes the skb with rt6_nlmsg_size() and later fills it with rt6_fill_node(). With nexthop compatibility mode enabled, a concurrent replacement can grow the group between these independent snapshots. rt6_fill_node() can then legitimately return -EMSGSIZE, so the warning does not prove a sizing bug.
Remove the warning. The existing error path still frees the skb and reports the error to listeners.
--- net/ipv6/route.c | 2 -- 1 file changed, 2 deletions(-)
net/ipv6/route.c +0 -2
@@ -6333,8 +6333,6 @@ void fib6_info_hw_flags_set(struct net * err =rt6_fill_node (net, skb, f6i,NULL ,NULL ,NULL ,0 ,RTM_NEWROUTE ,0 ,0 ,0 );if (err <0 ) { -/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ -WARN_ON (err == -EMSGSIZE );kfree_skb (skb); goto errout; }
Greg Kroah-Hartman
maintainerPATCH 434/1887 arm64: irq: exclude the softirq stack switch from KCOV
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit a9cd14bfb0c113f1cd77be4349784663bec71bb4 upstream.
On IRQ exit, __irq_exit_rcu() drops HARDIRQ_OFFSET before calling invoke_softirq(). The arm64 do_softirq_own_stack() wrapper and its ____do_softirq() trampoline run before __do_softirq() establishes softirq context, so KCOV records their PCs in the interrupted task's coverage buffer. They also run outside softirq accounting when local_bh_enable() reaches do_softirq().
The IRQ-exit coverage makes the KCOV boot selftest fail even after the scheduler and timer coverage leaks are suppressed. The generic softirq.o is already excluded from KCOV, but that exclusion does not cover the separately compiled arm64 wrappers.
Exclude irq.o from KCOV instrumentation, as is already done for the arm64 entry code. This covers both wrappers even with compilers that lack the no_sanitize_coverage attribute. The softirq action functions remain instrumented for explicit remote coverage.
--- arch/arm64/kernel/Makefile | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kernel/Makefile +3 -0
@@ -25,6 +25,9 @@ KASAN_SANITIZE_stacktrace.o := n KCOV_INSTRUMENT_entry-common.o := n KCOV_INSTRUMENT_idle.o := n +# Softirq stack switching can run outside interrupt context. +KCOV_INSTRUMENT_irq.o := n + # Object file lists. obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ entry-common.o entry-fpsimd.o process.o ptrace.o \
Greg Kroah-Hartman
maintainerPATCH 435/1887 ASoC: amd: yc: Add DMI quirk for Acer Aspire Go 15 (AG15-21P)
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Garland <[email protected]>
commit d0cb7a7b2a490c381ad97f53155d02a748b60dea upstream.
The Acer Aspire Go 15 (AG15-21P, board MDC Herbag2_MDU) has two PDM DMICs connected to the ACP. The BIOS does not set the AcpDmicConnected _DSD property, so the acp6x machine driver never registers the DMIC card. The existing Herbag_MDU entry does not match this board name, so add a DMI quirk for it.
Tested on BIOS V1.11: the acp6x DMIC capture device is registered and records audio on both channels.
--- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+)
sound/soc/amd/yc/acp6x-mach.c +7 -0
@@ -608,6 +608,13 @@ static const struct dmi_system_id yc_acp { .driver_data = &acp6x_card, .matches = { +DMI_MATCH (DMI_BOARD_VENDOR ,"MDC" ), + DMI_MATCH(DMI_BOARD_NAME, "Herbag2_MDU"), + } + }, + { + .driver_data = &acp6x_card, + .matches = {DMI_MATCH (DMI_BOARD_VENDOR ,"Micro-Star International Co., Ltd." ), DMI_MATCH(DMI_PRODUCT_NAME, "Thin A15 B7VE"), }
Greg Kroah-Hartman
maintainerPATCH 436/1887 btrfs: scrub: fix local_root reference leak in scrub_print_warning_inode()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 1fd742c7479961da6d0bb794ef8ac6b7b9442847 upstream.
When paths_from_inode() fails, scrub_print_warning_inode() jumps to err without dropping the reference taken by btrfs_get_fs_root(), leaking a reference to the root every time path resolution fails while printing scrub warnings. Every other error and success path of the function drops the reference.
Drop the reference on the paths_from_inode() failure path too.
--- fs/btrfs/scrub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/btrfs/scrub.c +3 -1
@@ -851,8 +851,10 @@ static int scrub_print_warning_inode(u64 } ret =paths_from_inode (inum, ipath); -if (ret <0 ) +if (ret <0 ) { +btrfs_put_root (local_root); goto err; + }/* * we deliberately ignore the bit ipath might have been too small to
Greg Kroah-Hartman
maintainerPATCH 437/1887 dm ioctl: dont let data_start run past the buffer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Palla Raghunath <[email protected]>
commit 9b3fcf519d370df94a56f3b272d9eddffffa5be8 upstream.
struct dm_ioctl has seven bytes of trailing padding, so the smallest buffer userspace is allowed to ask for, offsetof(struct dm_ioctl, data), is seven bytes shorter than sizeof(struct dm_ioctl).
get_result_buffer() sets data_start to sizeof(struct dm_ioctl) without looking at how big the buffer actually is. Ask for the minimum and data_start ends up seven bytes past the end. Callers add it to data_size, and ctl_ioctl() copies that much back to userspace:
BUG: KASAN: slab-out-of-bounds in _copy_to_user+0xad/0xd0 Read of size 312 at addr ffff8880169e4c00 by task repro-dm/140 ctl_ioctl+0x5e3/0xcb0 dm_ctl_ioctl+0x25/0x40 allocated 305-byte region [ffff8880169e4c00, ffff8880169e4d31)
A DM_LIST_DEVICES with data_size set to 305 is enough to hit it, and the seven bytes that leak are whatever sat next to the allocation.
Clamp data_start to the buffer size.
Note that this is not a security bug because the out-of-bounds read can only be triggered by root.
--- drivers/md/dm-ioctl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/md/dm-ioctl.c +8 -2
@@ -545,10 +545,16 @@ static void *get_result_buffer(struct dm { param->data_start =align_ptr (param +1 ) - (void *) param; -if (param->data_start < param_size) +if (param->data_start < param_size) { *len = param_size - param->data_start; -else + }else { +/* +* The buffer can be as small as offsetof(*param, data), which +* is less than sizeof(*param), so don't run off the end of it. +*/ *len =0 ; + param->data_start = param_size; + }return ((void *) param) + param->data_start; }
Greg Kroah-Hartman
maintainerPATCH 438/1887 wifi: brcmfmac: fix P2P device removal race in brcmf_detach()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michele Dionisio <[email protected]>
commit 08a3f02fea636e97a7422d1512f76dacdb5b0887 upstream.
When the driver is removed while the user space process that created the P2P device (e.g. wpa_supplicant) is still exiting, the P2P device interface is removed twice and the kernel crashes.
The two paths are:
- wpa_supplicant, on exit, sends NL80211_CMD_DEL_INTERFACE for the P2P device. nl80211_del_interface() holds RTNL and the wiphy mutex and calls brcmf_p2p_del_vif(), which disables discovery and waits up to 1.5 s for BRCMF_E_IF_DEL. Then it calls brcmf_remove_interface(), which unregisters the wdev and frees the vif and the ifp.
- brcmf_detach() sets the bus down, so BRCMF_E_IF_DEL never arrives, and calls brcmf_remove_interface(ifp, false) for the same ifp. brcmf_p2p_ifp_removed() reads ifp->vif and then blocks on rtnl_lock(). When brcmf_p2p_del_vif() releases RTNL, it calls cfg80211_unregister_wdev() on the wdev that was already unregistered and freed.
The second list_del_rcu() of wdev->list faults on LIST_POISON2:
brcmfmac: brcmf_p2p_del_vif delete P2P vif
brcmfmac: brcmf_p2p_deinit_discovery enter
brcmfmac: brcmf_p2p_del_vif P2P: GO_NEG_PHASE status cleared
brcmfmac: brcmf_detach Enter
brcmfmac: brcmf_bus_change_state 1 -> 0
brcmfmac: brcmf_remove_interface Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_del_if Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_p2p_ifp_removed P2P: device interface removed [1.5 s later, brcmf_p2p_del_vif() timed out]
brcmfmac: brcmf_remove_interface Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_del_if Enter, bsscfgidx=1, ifidx=0
brcmfmac: brcmf_p2p_ifp_removed P2P: device interface removed
Unable to handle kernel paging request at virtual address dead000000000122 Internal error: Oops: 96000044 [#1] PREEMPT_RT SMP pc : _cfg80211_unregister_wdev+0x6c/0x264 [cfg80211] Call trace: _cfg80211_unregister_wdev+0x6c/0x264 [cfg80211] cfg80211_unregister_wdev+0x10/0x1c [cfg80211] brcmf_p2p_ifp_removed+0x84/0xb0 [brcmfmac] brcmf_remove_interface+0x1f4/0x254 [brcmfmac] brcmf_detach+0x88/0x180 [brcmfmac] brcmf_sdio_remove+0x90/0x7b0 [brcmfmac] brcmf_sdiod_remove+0x20/0xa0 [brcmfmac] brcmf_ops_sdio_remove+0xbc/0x12c [brcmfmac] sdio_bus_remove+0x38/0x144 device_release_driver_internal+0x1e8/0x2c0 device_release_driver+0x14/0x20 brcmf_sdio_bus_remove+0x2c/0x40 [brcmfmac] brcmf_fwvid_unregister_vendor+0xd8/0x170 [brcmfmac] __exit_compat+0x18/0x418 [brcmfmac_cyw] __arm64_sys_delete_module+0x1ac/0x244
The log was taken with debug=0x406 on an i.MX 8M Plus board with a CYW55513 (Sona IF513) on SDIO. The driver is the Ezurio backport of brcmfmac from v6.18.22 on a 5.4-rt kernel. The code involved is the same in mainline.
To reproduce:
1. Start wpa_supplicant on wlan0 and let it associate. It creates the P2P device (iw dev shows "type P2P-device").
2. Stop wpa_supplicant and remove the driver without waiting for wpa_supplicant to exit:
kill $(pidof wpa_supplicant)
rmmod brcmfmac_cyw brcmfmac
The crash is reproducible on that board.
For the interface without a netdev (the P2P device), take RTNL and the wiphy mutex in brcmf_detach() before reading iflist, and remove it with locked=true. If brcmf_p2p_del_vif() runs first, brcmf_detach() finds the slot empty. If brcmf_detach() runs first, nl80211 does not find the wdev any more. The interfaces with a netdev are removed as before, because brcmf_del_if() takes RTNL on its own for the primary interface.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 27 ++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +25 -2
@@ -1471,8 +1471,31 @@ void brcmf_detach(struct device *dev)brcmf_bus_change_state (bus_if,BRCMF_BUS_DOWN );/* make sure primary interface removed last */ for (i =BRCMF_MAX_IFS -1 ; i >-1 ; i--) { -if (drvr->iflist[i]) -brcmf_remove_interface (drvr->iflist[i], false); +struct brcmf_if *ifp = drvr->iflist[i]; + +if (!ifp) +continue ; + +if (ifp->ndev) { +brcmf_remove_interface (ifp, false); +continue ; + } + +/* The P2P device interface has no netdev. Its removal can +* race with NL80211_CMD_DEL_INTERFACE issued by a user space +* process that is exiting (e.g. wpa_supplicant), which ends +* in brcmf_p2p_del_vif() under RTNL and the wiphy mutex. If +* both paths remove the interface, the wdev is unregistered +* twice and the vif is used after being freed. Take the same +* locks and re-read iflist, so only one path removes it. +*/ +rtnl_lock (); +wiphy_lock (drvr->wiphy); + ifp = drvr->iflist[i]; +if (ifp) +brcmf_remove_interface (ifp, true); +wiphy_unlock (drvr->wiphy); +rtnl_unlock (); }brcmf_bus_stop (drvr->bus_if);
Greg Kroah-Hartman
maintainerPATCH 439/1887 wireguard: noise: reject response consumption after intermediate initiation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason A. Donenfeld <[email protected]>
commit d0305f8d90029556260c6824b61c493c424eba9e upstream.
Two threads begin processing the identical response message, received twice. The first thread, A, runs. While it's running, the second one, B, gets partway through, and during that slow calculation, or even while blocking on down_write(), A completes and then also a handshake initiation that's already been queued up runs in thread C, which itself takes that same down_write(). The handshake initiation creation succeeds, and sets the state back to waiting-for-response, and calls up_write(), at which point thread B resumes, because either its finished its calculations or was finally allowed to acquire down_write(). Thread B then copies the state back to the peer, and begins a new session, using that state, which is the same session as the one made in thread A.
Thread A Thread B Thread C
down_read()
sA = handshake->state
memcpy(cA, handshake->crypto)up_read()
if (sA != 1)
goto failslow_crypto(cA)
down_read() sB = handshake->state memcpy(cB, handshake->crypto) up_read() if (sB != 1) goto fail slow_crypto(cB)
down_write()
if (sA != handshake->state)
goto fail
memcpy(handshake->crypto, cA)
handshake->state = 2up_write()down_write()
if (handshake->state != 2)
goto fail
derive_session(handshake->crypto)up_write()
down_write() slow_crypto(handshake->crypto) handshake->state = 1 up_write() down_write() if (sB != handshake->state) goto fail memcpy(handshake->crypto, cB) handshake->state = 2 up_write() down_write() if (handshake->state != 2) goto fail derive_session(handshake->crypto) up_write()
This seems basically impossible to hit in a meaningful way in practice, but ensure that it absolutely cannot happen by comparing the ephemeral private key that's on the stack with the latest one that the peer's handshake state has.
--- drivers/net/wireguard/noise.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/wireguard/noise.c +4 -3
@@ -784,10 +784,11 @@ wg_noise_handshake_consume_response(stru/* Success! Copy everything to peer */ down_write (&handshake->lock); -/* It's important to check that the state is still the same, while we -* have an exclusive lock. +/* Check that the state is the same and that this is still the +* initiation we started with, while we have an exclusive lock. */ -if (handshake->state != state) { +if (handshake->state != state || +crypto_memneq (handshake->ephemeral_private, ephemeral_private,NOISE_PUBLIC_KEY_LEN )) {up_write (&handshake->lock); goto fail; }
Greg Kroah-Hartman
maintainerPATCH 440/1887 workqueue: Fix NULL current_pwq deref in chained work check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavankumar Kondeti <[email protected]>
commit 980db94e3eeefdd8a1c46f86412c33a7f7806f51 upstream.
current_wq_worker() only tells us that %current is a kworker. It does not guarantee that the worker is currently executing a work item, as worker->current_pwq is populated only while process_one_work() is running the work function.
is_chained_work() can be reached while queueing on a draining or destroying workqueue. If a kworker outside work-item execution reaches that path, current_wq_worker() returns a worker but worker->current_pwq is NULL, and the chained-work test can fault before it emits the intended warning.
Guard the chained-work test with worker->current_pwq. A kworker without current_pwq is not executing work on the target workqueue, so the helper should return false and let the draining/destroying warning fire.
--- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/workqueue.c +1 -1
@@ -1382,7 +1382,7 @@ static bool is_chained_work(struct workq* Return %true iff I'm a worker executing a work item on @wq. If * I'm @worker, it's safe to dereference it without locking. */ -return worker && worker->current_pwq->wq == wq; +return worker && worker->current_pwq && worker->current_pwq->wq == wq; }/*
Greg Kroah-Hartman
maintainerPATCH 441/1887 xen/netfront: dont leak the skb when xennet_fill_frags() fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik <[email protected]>
commit 93ccaf1c26e2133396173b76a071e59024daa622 upstream.
When a response chain has more slots than fit in the skb's frags, xennet_fill_frags() returns an error and xennet_poll() jumps to its error path. That path moves what's left on tmpq to errq to be freed, but the skb being filled was already dequeued from tmpq, so it's never freed. Each chain that overflows leaks the skb and the pages attached to it as frags, and the backend decides how many slots it sends.
Put the skb back on tmpq before taking the error path, like the xennet_set_skb_gso() failure just above it does.
--- drivers/net/xen-netfront.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/xen-netfront.c +3 -1
@@ -1345,8 +1345,10 @@ err: skb->data_len = rx->status; skb->len += rx->status; -if (unlikely (xennet_fill_frags (queue, skb, &tmpq))) +if (unlikely (xennet_fill_frags (queue, skb, &tmpq))) { +__skb_queue_head (&tmpq, skb); goto err; + }if (rx->flags & XEN_NETRXF_csum_blank) skb->ip_summed =CHECKSUM_PARTIAL ;
Greg Kroah-Hartman
maintainerPATCH 442/1887 strparser: make sure __strp_recv isnt running before tearing down the parser
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
commit 0984ebc631792acf8fff105112ee74a6b8f1efcc upstream.
The comment above strp_done() claims that if strp is stopped, strp_recv will no longer be called. That's only true if the caller has a mechanism (eg locking) to guarantee that strp_recv() calls that started before strp_stop() have completed by the time we call strp_done().
This adds a dummy lock_sock/release_sock pair to guarantee that any in-flight strp_recv() (which runs under either bh_lock_sock or lock_sock, depending if it's called from ->sk_data_ready or strp_work) has completed.
Only espintcp can be affected by this race condition, but this patch makes sure no future user of strp can have the bug.
This could crash on strp->sk ("general mode" of strp), but this mode has been here for 9 years and has never been used. It'll be gone soon, no point worrying about it.
Switch the stopped/paused/etc bits to u8's to avoid races between strp_stop() and strp_pause/unpause().
A reproducer has been published and turns the possible UAF into an exploit [1].
--- Documentation/networking/strparser.rst | 2 +- include/net/strparser.h | 10 +++++----- net/strparser/strparser.c | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-)
Documentation/networking/strparser.rst +1 -1
@@ -77,7 +77,7 @@ Functions strp_done is called to release any resources held by the stream parser instance. This must be called after the stream processor - has been stopped. + has been stopped. The socket lock must not be held. ::
include/net/strparser.h +5 -5
@@ -91,11 +91,11 @@ static inline struct strp_msg *strp_msg(struct strparser {struct sock *sk; -u32 stopped :1 ; -u32 paused :1 ; -u32 aborted :1 ; -u32 interrupted :1 ; -u32 unrecov_intr :1 ; +u8 stopped; +u8 paused; +u8 aborted; +u8 interrupted; +u8 unrecov_intr;struct sk_buff **skb_nextp;struct sk_buff *skb_head;
net/strparser/strparser.c +5 -1
@@ -518,12 +518,16 @@ void strp_unpause(struct strparser *strpEXPORT_SYMBOL_GPL (strp_unpause);/* strp must already be stopped so that strp_recv will no longer be called. -* Note that strp_done is not called with the lower socket held. +* Note that strp_done must not be called with the lower socket held. */ void strp_done (struct strparser *strp) {WARN_ON (!strp->stopped); +lock_sock (strp->sk); +/* sync with pending strp_recv */ +release_sock (strp->sk); +cancel_delayed_work_sync (&strp->msg_timer_work);cancel_work_sync (&strp->work);
Greg Kroah-Hartman
maintainerPATCH 443/1887 tipc: destroy topsrv workqueues before closing connections
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
commit 3acdd44385bc7e2e57605e073691ce69cc5a960d upstream.
tipc_topsrv_stop() closed subscriber connections while the topology server's send and receive workqueues were still running. Socket callbacks and subscription events could then queue more work, and in-flight send/recv work could drop the last connection reference during the conn_idr walk.
That race produced several teardown failures: refcount_t addition on 0 from conn_get() on a connection whose release was blocked on idr_lock, a subsequent use-after-free in tipc_conn_close(), queue_work() on an already destroyed workqueue from the listener data-ready callback, and an RCU stall in tipc_topsrv_exit_net() while the walk spun under idr_lock.
Clear srv->listener under idr_lock so it acts as a shutdown flag, skip queue_work() once it is NULL, destroy the workqueues to flush in-flight work, and only then close the remaining connections. Refuse tipc_conn_lookup() after that flag is cleared, and drop idr_lock when the teardown walk finds no connection, so an in-flight subscription event cannot pin idr_in_use while the walk holds the lock.
v3 supersedes the narrower in-thread diff Tung Quang Nguyen posted on 2026-09-23. It keeps his teardown order and adds the lookup refusal and the empty-idr unlock.
--- net/tipc/topsrv.c | 80 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 15 deletions(-)
net/tipc/topsrv.c +65 -15
@@ -54,7 +54,7 @@/** * struct tipc_topsrv - TIPC server structure * @conn_idr: identifier set of connection -* @idr_lock: protect the connection identifier set +* @idr_lock: protect the connection identifier set and listener * @idr_in_use: amount of allocated identifier entry * @net: network namspace instance * @awork: accept work item
@@ -217,6 +217,10 @@ static struct tipc_conn *tipc_conn_lookustruct tipc_conn *con;spin_lock_bh (&s->idr_lock); +if (!s->listener) { +spin_unlock_bh (&s->idr_lock); +return NULL ; + } con =idr_find (&s->conn_idr, conid);if (!connected (con) || !kref_get_unless_zero (&con->kref)) con =NULL ;
@@ -300,10 +304,20 @@ static void tipc_conn_send_to_sock(strucstatic void tipc_conn_send_work (struct work_struct *work) { struct tipc_conn *con = container_of(work, struct tipc_conn, swork); +struct tipc_topsrv *srv; + + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (!srv->listener) { +spin_unlock_bh (&srv->idr_lock); + goto out; + } +spin_unlock_bh (&srv->idr_lock);if (connected (con))tipc_conn_send_to_sock (con); +out:conn_put (con); }
@@ -333,8 +347,14 @@ void tipc_topsrv_queue_evt(struct net *nlist_add_tail (&e->list, &con->outqueue);spin_unlock_bh (&con->outqueue_lock); -if (queue_work (srv->send_wq, &con->swork)) -return ; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +if (queue_work (srv->send_wq, &con->swork)) { +spin_unlock_bh (&srv->idr_lock); +return ; + } + } +spin_unlock_bh (&srv->idr_lock); err:conn_put (con); }
@@ -345,14 +365,20 @@ err:*/ static void tipc_conn_write_space (struct sock *sk) { +struct tipc_topsrv *srv;struct tipc_conn *con;read_lock_bh (&sk->sk_callback_lock); con = sk->sk_user_data;if (connected (con)) { -conn_get (con); -if (!queue_work (con->server->send_wq, &con->swork)) -conn_put (con); + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +conn_get (con); +if (!queue_work (srv->send_wq, &con->swork)) +conn_put (con); + } +spin_unlock_bh (&srv->idr_lock); }read_unlock_bh (&sk->sk_callback_lock); }
@@ -417,8 +443,17 @@ static int tipc_conn_rcv_from_sock(strucstatic void tipc_conn_recv_work (struct work_struct *work) { struct tipc_conn *con = container_of(work, struct tipc_conn, rwork); +struct tipc_topsrv *srv;int count =0 ; + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (!srv->listener) { +spin_unlock_bh (&srv->idr_lock); + goto out; + } +spin_unlock_bh (&srv->idr_lock); +while (connected (con)) {if (tipc_conn_rcv_from_sock (con))break ;
@@ -429,6 +464,7 @@ static void tipc_conn_recv_work(struct w count =0 ; } } +out:conn_put (con); }
@@ -437,14 +473,20 @@ static void tipc_conn_recv_work(struct w*/ static void tipc_conn_data_ready (struct sock *sk) { +struct tipc_topsrv *srv;struct tipc_conn *con;read_lock_bh (&sk->sk_callback_lock); con = sk->sk_user_data;if (connected (con)) { -conn_get (con); -if (!queue_work (con->server->rcv_wq, &con->rwork)) -conn_put (con); + srv = con->server; +spin_lock_bh (&srv->idr_lock); +if (srv->listener) { +conn_get (con); +if (!queue_work (srv->rcv_wq, &con->rwork)) +conn_put (con); + } +spin_unlock_bh (&srv->idr_lock); }read_unlock_bh (&sk->sk_callback_lock); }
@@ -498,8 +540,12 @@ static void tipc_topsrv_listener_data_reread_lock_bh (&sk->sk_callback_lock); srv = sk->sk_user_data; -if (srv) -queue_work (srv->rcv_wq, &srv->awork); +if (srv) { +spin_lock_bh (&srv->idr_lock); +if (srv->listener) +queue_work (srv->rcv_wq, &srv->awork); +spin_unlock_bh (&srv->idr_lock); + }read_unlock_bh (&sk->sk_callback_lock); }
@@ -696,22 +742,26 @@ static void tipc_topsrv_stop(struct netint id;spin_lock_bh (&srv->idr_lock); + srv->listener =NULL ; +spin_unlock_bh (&srv->idr_lock); +tipc_topsrv_work_stop (srv); + +spin_lock_bh (&srv->idr_lock);for (id =0 ; srv->idr_in_use; id++) { con =idr_find (&srv->conn_idr, id);if (con) { -conn_get (con);spin_unlock_bh (&srv->idr_lock);tipc_conn_close (con); -conn_put (con);spin_lock_bh (&srv->idr_lock); +continue ; } +spin_unlock_bh (&srv->idr_lock); +spin_lock_bh (&srv->idr_lock); }__module_get (lsock->ops->owner);__module_get (lsock->sk->sk_prot_creator->owner); - srv->listener =NULL ;spin_unlock_bh (&srv->idr_lock); -tipc_topsrv_work_stop (srv);sock_release (lsock);idr_destroy (&srv->conn_idr);kfree (srv);
Greg Kroah-Hartman
maintainerPATCH 444/1887 tipc: hold a reference to nodes found by link name
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 17e73bae400f6a434dc006e3bee92c94cf781954 upstream.
tipc_node_find_by_name() returns a node after dropping its RCU read lock without taking a reference. The LINK_SET, LINK_GET and LINK_RESET_STATS handlers then lock and access the node, racing with timer-driven cleanup of a down peer. Generic netlink serialization does not exclude the node timer.
The following interleaving can leave a handler using a freed node:
CPU 0: find the node under RCU and release the node read lock CPU 1: tipc_node_timeout() clears the links and unlinks the down node CPU 1: drop the list and timer references, queuing tipc_node_free() CPU 0: leave the RCU read-side critical section
CPU 1: complete the grace period and free the node
CPU 0: acquire the node lock through the stale pointer
LINK_SET also uses the node's media address after releasing the node lock, when passing queued packets to tipc_bearer_xmit().
KASAN on v7.3-rc5 reported:
BUG: KASAN: slab-use-after-free in _raw_read_lock_bh Write of size 4 at addr ffff88807e06f008 by task poc/92 Call Trace: _raw_read_lock_bh kernel/locking/spinlock.c:287 tipc_nl_node_set_link net/tipc/node.c:2475 genl_family_rcv_msg_doit net/netlink/genetlink.c:1114 genl_rcv_msg net/netlink/genetlink.c:1209 netlink_rcv_skb net/netlink/af_netlink.c:2575 Allocated by task 0: tipc_node_create net/tipc/node.c:539 tipc_node_check_dest net/tipc/node.c:1196 tipc_disc_rcv net/tipc/discover.c:252 Freed by task 92: kfree mm/slub.c:6801 rcu_core kernel/rcu/tree.c:2919 Last potentially related work creation: __call_rcu_common.constprop.0 kernel/rcu/tree.c:3181 tipc_node_timeout net/tipc/node.c:814
Acquire a reference to the selected node with kref_get_unless_zero() before leaving RCU, returning NULL if the node has already been released. Release that reference on every caller exit after the last node access, including transmission in LINK_SET. Keep the existing link lookup order and locking so concurrent link removal still takes the existing error paths.
--- net/tipc/node.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
net/tipc/node.c +9 -1
@@ -2421,8 +2421,11 @@ static struct tipc_node *tipc_node_find_ } }tipc_node_read_unlock (n); -if (found_node) +if (found_node) { +if (!kref_get_unless_zero (&found_node->kref)) + found_node =NULL ;break ; + } }rcu_read_unlock ();
@@ -2507,6 +2510,7 @@ out:tipc_node_read_unlock (node);tipc_bearer_xmit (net, bearer_id, &xmitq, &node->links[bearer_id].maddr,NULL ); +tipc_node_put (node);return res; }
@@ -2558,12 +2562,14 @@ int tipc_nl_node_get_link(struct sk_buff link = node->links[bearer_id].link;if (!link) {tipc_node_read_unlock (node); +tipc_node_put (node); err = -EINVAL ; goto err_free; } err =__tipc_nl_add_link (net, &msg, link,0 );tipc_node_read_unlock (node); +tipc_node_put (node);if (err) goto err_free; }
@@ -2634,11 +2640,13 @@ int tipc_nl_node_reset_link_stats(structif (!link) {spin_unlock_bh (&le->lock);tipc_node_read_unlock (node); +tipc_node_put (node);return -EINVAL ; }tipc_link_reset_stats (link);spin_unlock_bh (&le->lock);tipc_node_read_unlock (node); +tipc_node_put (node);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 445/1887 Revert "wifi: libertas: reject short monitor TX frames"
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <[email protected]>
commit 9727d1c4e1c971fc42b049b645fdda6852758835 upstream.
This reverts commit 13ff543e0b2c713aedeaadadde686686e949dc78.
The 'goto free' just made things worse, causing a spinlock to be handled incorrectly. Revert this for now.
--- drivers/net/wireless/marvell/libertas/tx.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/net/wireless/marvell/libertas/tx.c +0 -7
@@ -117,13 +117,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sif (priv->wdev->iftype ==NL80211_IFTYPE_MONITOR ) {struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; -if (skb->len <sizeof (*rtap_hdr) +4 +ETH_ALEN ) { -lbs_deb_tx ("tx err: short monitor frame %u\n" , skb->len); - dev->stats.tx_dropped++; - dev->stats.tx_errors++; - goto free; - } -/* set txpd fields from the radiotap header */ txpd->tx_control =cpu_to_le32 (convert_radiotap_rate_to_mv (rtap_hdr->rate));
Greg Kroah-Hartman
maintainerPATCH 446/1887 selinux: preserve NATIVE_LABELS on already-initialized sb in set_mnt_opts
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <[email protected]>
commit 28b7260548af3d35773477993ad4e4de41578dd7 upstream.
When an NFSv4 filesystem exported with security_label is mounted a second time, sget_fc() returns the existing superblock and nfs_get_root() calls security_sb_set_mnt_opts() again on it. Since the superblock is already SB_INITIALIZED, selinux_set_mnt_opts() takes an early exit without setting SECURITY_LSM_NATIVE_LABELS in *set_kern_flags. nfs_get_root() then sees kflags without SECURITY_LSM_NATIVE_LABELS set and clears NFS_CAP_SECURITY_LABEL on the shared nfs_server, silently disabling per-file labeling for both the new and the original mount.
Commit 3815a245b501 ("security/selinux: fix SECURITY_LSM_NATIVE_LABELS on reused superblock") fixed the same problem in selinux_sb_clone_mnt_opts(). The reused-superblock path for a plain second mount now goes through sb_set_mnt_opts rather than sb_clone_mnt_opts, so it needs the same treatment: on both SE_SBINITIALIZED early exits, set SECURITY_LSM_NATIVE_LABELS in *set_kern_flags when the superblock was already using SECURITY_FS_USE_NATVE.
--- security/selinux/hooks.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
security/selinux/hooks.c +8 -1
@@ -646,8 +646,12 @@ static int selinux_set_mnt_opts(struct s* will be used for both mounts) */ if ((sbsec->flags &SE_SBINITIALIZED ) && (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) - && !opts) + && !opts) { +if ((kern_flags &SECURITY_LSM_NATIVE_LABELS ) && + sbsec->behavior ==SECURITY_FS_USE_NATIVE ) + *set_kern_flags |=SECURITY_LSM_NATIVE_LABELS ; goto out; + } root_isec =backing_inode_security_novalidate (root);
@@ -691,6 +695,9 @@ static int selinux_set_mnt_opts(struct s/* previously mounted with options, but not on this attempt? */ if ((sbsec->flags &SE_MNTMASK ) && !opts) goto out_double_mount; +if ((kern_flags &SECURITY_LSM_NATIVE_LABELS ) && + sbsec->behavior ==SECURITY_FS_USE_NATIVE ) + *set_kern_flags |=SECURITY_LSM_NATIVE_LABELS ; rc =0 ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 447/1887 sctp: copy zeroed stats to user in sctp_getsockopt_pr_streamstatus() when !streamoute
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Peng <[email protected]>
commit 538b529509c7ab0d909cb65bb7264edca1788d30 upstream.
When an SCTP stream output extension structure (streamoute) has not yet been allocated, sctp_getsockopt_pr_streamstatus() sets the local stack variables params.sprstat_abandoned_unsent = 0 and params.sprstat_abandoned_sent = 0, but then immediately jumps to 'out:', bypassing copy_to_user(). As a result, when an uninitialized user buffer is passed to getsockopt(SCTP_PR_STREAM_STATUS), the kernel returns success (0) without copying the zeroed stats back to user space, leaving uninitialized data in the user buffer.
Refactor the !streamoute check into an if-else chain so that when streamoute is NULL, params is zeroed and falls through to copy_to_user(), copying the zeroed stats to user space and setting retval = 0 once before returning.
Tested in QEMU against Linux 7.3.0-rc3 using an uninitialized sctp_prstatus user struct passed to getsockopt(SCTP_PR_STREAM_STATUS) on a freshly created stream: on the unfixed kernel the user struct contains uninitialized stack garbage; whereas with this fix applied, getsockopt() copies zeroed stats into user space and returns 0.
--- net/sctp/socket.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
net/sctp/socket.c +1 -5
@@ -7520,11 +7520,7 @@ static int sctp_getsockopt_pr_streamstat/* Not allocated yet, means all stats are 0 */ params.sprstat_abandoned_unsent =0 ; params.sprstat_abandoned_sent =0 ; - retval =0 ; - goto out; - } - -if (policy ==SCTP_PR_SCTP_ALL ) { + }else if (policy ==SCTP_PR_SCTP_ALL ) { params.sprstat_abandoned_unsent =0 ; params.sprstat_abandoned_sent =0 ;for (policy =0 ; policy <=SCTP_PR_INDEX (MAX ); policy++) {
Greg Kroah-Hartman
maintainerPATCH 448/1887 gpio: xilinx: fix runtime PM leak on request error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ridham Khurana <[email protected]>
commit ff82fc3a4a1d417dee1229681cc5285986edb1fa upstream.
pm_runtime_get_sync() leaves the usage counter incremented even when it fails, and xgpio_request() returns the error without dropping it.
gpiolib does not call ->free() when ->request() fails, so xgpio_free(), which holds the only matching pm_runtime_put(), never runs. The reference is leaked and the controller can no longer runtime-suspend, so its clock stays enabled.
Switch to pm_runtime_resume_and_get(), which only increments the usage counter on success.
--- drivers/gpio/gpio-xilinx.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/gpio/gpio-xilinx.c +1 -8
@@ -292,14 +292,7 @@ static void xgpio_save_regs(struct xgpiostatic int xgpio_request (struct gpio_chip *chip,unsigned int offset) { -int ret; - - ret =pm_runtime_get_sync (chip->parent); -/* -* If the device is already active pm_runtime_get() will return 1 on -* success, but gpio_request still needs to return 0. -*/ -return ret <0 ? ret :0 ; +return pm_runtime_resume_and_get (chip->parent); }static void xgpio_free (struct gpio_chip *chip,unsigned int offset)
Greg Kroah-Hartman
maintainerPATCH 449/1887 ibmveth: h_free logical LAN on open-fail after register
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingming Cao <[email protected]>
commit af0524bf4ce1a4cbd2946aa81751582951cfcab5 upstream.
ibmveth_open() registers the logical LAN, then allocates the RX buffer pools. A pool failure jumps to out_free_buffer_pools without h_free_logical_lan(), so PHYP still owns the buffer-list page when it is unmapped. request_irq() failure already issued the hypercall before taking the same label.
Move that h_free to the shared post-register unwind so both paths deregister before the buffer list is unmapped.
--- drivers/net/ethernet/ibm/ibmveth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/ethernet/ibm/ibmveth.c +3 -4
@@ -630,10 +630,6 @@ static int ibmveth_open(struct net_devicif (rc !=0 ) {netdev_err (netdev,"unable to request irq 0x%x, rc %d\n" , netdev->irq, rc); -do { - lpar_rc =h_free_logical_lan (adapter->vdev->unit_address); - }while (H_IS_LONG_BUSY (lpar_rc) || (lpar_rc ==H_BUSY )); - goto out_free_buffer_pools; }
@@ -649,6 +645,9 @@ static int ibmveth_open(struct net_devicreturn 0 ; out_free_buffer_pools: +do { + lpar_rc =h_free_logical_lan (adapter->vdev->unit_address); + }while (H_IS_LONG_BUSY (lpar_rc) || (lpar_rc ==H_BUSY ));while (--i >=0 ) {if (adapter->rx_buff_pool[i].active) ibmveth_free_buffer_pool(adapter,
Greg Kroah-Hartman
maintainerPATCH 450/1887 ibmveth: fix TX LTB and filter unwind on open-fail
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingming Cao <[email protected]>
commit 84bec0bf035258a1073ffd6f6dc8ea61806aa7d4 upstream.
out_free_buffer_pools reuses open()'s loop index for the TX LTB walk. After the pool unwind i is -1, so the TX buffers allocated earlier are leaked. request_irq() failure has the same leak.
The TX-fail goto on that walk also skips dma_unmap of the filter list (pre-existing since the LTB was added). Rewrite the TX walk to real_num_tx_queues with a pointer check, and unmap the filter list before those frees.
--- drivers/net/ethernet/ibm/ibmveth.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/ibm/ibmveth.c +9 -6
@@ -465,10 +465,15 @@ static void ibmveth_rxq_harvest_buffer(sstatic void ibmveth_free_tx_ltb (struct ibmveth_adapter *adapter,int idx) { +void *ptr = adapter->tx_ltb_ptr[idx]; + +if (!ptr) +return ; + + adapter->tx_ltb_ptr[idx] =NULL ;dma_unmap_single (&adapter->vdev->dev, adapter->tx_ltb_dma[idx], adapter->tx_ltb_size,DMA_TO_DEVICE ); -kfree (adapter->tx_ltb_ptr[idx]); - adapter->tx_ltb_ptr[idx] =NULL ; +kfree (ptr); }static int ibmveth_allocate_tx_ltb (struct ibmveth_adapter *adapter,int idx)
@@ -579,7 +584,7 @@ static int ibmveth_open(struct net_devicfor (i =0 ; i < netdev->real_num_tx_queues; i++) {if (ibmveth_allocate_tx_ltb (adapter, i)) - goto out_free_tx_ltb; + goto out_unmap_filter_list; } adapter->rx_queue.index =0 ;
@@ -657,10 +662,8 @@ out_unmap_filter_list:dma_unmap_single (dev, adapter->filter_list_dma,4096 ,DMA_BIDIRECTIONAL ); -out_free_tx_ltb: -while (--i >=0 ) { +for (i = netdev->real_num_tx_queues -1 ; i >=0 ; i--)ibmveth_free_tx_ltb (adapter, i); - } out_unmap_buffer_list: dma_unmap_single(dev, adapter->buffer_list_dma, 4096,
Greg Kroah-Hartman
maintainerPATCH 451/1887 keys: finalize persistent keyring timeout after link attempt
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
commit 25bf14f817168079f731975b8998fc2af380f29e upstream.
When no keyring exists for the requested UID, KEYCTL_GET_PERSISTENT creates and registers one before linking it to the requested destination. The configured timeout is set only after the destination link succeeds.
A destination restricted with KEYCTL_RESTRICT_KEYRING makes that link fail with -EPERM. With persistent_keyring_expiry set to 60 seconds, /proc/keys still reports the registered keyring's expiry as "perm".
The failed call therefore leaves a quota-exempt keyring in the namespace's hidden register, where it may remain until namespace teardown.
Rename the write-locked helper to key_get_or_create_persistent() and return the key reference through a result parameter. Return 0 when it creates a keyring and 1 when the retry finds an existing one. Return a negative error on failure. Another caller may create the keyring between the initial read-locked lookup and the retry under the write lock.
Set the timeout after permission checking and linking. Do this on success, or on failure if the call allocated the keyring. This leaves a new keyring collectible after failure without starting its timeout while linking is still in progress.
--- security/keys/persistent.c | 55 ++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-)
security/keys/persistent.c +32 -23
@@ -33,25 +33,31 @@ static int key_create_persistent_registe }/* -* Create the persistent keyring for the specified user. +* Get or create the persistent keyring for the specified user. * * Called with the namespace's sem locked for writing. +* +* Returns a boolean indicating whether the keyring already existed, +* or a negative error. On success, *persistent_ref holds a reference +* to the keyring. */ -static key_ref_t key_create_persistent (struct user_namespace *ns,kuid_t uid, -struct keyring_index_key *index_key) +static int key_get_or_create_persistent (struct user_namespace *ns,kuid_t uid, +struct keyring_index_key *index_key, +key_ref_t *persistent_ref) {struct key *persistent; -key_ref_t reg_ref, persistent_ref; +key_ref_t reg_ref;if (!ns->persistent_keyring_register) { -long err =key_create_persistent_register (ns); +int err =key_create_persistent_register (ns); +if (err <0 ) -return ERR_PTR (err); +return err; }else { reg_ref =make_key_ref (ns->persistent_keyring_register, true); - persistent_ref =find_key_to_update (reg_ref, index_key); -if (persistent_ref) -return persistent_ref; + *persistent_ref =find_key_to_update (reg_ref, index_key); +if (*persistent_ref) +return 1 ; } persistent = keyring_alloc(index_key->description,
@@ -61,9 +67,10 @@ static key_ref_t key_create_persistent(sKEY_ALLOC_NOT_IN_QUOTA ,NULL , ns->persistent_keyring_register);if (IS_ERR (persistent)) -return ERR_CAST (persistent); +return PTR_ERR (persistent); -return make_key_ref (persistent, true); + *persistent_ref =make_key_ref (persistent, true); +return 0 ; }/*
@@ -78,6 +85,7 @@ static long key_get_persistent(struct uskey_ref_t reg_ref, persistent_ref;char buf[32 ];long ret; +bool created = false;/* Look in the register if it exists */ memset (&index_key,0 ,sizeof (index_key));
@@ -100,23 +108,24 @@ static long key_get_persistent(struct us* also need to create the register. */ down_write (&ns->keyring_sem); - persistent_ref =key_create_persistent (ns, uid, &index_key); + ret =key_get_or_create_persistent (ns, uid, &index_key, + &persistent_ref);up_write (&ns->keyring_sem); -if (!IS_ERR (persistent_ref)) - goto found; - -return PTR_ERR (persistent_ref); +if (ret <0 ) +return ret; + created = ret ==0 ; found: + persistent =key_ref_to_ptr (persistent_ref); ret =key_task_permission (persistent_ref,current_cred (),KEY_NEED_LINK ); -if (ret ==0 ) { - persistent =key_ref_to_ptr (persistent_ref); +if (ret ==0 ) ret =key_link (key_ref_to_ptr (dest_ref), persistent); -if (ret ==0 ) { -key_set_timeout (persistent, persistent_keyring_expiry); - ret = persistent->serial; - } - } + +if (ret ==0 || created) +key_set_timeout (persistent, persistent_keyring_expiry); + +if (ret ==0 ) + ret = persistent->serial;key_ref_put (persistent_ref);return ret;
Greg Kroah-Hartman
maintainerPATCH 452/1887 KEYS: Fix add_key() race with keyring restriction
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: 성병찬 <[email protected]>
commit dd3ea3fcba7c75493760cdbccd35f029597e8d5e upstream.
__key_create_or_update() snapshots keyring->restrict_link before taking the destination keyring's semaphore. keyring_restrict() installs a restriction while holding that semaphore.
This allows a writer to observe no restriction, wait for the keyring owner to install a reject-all restriction and return successfully, and then link a key using the stale NULL snapshot. The writer only needs write permission on the destination keyring.
Move the restrict_link read after __key_link_lock() and __key_link_begin(). The read and the subsequent restriction check are then serialized with restriction installation by keyring->sem.
The race was reproduced on v7.2.8 in 19 executions where restriction installation returned before the link completed. All 19 linked the key despite the reject-all restriction. With this change, 312 executions reached the same ordering and every add_key() call failed with -EPERM.
The issue was found by manual concurrency analysis assisted by AI-based analysis and independently verified with a QEMU reproducer and kernel instrumentation.
--- security/keys/key.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
security/keys/key.c +3 -3
@@ -845,9 +845,6 @@ key_ref_t key_create_or_update(key_ref_tkey_check (keyring); -if (!(flags &KEY_ALLOC_BYPASS_RESTRICTION )) - restrict_link = keyring->restrict_link; - key_ref =ERR_PTR (-ENOTDIR );if (keyring->type != &key_type_keyring) goto error_put_type;
@@ -885,6 +882,9 @@ key_ref_t key_create_or_update(key_ref_t goto error_link_end; } +if (!(flags &KEY_ALLOC_BYPASS_RESTRICTION )) + restrict_link = keyring->restrict_link; +if (restrict_link && restrict_link->check) { ret = restrict_link->check (keyring, index_key.type, &prep.payload, restrict_link->key);
Greg Kroah-Hartman
maintainerPATCH 453/1887 memstick: core: wait for request completion before freeing card
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raj Ojha <[email protected]>
commit aa0a37b5024d921e96ac4f8f487c8bfbf1f1a582 upstream.
In memstick_alloc_card() and memstick_set_rw_addr(), wait_for_completion_timeout() is used to wait for device identification and address configuration requests to complete.
The memstick subsystem does not provide an abort or cancellation callback in struct memstick_host for in-flight requests. If wait_for_completion_timeout() expires (for instance, when a USB transfer or command retry is delayed), memstick_alloc_card() returns an error and frees the memstick_dev structure via kfree(card).
However, the host controller driver (such as rtsx_usb_ms) is still running the request asynchronously in worker context. When the transfer eventually finishes, the driver writes into host->req->data, which points to memory inside the already freed card structure. This leads to a KASAN slab-use-after-free write:
BUG: KASAN: slab-use-after-free in ms_read_bytes+0x8fe/0x990 Write of size 1 at addr ffff88813c188079 by task kworker/1:5/5239 Workqueue: events rtsx_usb_ms_handle_req Call Trace: ms_read_bytes+0x8fe/0x990 drivers/memstick/host/rtsx_usb_ms.c:450 rtsx_usb_ms_issue_cmd drivers/memstick/host/rtsx_usb_ms.c:477 [inline] rtsx_usb_ms_handle_req+0x557/0x1a00 drivers/memstick/host/rtsx_usb_ms.c:531 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396 worker_thread+0x5ef/0xe50 kernel/workqueue.c:3560 kthread+0x373/0x450 kernel/kthread.c:436 Allocated by task 1662: memstick_alloc_card drivers/memstick/core/memstick.c:383 [inline] memstick_check+0x2c1/0x10d0 drivers/memstick/core/memstick.c:452 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396 Freed by task 1662: kfree+0x20c/0x650 mm/slub.c:6792 memstick_alloc_card drivers/memstick/core/memstick.c:420 [inline] memstick_check+0x72b/0x10d0 drivers/memstick/core/memstick.c:452 process_one_work+0xac7/0x1b10 kernel/workqueue.c:3396
Host controller drivers (rtsx_usb_ms, jmb38x_ms, tifm_ms, r592) already implement their own hardware and bus timeouts, and callers in mspro_block and ms_block already rely on wait_for_completion() unconditionally.
Replace wait_for_completion_timeout() with wait_for_completion() in memstick_set_rw_addr() and memstick_alloc_card() so that the card structure is never freed while an asynchronous request is in flight.
--- drivers/memstick/core/memstick.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/memstick/core/memstick.c +2 -6
@@ -367,9 +367,7 @@ int memstick_set_rw_addr(struct memstick { card->next_request = h_memstick_set_rw_addr;memstick_new_req (card->host); -if (!wait_for_completion_timeout (&card->mrq_complete, -msecs_to_jiffies (500 ))) - card->current_mrq.error = -ETIMEDOUT ; +wait_for_completion (&card->mrq_complete);return card->current_mrq.error; }
@@ -403,9 +401,7 @@ static struct memstick_dev *memstick_all card->next_request = h_memstick_read_dev_id;memstick_new_req (host); -if (!wait_for_completion_timeout (&card->mrq_complete, -msecs_to_jiffies (500 ))) - card->current_mrq.error = -ETIMEDOUT ; +wait_for_completion (&card->mrq_complete);if (card->current_mrq.error) goto err_out;
Greg Kroah-Hartman
maintainerPATCH 454/1887 memstick: rtsx_usb_ms: complete requests after eject instead of dropping them
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nguyen Ngoc Thang <[email protected]>
commit c96ca94425b076dc398d929366e378d1e22ec794 upstream.
memstick_check() can pass its host->removing check just before rtsx_usb_ms_drv_remove() sets eject/removing. Its next request is then silently dropped: rtsx_usb_ms_request() skips schedule_work() once eject is set, and drv_remove's cancel_work_sync() can also cancel a queued handle_req before it picks the request up. Nobody completes card->mrq_complete.
Once memstick core waits for requests without a timeout ("memstick: core:
wait for request completion before freeing card"), this hangs removal:memstick_check() never returns and memstick_remove_host() blocks in flush_workqueue():
INFO: task kworker/u10:3:65 blocked for more than 20 seconds. Workqueue: kmemstick memstick_check __wait_for_common memstick_check INFO: task kworker/1:1:33 blocked for more than 20 seconds. Workqueue: usb_hub_wq hub_event __flush_workqueue memstick_remove_host rtsx_usb_ms_drv_remove
Never drop a request. rtsx_usb_ms_request() always schedules handle_req, and handle_req fails requests with -ENOMEDIUM once eject is set, without touching the device. drv_remove flushes handle_req instead of cancelling it, and cancels it only after memstick_remove_host(), when no new request can arrive, so it cannot run on a freed host.
The host_mutex drain in drv_remove is removed: handle_req always leaves host->req NULL when it finishes, so the drain never had anything to do, and it would now race with handle_req.
--- drivers/memstick/host/rtsx_usb_ms.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-)
drivers/memstick/host/rtsx_usb_ms.c +11 -20
@@ -27,7 +27,6 @@ struct rtsx_usb_ms {struct memstick_host *msh;struct memstick_request *req; -struct mutex host_mutex;struct work_struct handle_req;struct delayed_work poll_card;
@@ -511,6 +510,13 @@ static void rtsx_usb_ms_handle_req(strucstruct memstick_host *msh = host->msh;int rc; +/* Fail requests after eject so their waiters are released. */ +if (host->eject) { +while (!memstick_next_req (msh, &host->req)) + host->req->error = -ENOMEDIUM ; +return ; + } +if (!host->req) {pm_runtime_get_sync (ms_dev (host)); do {
@@ -544,8 +550,7 @@ static void rtsx_usb_ms_request(struct mdev_dbg (ms_dev (host),"--> %s\n" , __func__); -if (!host->eject) -schedule_work (&host->handle_req); +schedule_work (&host->handle_req); } static int rtsx_usb_ms_set_param(struct memstick_host *msh,
@@ -778,7 +783,6 @@ static int rtsx_usb_ms_drv_probe(struct host->power_mode =MEMSTICK_POWER_OFF ;platform_set_drvdata (pdev, host); -mutex_init (&host->host_mutex);INIT_WORK (&host->handle_req, rtsx_usb_ms_handle_req);INIT_DELAYED_WORK (&host->poll_card, rtsx_usb_ms_poll_card);
@@ -809,27 +813,12 @@ static int rtsx_usb_ms_drv_remove(struct {struct rtsx_usb_ms *host =platform_get_drvdata (pdev);struct memstick_host *msh = host->msh; -int err; host->eject = true; msh->removing = true; -cancel_work_sync (&host->handle_req); +flush_work (&host->handle_req);cancel_delayed_work_sync (&host->poll_card); -mutex_lock (&host->host_mutex); -if (host->req) { -dev_dbg (ms_dev (host), -"%s: Controller removed during transfer\n" , -dev_name (&msh->dev)); - host->req->error = -ENOMEDIUM ; -do { - err =memstick_next_req (msh, &host->req); -if (!err) - host->req->error = -ENOMEDIUM ; - }while (!err); - } -mutex_unlock (&host->host_mutex); -/* Balance possible unbalanced usage count * e.g. unconditional module removal */
@@ -838,6 +827,8 @@ static int rtsx_usb_ms_drv_remove(structpm_runtime_disable (ms_dev (host));memstick_remove_host (msh); +/* No card, no new requests; wait for the last failed one to finish. */ +cancel_work_sync (&host->handle_req);dev_dbg (ms_dev (host),": Realtek USB Memstick controller has been removed\n" );memstick_free_host (msh);
Greg Kroah-Hartman
maintainerPATCH 455/1887 dm-crypt: reject the lmk IV mode with AEAD ciphers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Cressey <[email protected]>
commit 3195e0daf590683992edb4eed32269e569e04924 upstream.
A "capi:" table line that pairs an AEAD cipher with the lmk IV mode, for example "capi:gcm(aes)-lmk" with the integrity:28:aead option, causes an oops when it is loaded. lmk sets tfms_count to 64, but crypt_alloc_tfms_aead only allocates one transform, so crypt_setkey reads past the end of the tfms_aead array and calls crypto_aead_setkey on the values it finds there.
lmk exists for compatibility with Loop-AES, which uses CBC, so refuse it with an AEAD cipher rather than allocate 64 AEAD transforms. The check cannot go in crypt_iv_lmk_ctr with the other lmk checks, because the IV constructor runs after crypt_set_key.
Note that this is not a security bug because the memory corruption can only be triggered by root.
--- drivers/md/dm-crypt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/dm-crypt.c +6 -1
@@ -2914,8 +2914,13 @@ static int crypt_ctr_cipher_new(struct d } } -if (*ivmode && !strcmp (*ivmode,"lmk" )) +if (*ivmode && !strcmp (*ivmode,"lmk" )) { +if (crypt_integrity_aead (cc)) { + ti->error ="AEAD transforms not supported for LMK" ; +return -EINVAL ; + } cc->tfms_count =64 ; + }if (*ivmode && !strcmp (*ivmode,"essiv" )) {if (!*ivopts) {
Greg Kroah-Hartman
maintainerPATCH 456/1887 dm-snap: reject the transient exception store for snapshot-merge
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ma Xinmeng <[email protected]>
commit fcbde6227fcc53c73f08c56b2539e462d545cac6 upstream.
snapshot_merge_next_chunks() calls s->store->type->prepare_merge() without checking it. The transient store ("N") implements neither prepare_merge nor commit_merge, and snapshot_ctr() validates those callbacks only on the handover path (__validate_exception_handover()), so a directly constructed snapshot-merge calls a NULL prepare_merge on resume:
snapshot_merge_resume -> snapshot_merge_next_chunks -> prepare_merge(...)
commit_merge() is NULL for the same reason. Userspace only issues documented device-mapper ioctls (CAP_SYS_ADMIN); this is a misconfiguration the kernel must reject rather than oops on.
Reject the combination in snapshot_ctr() at table-load time (-EINVAL), the same check the handover path already performs; this also covers the commit_merge() call site, which a guard local to the prepare_merge call would miss.
Tested on Linux v6.6.157 KASAN: unpatched, the dmsetup reproducer oopses in snapshot_merge_next_chunks(); with this patch, the table load fails with -EINVAL and no oops. Also present on v6.6.145; still present on the linux-dm tree (555f3d7be91a) and on torvalds/linux master (62f4c998b297) as of 2026-09-22.
Note that this is not a security bug because only root can trigger it.
--- drivers/md/dm-snap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/md/dm-snap.c +14 -0
@@ -1306,6 +1306,20 @@ static int snapshot_ctr(struct dm_target goto bad_store; } +/* +* snapshot-merge requires the optional prepare_merge/commit_merge +* callbacks; the transient exception store does not implement them. +* The handover path checks this in __validate_exception_handover(), +* but a directly constructed snapshot-merge never goes through it. +*/ +if (dm_target_is_snapshot_merge (ti) && + (!s->store->type->prepare_merge || + !s->store->type->commit_merge)) { + ti->error ="Snapshot exception store does not support snapshot-merge." ; + r = -EINVAL ; + goto bad_hash_tables; + } + argv += args_used; argc -= args_used;
Greg Kroah-Hartman
maintainerPATCH 457/1887 mmc: cavium-octeon: destroy slot platform devices on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 0f4d4424fc1d651ec3fa63a0a8060ba9087eb0ec upstream.
octeon_mmc_probe() creates host->slot_pdev[i] with of_platform_device_create(), while octeon_mmc_remove() does not destroy the child platform devices.
The probe failure path removes each MMC slot and destroys its associated platform device, but the normal remove path only removes the MMC slot. As a result, the child platform devices remain registered after the Octeon MMC controller is removed.
Destroy each slot platform device during removal after cleaning up the corresponding MMC slot, matching the probe failure cleanup path.
This issue was found by manual code inspection.
--- drivers/mmc/host/cavium-octeon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/cavium-octeon.c +4 -1
@@ -300,9 +300,12 @@ static int octeon_mmc_remove(struct platu64 dma_cfg;int i; -for (i =0 ; i <CAVIUM_MAX_MMC ; i++) +for (i =0 ; i <CAVIUM_MAX_MMC ; i++) {if (host->slot[i])cvm_mmc_of_slot_remove (host->slot[i]); +if (host->slot_pdev[i]) +of_platform_device_destroy (&host->slot_pdev[i]->dev,NULL ); + } dma_cfg =readq (host->dma_base +MIO_EMM_DMA_CFG (host)); dma_cfg &= ~MIO_EMM_DMA_CFG_EN ;
Greg Kroah-Hartman
maintainerPATCH 458/1887 mmc: cavium-thunderx: destroy slot platform devices on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 29ee8cf18a21b02cd0b2e35f741b61cd1fe3e14e upstream.
thunder_mmc_probe() creates host->slot_pdev[i] with of_platform_device_create(), while thunder_mmc_remove() does not destroy the child platform devices.
The probe failure path removes each MMC slot and destroys its associated platform device, but the normal remove path only removes the MMC slot. As a result, the child platform devices remain registered after the ThunderX MMC controller is removed.
Destroy each slot platform device during removal after cleaning up the corresponding MMC slot, matching the probe failure cleanup path. Keep an extra device reference around of_platform_device_destroy() as done in the existing error path.
This issue was found by manual code inspection.
--- drivers/mmc/host/cavium-thunderx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/cavium-thunderx.c +4 -1
@@ -173,9 +173,12 @@ static void thunder_mmc_remove(struct pcu64 dma_cfg;int i; -for (i =0 ; i <CAVIUM_MAX_MMC ; i++) +for (i =0 ; i <CAVIUM_MAX_MMC ; i++) {if (host->slot[i])cvm_mmc_of_slot_remove (host->slot[i]); +if (host->slot_pdev[i]) +of_platform_device_destroy (&host->slot_pdev[i]->dev,NULL ); + } dma_cfg =readq (host->dma_base +MIO_EMM_DMA_CFG (host)); dma_cfg &= ~MIO_EMM_DMA_CFG_EN ;
Greg Kroah-Hartman
maintainerPATCH 459/1887 mmc: mtk-sd: Cancel request timeout work on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yibo Tan <[email protected]>
commit b38af5386a74416e898955443f2e26547b358cb2 upstream.
The driver queues req_timeout while a request is active. msdc_request_done() uses cancel_delayed_work(), which does not wait for a timeout callback that has already started.
The timeout callback calls mmc_request_done(), which wakes the request waiter, and then continues to use host->dev_comp and check the SDIO IRQ. During unbind, msdc_drv_remove() can return and the managed mmc_host can be freed before the callback finishes.
KASAN reported use-after-free accesses in msdc_request_done() and msdc_recheck_sdio_irq() in each of three unbind tests. The same tests completed without a kernel diagnostic after this change.
Call cancel_delayed_work_sync() after mmc_remove_host() has stopped new requests and before the driver releases the host resources.
--- drivers/mmc/host/mtk-sd.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/mtk-sd.c +1 -0
@@ -2854,6 +2854,7 @@ static int msdc_drv_remove(struct platfoplatform_set_drvdata (pdev,NULL );mmc_remove_host (mmc); +cancel_delayed_work_sync (&host->req_timeout);msdc_deinit_hw (host);msdc_gate_clock (host);
Greg Kroah-Hartman
maintainerPATCH 460/1887 mmc: sdhci-sprd: disable runtime PM on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit e1c6c10a6a70a69e29b04fcc1ebe4b9bcbc7a49a upstream.
sdhci_sprd_probe() enables runtime PM, while sdhci_sprd_remove() does not perform the corresponding runtime PM cleanup.
The probe failure path disables runtime PM before disabling the clocks, but the normal remove path directly disables clocks that are also managed by the runtime PM callbacks. If the device is runtime suspended, those clocks may already be disabled.
Resume the device before removal, disable runtime PM and drop the temporary runtime PM reference before disabling the clocks.
This issue was found by manual code inspection.
--- drivers/mmc/host/sdhci-sprd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/mmc/host/sdhci-sprd.c +4 -0
@@ -756,6 +756,10 @@ static int sdhci_sprd_remove(struct platstruct sdhci_host *host =platform_get_drvdata (pdev);struct sdhci_sprd_host *sprd_host =TO_SPRD_HOST (host); +pm_runtime_get_sync (&pdev->dev); +pm_runtime_disable (&pdev->dev); +pm_runtime_put_noidle (&pdev->dev); +sdhci_remove_host (host,0 );clk_disable_unprepare (sprd_host->clk_sdio);
Greg Kroah-Hartman
maintainerPATCH 461/1887 net/packet: guard the ll header push in packet_rcv_spkt()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Quchaosheng <[email protected]>
commit 28bc1ef699610ee09ce3d46a00552f5a0a0144bd upstream.
packet_rcv_spkt() restores the link layer header with
skb_push(skb, skb->data - skb_mac_header(skb));
That subtraction is only meaningful when the device actually has a link layer header. packet_rcv() and tpacket_rcv() both wrap it in dev_has_header(), which is also the predicate the block comment at the top of the file states the restore in terms of; packet_rcv_spkt() does not. commit d549699048b4 ("net/packet: fix packet receive on L3 devices without visible hard header") introduced the helper and changed the two call sites, and this one stayed behind.
A device without a visible ll header can leave skb->mac_header at the 0xFFFF sentinel that __alloc_skb() initialises it to. A CAN skb does:init_can_skb() sets pkt_type and ip_summed but does not reset the headers, and commit 9f10374bb024 ("can: remove private CAN skb headroom infrastructure") dropped the skb_reset_*_header() calls that used to be there. skb_mac_header() is then 0xFFFF, the length becomes a large negative number and skb_push() reports it through skb_under_panic() -- from softirq context, so it is a full system panic even with panic_on_oops=0:
skbuff: skb_under_panic: text:ffffffff8bd21bc1 len:-65455 put:-65471 head:... data:... tail:0x50 end:0x180 dev:can0 kernel BUG at net/core/skbuff.c:214!
RIP: 0010:skb_panic+0x50/0x60 Call Trace: <IRQ> skb_push+0x38/0x40 packet_rcv_spkt+0xe1/0x170 __netif_receive_skb_core.constprop.0+0x7e8/0xd30 ... Kernel panic - not syncing: Fatal exception in interrupt
The socket type is reachable: packet_create() accepts SOCK_PACKET alongside SOCK_RAW and SOCK_DGRAM behind the same CAP_NET_RAW check, and neither the socket length nor a capability check keeps it away from a CAN interface.
The missing skb_reset_*_header() calls in init_can_skb() are a regression in their own right and are being fixed separately, but a packet socket should not turn a link layer that did not initialise its mac header into a kernel panic. Guard the push the way the other two receive paths do.
Tested on v7.3-rc5 under QEMU with a slcan device on a pty, which is the driver RX path: vcan does not reproduce it, because can_send() resets the headers on the way out. One SOCK_PACKET socket bound to can0 and one frame written into the line discipline panics an unpatched kernel with the trace above; the same image with this patch prints no panic and powers off normally. Both kernels are this tree, defconfig plus CONFIG_CAN_SLCAN=y, differing only in this hunk.
--- net/packet/af_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/packet/af_packet.c +2 -1
@@ -1964,7 +1964,8 @@ static int packet_rcv_spkt(struct sk_buf spkt = &PACKET_SKB_CB (skb)->sa.pkt; -skb_push (skb, skb->data -skb_mac_header (skb)); +if (dev_has_header (dev)) +skb_push (skb, skb->data -skb_mac_header (skb));/* * The SOCK_PACKET socket receives _all_ frames.
Greg Kroah-Hartman
maintainerPATCH 462/1887 net/smc: protect clcsock lifetime in smc_getname
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 64a6b36b0e1855288080bc5f89769f27d6dc03c8 upstream.
smc_getname() dereferences smc->clcsock without holding clcsock_release_lock. Link-group termination can release the CLC socket through smc_close_active_abort() while the SMC socket is still open, for example after shutdown(SHUT_WR).
A getsockname() caller can load smc->clcsock, then the termination worker can clear the pointer and call sock_release() before the caller accesses clcsock->ops or invokes getname(). This causes a use-after-free; if the worker clears the pointer before the load, it causes a NULL dereference. The syscall's file reference keeps the SMC socket alive but does not prevent asynchronous release of its CLC socket.
KASAN reported the following with test-only timing instrumentation:
BUG: KASAN: slab-use-after-free in smc_getname+0x19e/0x1b0 Read of size 8 at addr ffff888109abb4e0 by task poc/103 Call Trace: smc_getname+0x19e/0x1b0 do_getsockname+0xe5/0x170 __sys_getsockname+0x8c/0x100 Allocated by task 95: sock_alloc_inode+0x1e/0x280 sock_alloc+0x3d/0x240 __sock_create+0x7e/0x430 smc_create+0x121/0x240 Freed by task 0: kmem_cache_free+0xcc/0x340 rcu_core+0x50a/0x1850 Last potentially related work creation: evict+0x446/0x6c0 smc_clcsock_release+0xa8/0xd0 smc_close_active_abort+0x26a/0x3a0 __smc_lgr_terminate.part.0+0x137/0x2e0
Hold clcsock_release_lock across the pointer check and the getname() callback to serialize with smc_clcsock_release(). Return -EBADF if the CLC socket has already been released, preserving the existing peer state check and the callback's return value otherwise.
--- net/smc/af_smc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
net/smc/af_smc.c +6 -1
@@ -2677,6 +2677,7 @@ static int smc_getname(struct socket *so int peer) {struct smc_sock *smc; +int rc = -EBADF ;if (peer && (sock->sk->sk_state !=SMC_ACTIVE ) && (sock->sk->sk_state !=SMC_APPCLOSEWAIT1 ))
@@ -2684,7 +2685,11 @@ static int smc_getname(struct socket *so smc =smc_sk (sock->sk); -return smc->clcsock->ops->getname (smc->clcsock, addr, peer); +mutex_lock (&smc->clcsock_release_lock); +if (smc->clcsock) + rc = smc->clcsock->ops->getname (smc->clcsock, addr, peer); +mutex_unlock (&smc->clcsock_release_lock); +return rc; }static int smc_sendmsg (struct socket *sock,struct msghdr *msg,size_t len)
Greg Kroah-Hartman
maintainerPATCH 463/1887 net: bridge: avoid recursive multicast port cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zixuan Chai <[email protected]>
commit 5158353121bae4f552cb677ce8c5c3ef52f93a0d upstream.
br_multicast_sg_del_exclude_ports() removes automatically added STAR_EXCL port groups by calling br_multicast_del_pg(). For S,G entries, that deletion calls back into br_multicast_sg_del_exclude_ports(), so a large number of STAR_EXCL ports consumes one kernel stack frame per port and can hit the stack guard page.
Keep the complete port-group deletion path for cleanup, but suppress the S,G exclude-port cleanup while that helper is already walking the same entry. Normal deletion callers retain the existing behavior.
--- net/bridge/br_multicast.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
net/bridge/br_multicast.c +18 -5
@@ -80,6 +80,10 @@ __br_multicast_add_group(struct net_brid bool blocked);static void br_multicast_find_del_pg (struct net_bridge *br,struct net_bridge_port_group *pg); +static void __br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp, +bool sg_del_exclude_ports);static void __br_multicast_stop (struct net_bridge_mcast *brmctx); static int br_mc_disabled_update(struct net_device *dev, bool value,
@@ -436,7 +440,7 @@ static void br_multicast_sg_del_exclude_for (pp = &sgmp->ports; (p =mlock_dereference (*pp, sgmp->br)) !=NULL ;) {if (!(p->flags &MDB_PG_FLAGS_PERMANENT )) -br_multicast_del_pg (sgmp, p, pp); +__br_multicast_del_pg (sgmp, p, pp, false);else pp = &p->next; }
@@ -675,9 +679,10 @@ static void br_multicast_destroy_port_grkfree_rcu (pg, rcu); } -void br_multicast_del_pg (struct net_bridge_mdb_entry *mp, -struct net_bridge_port_group *pg, -struct net_bridge_port_group __rcu **pp) +static void __br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp, +bool sg_del_exclude_ports) {struct net_bridge *br = pg->key.port->br;struct net_bridge_group_src *ent;
@@ -692,7 +697,8 @@ void br_multicast_del_pg(struct net_bridif (!br_multicast_is_star_g (&mp->addr)) {rhashtable_remove_fast (&br->sg_port_tbl, &pg->rhnode, br_sg_port_rht_params); -br_multicast_sg_del_exclude_ports (mp); +if (sg_del_exclude_ports) +br_multicast_sg_del_exclude_ports (mp); }else {br_multicast_star_g_handle_mode (pg,MCAST_INCLUDE ); }
@@ -703,6 +709,13 @@ void br_multicast_del_pg(struct net_bridmod_timer (&mp->timer, jiffies); } +void br_multicast_del_pg (struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp) +{ +__br_multicast_del_pg (mp, pg, pp, true); +} +static void br_multicast_find_del_pg (struct net_bridge *br,struct net_bridge_port_group *pg) {
Greg Kroah-Hartman
maintainerPATCH 464/1887 net: dsa: microchip: fix KSZ8765 fiber detection
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastien Royen <[email protected]>
commit fc13ba44da197a186f2f4d77c5b7d73d0f99f053 upstream.
The KSZ8765 is similar to the KSZ8795 but has two fiber ports.
KSZ8_PORT_STATUS_0 is used to detect fiber mode. It is currently defined as 0x08, which is the Global Control 6 MIB Control register and has bit 7 defined as Flush Counter.
Set KSZ8_PORT_STATUS_0 to 0x18, which is the Port 1 Status 0 register where bit 7 is the Fiber Mode bit.
This issue was discovered when upgrading an embedded device from kernel 5.10 to 6.16. The device was using a KSZ8765 device tree configuration and the corresponding hardware, but during boot the kernel incorrectly detected it as a KSZ8795. The relevant boot messages were:
ksz-switch spi0.0: found switch: KSZ8795, rev 0
ksz-switch spi0.0: Device tree specifies chip KSZ8765 but found KSZ8795, please fix it!
--- drivers/net/dsa/microchip/ksz_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/microchip/ksz_common.h +1 -1
@@ -552,7 +552,7 @@ static inline int is_lan937x(struct ksz_#define KSZ87_FAMILY_ID 0x87#define KSZ88_FAMILY_ID 0x88 -#define KSZ8_PORT_STATUS_0 0x08 +#define KSZ8_PORT_STATUS_0 0x18#define KSZ8_PORT_FIBER_MODE BIT(7)#define SW_CHIP_ID_M GENMASK(7, 4)
Greg Kroah-Hartman
maintainerPATCH 465/1887 net: usb: ax88179_178a: fix rx frame length for non-last packets
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fredrik Nyberg <[email protected]>
commit 9b6c20f788472d2042717a3c2f1bc60b2b77083e upstream.
Commit 4ce62d5b2f7a ("net: usb: ax88179_178a: stop lying about skb->truesize") replaced skb_clone() with a copy into a new skb for every packet of a bulk-in transfer except the last one. The copy skips the 2-byte IP alignment pseudo header but still copies pkt_len bytes, and pkt_len includes that header. Each of these frames is therefore delivered with two extra trailing bytes: the 0xeeee pseudo header of the next slot when the frame ends on an 8-byte boundary, or slot padding otherwise. The last packet is still trimmed to pkt_len - 2.
IPv4 and IPv6 trim the extra bytes, so most traffic is unaffected. Anything that relies on the frame length is not. MACsec takes the ICV from the last 16 bytes and drops every such frame as InPktsNotValid. In our setup that was 0.2-1.2% of received MACsec frames, depending on how many frames shared a transfer, including service discovery multicast.
Allocate and copy pkt_len - 2 bytes, like the last-packet path.
--- drivers/net/usb/ax88179_178a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/usb/ax88179_178a.c +3 -3
@@ -1461,11 +1461,11 @@ static int ax88179_rx_fixup(struct usbnereturn 1 ; } - ax_skb =netdev_alloc_skb_ip_align (dev->net, pkt_len); + ax_skb =netdev_alloc_skb_ip_align (dev->net, pkt_len -2 );if (!ax_skb)return 0 ; -skb_put (ax_skb, pkt_len); -memcpy (ax_skb->data, skb->data +2 , pkt_len); +skb_put (ax_skb, pkt_len -2 ); +memcpy (ax_skb->data, skb->data +2 , pkt_len -2 );ax88179_rx_checksum (ax_skb, pkt_hdr);usbnet_skb_return (dev, ax_skb);
Greg Kroah-Hartman
maintainerPATCH 466/1887 nvme: fix swapped ZRASF zone state values for full and read only
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Bonde Torp <[email protected]>
commit 564e46d9f6e87912effa03f123d37a511d520f09 upstream.
The Zone Management Receive command Zone Receive Action Specific (ZRASF) reporting option values for the Full and Read Only zone states are swapped compared to the NVM Express Zoned Namespace Command Set Specification, Revision 1.5, Figure 35:
- 5h lists the zones in the ZSF:Full state.
- 6h lists the zones in the ZSRO:Read Only state.
The nvmet ZNS backend uses these constants to map the ZRASF value received from the host to a block layer zone condition when filtering zones in Report Zones. Because of the swap, a host asking for full zones was given the read only zones, and a host asking for read only zones was given the full zones.
Swap the values of NVME_ZRASF_ZONE_STATE_FULL and NVME_ZRASF_ZONE_STATE_READONLY to match the specification.
--- include/linux/nvme.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/nvme.h +2 -2
@@ -1060,8 +1060,8 @@ enum {NVME_ZRASF_ZONE_STATE_IMP_OPEN =0x02 ,NVME_ZRASF_ZONE_STATE_EXP_OPEN =0x03 ,NVME_ZRASF_ZONE_STATE_CLOSED =0x04 , -NVME_ZRASF_ZONE_STATE_READONLY =0x05 , -NVME_ZRASF_ZONE_STATE_FULL =0x06 , +NVME_ZRASF_ZONE_STATE_FULL =0x05 , +NVME_ZRASF_ZONE_STATE_READONLY =0x06 ,NVME_ZRASF_ZONE_STATE_OFFLINE =0x07 , NVME_REPORT_ZONE_PARTIAL = 1, };
Greg Kroah-Hartman
maintainerPATCH 467/1887 openvswitch: fix soft lockup in the netlink flow dump
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Denis V. Lunev <[email protected]>
commit aaaaf87ea99b8766c9a8aa0e71aa42e6bc8a5320 upstream.
A production compute node carrying a few thousand datapath flows hit a soft lockup inside a single netlink flow dump and panicked.
ovs_flow_cmd_dump() calls ovs_flow_stats_get() for every flow it emits, and that releases stats->lock with spin_unlock_bh() once per CPU that has touched the flow. Every release is a local_bh_enable(), and each one runs the pending softirq backlog in the dumping thread's own context.
The skb bounds the flows one callback emits, but not the softirq work it absorbs. On a CPU that carries the box's packet load the backlog refills as fast as it drains, so the dumping thread becomes that CPU's softirq engine. It never sleeps and it has no reschedule point, so under voluntary preemption nothing can take the CPU away from it:
neither the ksoftirqd the kernel woke to take the work over, nor the stopper thread the softlockup detector dispatches to refresh its timestamp.
Hold BH off across the whole callback instead, the way ctnetlink_dump_table() does, so the nested spin_unlock_bh() stop draining softirqs. The loop already runs under rcu_read_lock() and cannot sleep. What it gives up is preemption under CONFIG_PREEMPT, since a BH-off region is not preemptible outside PREEMPT_RT. The region stays short: the skb caps the flows one callback emits, and empty buckets cost no skb space but are each visited once per dump, as the cursor only moves forward. The table grows on insert and shrinks only on flush, so the walk is bounded by the largest flow count the datapath has held. The softirq backlog the callback used to absorb has no bound at all.
--- net/openvswitch/datapath.c | 8 ++++++++ 1 file changed, 8 insertions(+)
net/openvswitch/datapath.c +8 -0
@@ -1476,6 +1476,12 @@ static int ovs_flow_cmd_dump(struct sk_breturn -ENODEV ; } +/* +* Not needed for safety. Stops every spin_unlock_bh() in +* ovs_flow_stats_get() from running the softirq backlog. +*/ +local_bh_disable (); + ti =rcu_dereference (dp->table.ti);for (;;) {struct sw_flow *flow;
@@ -1496,6 +1502,8 @@ static int ovs_flow_cmd_dump(struct sk_b cb->args[0 ] = bucket; cb->args[1 ] = obj; } + +local_bh_enable ();rcu_read_unlock ();return skb->len; }
Greg Kroah-Hartman
maintainerPATCH 468/1887 regulator: ltc3676: dont read the write-only HRST and CLIRQ registers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abhishek Ojha <[email protected]>
commit 28c2388ee24cdbefbcc458fa41ef7bffaaa1cc83 upstream.
HRST (0x1e) and CLIRQ (0x1f) are write-only command strobes. Writing HRST triggers a hard reset of the chip and writing CLIRQ clears the interrupt; reading them returns nothing useful, and the read itself fires the command.
The result is that a plain register dump resets the board:
cat /sys/kernel/debug/regmap/2-003c/registers
walks every readable register, hits HRST, and the board reboots.
Split the callback back in two so HRST and CLIRQ stay writable but are no longer readable. The readable range is left unchanged (LTC3676_BUCK1 ... LTC3676_IRQSTAT).
--- drivers/regulator/ltc3676.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/regulator/ltc3676.c +12 -3
@@ -232,7 +232,7 @@ static const struct regulator_desc ltc36 LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2), }; -static bool ltc3676_readable_writeable_reg (struct device *dev,unsigned int reg) +static bool ltc3676_writeable_reg (struct device *dev,unsigned int reg) {switch (reg) { case LTC3676_BUCK1 ... LTC3676_IRQSTAT:
@@ -243,6 +243,15 @@ static bool ltc3676_readable_writeable_rreturn false; } +static bool ltc3676_readable_reg (struct device *dev,unsigned int reg) +{ +switch (reg) { + case LTC3676_BUCK1 ... LTC3676_IRQSTAT: +return true; + } +return false; +} +static bool ltc3676_volatile_reg (struct device *dev,unsigned int reg) {switch (reg) {
@@ -255,8 +264,8 @@ static bool ltc3676_volatile_reg(structstatic const struct regmap_config ltc3676_regmap_config = { .reg_bits =8 , .val_bits =8 , - .writeable_reg = ltc3676_readable_writeable_reg, - .readable_reg = ltc3676_readable_writeable_reg, + .writeable_reg = ltc3676_writeable_reg, + .readable_reg = ltc3676_readable_reg, .volatile_reg = ltc3676_volatile_reg, .max_register =LTC3676_CLIRQ , .use_single_read = true,
Greg Kroah-Hartman
maintainerPATCH 469/1887 scsi: qedi: Initialize callback state before registration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 85de8b3a5eaa23d153aff4c7c83dddbc949064c9 upstream.
qedi_get_protocol_tlv_data() can be called asynchronously by QED after qedi_ops->register_ops(). It takes stats_lock and reads ll2_mtu, but __qedi_probe() currently registers the callback before initializing the mutex and assigning the default MTU on the normal probe path.
Initialize the callback-visible state before registering qedi_cb_ops. Keep the recovery path from reinitializing state because it reuses the existing qedi context.
--- drivers/scsi/qedi/qedi_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/scsi/qedi/qedi_main.c +1 -2
@@ -2664,8 +2664,6 @@ retry_probe:snprintf (host_buf,sizeof (host_buf),"host_%d" , qedi->shost->host_no); qedi_ops->common->set_name (qedi->cdev, host_buf); - qedi_ops->register_ops (qedi->cdev, &qedi_cb_ops, qedi); -memset (¶ms,0 ,sizeof (params)); params.mtu =DEF_PATH_MTU +IPV6_HDR_LEN +TCP_HDR_LEN ; qedi->ll2_mtu =DEF_PATH_MTU ;
@@ -2682,6 +2680,7 @@ retry_probe:spin_lock_init (&qedi->task_idx_lock);mutex_init (&qedi->stats_lock); } + qedi_ops->register_ops (qedi->cdev, &qedi_cb_ops, qedi); qedi_ops->ll2->register_cb_ops (qedi->cdev, &qedi_ll2_cb_ops, qedi); qedi_ops->ll2->start (qedi->cdev, ¶ms);
Greg Kroah-Hartman
maintainerPATCH 470/1887 Bluetooth: hci_sock: Serialize dead-device detachment
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 381a0925c556a8d91a80a9b9e3e86651d60ffee3 upstream.
Rebinding an HCI socket after its controller is unregistered can race monitor control replay and crash the kernel. hci_sock_bind() clears hci_pi(sk)->hdev and drops the device reference under only the socket lock, whereas send_monitor_control_replay() holds hci_sk_list.lock for reading.
Replay can observe a non-NULL hdev, then bind can clear it and drop the last reference before create_monitor_ctrl_open() reads hdev->id. This can cause a NULL pointer dereference if the pointer is reloaded, or a use-after-free if the old pointer is retained.
The kernel reported:
KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f] RIP: 0010:create_monitor_ctrl_open+0x579/0x800 Call Trace: hci_sock_bind+0xd96/0x1190 __sys_bind+0x166/0x200 __x64_sys_bind+0x6d/0xb0 do_syscall_64+0xdd/0x4a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f
The same missing serialization lets hci_send_to_sock() select a socket for the old device and queue its frame after bind has detached the socket or installed a new binding.
Take hci_sk_list.lock for writing when clearing the device pointer and resetting the socket state. This waits for existing replay and delivery readers to finish before detachment and prevents later readers from using the old binding. Keep hci_dev_put() outside the critical section because the final device release can sleep.
--- net/bluetooth/hci_sock.c | 2 ++ 1 file changed, 2 insertions(+)
net/bluetooth/hci_sock.c +2 -0
@@ -1161,8 +1161,10 @@ static int hci_sock_bind(struct socket **/ hdev =hci_pi (sk)->hdev;if (hdev &&hci_dev_test_flag (hdev,HCI_UNREGISTER )) { +write_lock (&hci_sk_list.lock);hci_pi (sk)->hdev =NULL ; sk->sk_state =BT_OPEN ; +write_unlock (&hci_sk_list.lock);hci_dev_put (hdev); } hdev =NULL ;
Greg Kroah-Hartman
maintainerPATCH 471/1887 Bluetooth: MGMT: Fix status of pending commands flushed on power off
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Iaroslav Voitovych <[email protected]>
commit 86ef0f58bdecdedb3a1240971c56d71b7e4ce3fc upstream.
cmd_complete_rsp() receives a struct cmd_lookup and, for a pending command that has no cmd_complete callback, falls through to cmd_status_rsp(cmd, data). cmd_status_rsp() reads data as a u8 *, so the status sent comes from the first byte of match->sk's representation, not from match->mgmt_status.
commit f53e1c9c726d ("Bluetooth: MGMT: Fix possible crash on mgmt_index_removed") changed the callers' data from &status to &match and updated the cmd_complete branch to match->mgmt_status, but left the fall-through passing data unchanged.
In mgmt_index_removed() match->sk is NULL, so every such command is answered with status 0x00 (Success) instead of MGMT_STATUS_INVALID_INDEX. In __mgmt_power_off() it is NULL too, unless a Set Powered command was pending: then settings_rsp() has stored that command's socket in match->sk, and the byte sent comes from the socket pointer. Either way the status the caller set, MGMT_STATUS_NOT_POWERED (or MGMT_STATUS_INVALID_INDEX when the device is being unregistered), is lost.
Pass the status the callers set.
This was seen on a QCA9377 laptop: bluetoothd's Start Discovery, pending when the adapter was powered off, was answered with Command Status 0x00 and no parameters, and bluetoothd 5.72 crashed on the zero-length success. BlueZ master has since added the length check on that path ("adapter: Fix crash on short start discovery reply", BlueZ a734b06059cb), but userspace should still be told Not Powered, not Success.
Tested on Ubuntu 7.0.0-31 with a virtual controller (hci_vhci):
power off is held in HCI Write Scan Enable while a Start Discovery is submitted, and the flush answers it with status 0x00 before this change and 0x0f (Not Powered) after.
--- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/mgmt.c +1 -1
@@ -1453,7 +1453,7 @@ static void cmd_complete_rsp(struct mgmtreturn ; } -cmd_status_rsp (cmd, data); +cmd_status_rsp (cmd, &match->mgmt_status); }static int generic_cmd_complete (struct mgmt_pending_cmd *cmd,u8 status)
Greg Kroah-Hartman
maintainerPATCH 472/1887 Bluetooth: RFCOMM: free the skb when the DLC has no owner
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxim Skokov <[email protected]>
commit 9d1afbf60ed53c5b051cd124153e0ae3078c8b93 upstream.
rfcomm_recv_data() hands the skb to d->data_ready() and returns 0 without freeing it, so the callback owns the skb from that point on. The tty implementation frees it when the DLC has been detached from its device:
static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc,
struct sk_buff *skb)
{
struct rfcomm_dev *dev = dlc->owner; if (!dev) {
kfree_skb(skb);
return;
}The socket implementation returns without freeing it, and the skb is leaked.
A connected DLC can have no owner: rfcomm_sock_destruct() clears d->owner, while the DLC itself stays on the session until it is closed. Data frames that arrive in that window still find d->state == BT_CONNECTED in rfcomm_recv_data() and are handed to the callback, one leaked skb each.
The leak does not stop on its own either. The remote runs out of credits only once RFCOMM_RX_THROTTLED is set, and for a socket the only place that sets it is rfcomm_sk_data_ready() itself, below the return. rfcomm_process_dlcs() keeps granting credits, so the remote keeps sending and the leak keeps growing.
Free the skb, as the tty side does.
--- net/bluetooth/rfcomm/sock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/bluetooth/rfcomm/sock.c +4 -1
@@ -50,8 +50,11 @@ static void rfcomm_sock_kill(struct sockstatic void rfcomm_sk_data_ready (struct rfcomm_dlc *d,struct sk_buff *skb) {struct sock *sk = d->owner; -if (!sk) + +if (!sk) { +kfree_skb (skb);return ; + }atomic_add (skb->len, &sk->sk_rmem_alloc);skb_queue_tail (&sk->sk_receive_queue, skb);
Greg Kroah-Hartman
maintainerPATCH 473/1887 Bluetooth: RFCOMM: Fix NULL tty_dev dereference in rfcomm_dev_shutdown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Palla Raghunath <[email protected]>
commit 08e90633377f1b2567ab5ad6810b74c552246a07 upstream.
syzbot hit a NULL pointer dereference in rfcomm_dev_shutdown() when an RFCOMM tty is closed.
rfcomm_dev_add() puts the new device on rfcomm_dev_list first and only then registers the tty device and saves it in dev->tty_dev. If that registration fails, dev->tty_dev is never set at all. The device can be looked up in the meantime, so an open() of /dev/rfcommN gets through rfcomm_tty_install() and attaches to it. When that tty is closed again, rfcomm_dev_shutdown() uses dev->tty_dev without checking it:
Oops: general protection fault, probably for non-canonical address KASAN: null-ptr-deref in range [0x0000000000000040-0x0000000000000047] RIP: 0010:rfcomm_dev_shutdown+0x48/0xb0 net/bluetooth/rfcomm/tty.c:131 Call Trace: tty_port_shutdown+0x1bf/0x220 drivers/tty/tty_port.c:372 tty_port_close+0x4e/0x150 drivers/tty/tty_port.c:705 tty_release+0x359/0x1670 drivers/tty/tty_io.c:1718 __fput+0x418/0xa50 fs/file_table.c:512
rfcomm_dev_destruct() already copes with a NULL dev->tty_dev. Add the same check to rfcomm_dev_shutdown(), so the tty device is only moved when it was actually registered.
--- net/bluetooth/rfcomm/tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/rfcomm/tty.c +1 -1
@@ -131,7 +131,7 @@ static void rfcomm_dev_shutdown(struct t { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); -if (dev->tty_dev->parent) +if (dev->tty_dev && dev->tty_dev->parent)device_move (dev->tty_dev,NULL ,DPM_ORDER_DEV_LAST );/* close the dlc */
Greg Kroah-Hartman
maintainerPATCH 474/1887 drm/gud: dont keep a connector without a CRTC as connector_state
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sajal Gupta <[email protected]>
commit 71ec70ea26e399eb8371fe9d2d5bf5dab09570fb upstream.
If the 'for_each_new_connector_in_state()' loop finishes without hitting the break, connector_state is left pointing at the last connector visited, which has no CRTC, instead of staying NULL.
That skips the "if (!connector_state)" fallback below the loop, which looks up the active connector when the state contains none. The function then carries on with a connector that is not driven.
Fix by resetting connector_state to NULL for each connector visited that has no CRTC, so that it is NULL when none was found and the fallback runs.
--- drivers/gpu/drm/gud/gud_pipe.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/gud/gud_pipe.c +1 -0
@@ -489,6 +489,7 @@ int gud_pipe_check(struct drm_simple_disfor_each_new_connector_in_state (state, connector, connector_state, i) {if (connector_state->crtc)break ; + connector_state =NULL ; }/*
Greg Kroah-Hartman
maintainerPATCH 475/1887 drm/i915/gem: Prevent overstepping exec array boundary
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Karas <[email protected]>
commit ebe162db655881a38de43301151ff7ac940602b5 upstream.
It is possible for eb_relocate_parse_slow() to call kvfree() on entries outside the original exec array during following scenario inside eb_relocate_parse_slow():
1) eb_copy_relocations() allocates as many as eb->buffer_count copies for exec entries;
2) eb_parse() appends up to two VMAs, right after incrementing eb->buffer_count;
3) cleanup under "out" label uses this incremented buffer_count to release relocation pointers from exec array via kvfree(), not from VMA array.
To amend this problem, ensure that relocation cleanup uses the original exec object count, excluding the VMAs appended by the command parser.
--- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +1 -1
@@ -1752,6 +1752,7 @@ static int eb_reinit_userptr(struct i915 static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb) { +const unsigned int count = eb->buffer_count;bool have_copy = false;struct eb_vma *ev;int err =0 ;
@@ -1854,7 +1855,6 @@ err: out:if (have_copy) { -const unsigned int count = eb->buffer_count;unsigned int i;for (i =0 ; i < count; i++) {
Greg Kroah-Hartman
maintainerPATCH 476/1887 drm/i915/gt: Unmask interrupts only when ACTIVE is true
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Karas <[email protected]>
commit 5346b1cec6afa4f9b4b49a9f84e3cfef95a3f7bb upstream.
There is a small race window between intel_rps_boost() reading a stale ACTIVE state and queuing rps->work, where ACTIVE may be changed via asynchronous calls triggered by wakeref drop. This means that rps_work() could be triggered after the GT has been parked, so unmasking RPS PM interrupts would happen without holding PM wakelock. This sequence of events may be observed during live_rc6_ctx_wa() selftest:
1) live_rc6_ctx_wa()
-> intel_engine_pm_put()
-> wakeref_put()
ASYNC1) wakeref_put() callback
-> __engine_park()
-> intel_gt_pm_put_async()
-> intel_gt_pm_put_async_untracked()
-> intel_wakeref_put_async()ASYNC2) wakeref_put_async() callback
-> __gt_park()
-> intel_rps_park()
-> intel_rps_clear_active() [clear ACTIVE]
WITH INTERRUPTS:
-> rps_disable_interrupts()
-> cancel_work_sync(rps->work)
-> rps_reset_interrupts() [rps->pm_iir = 0]
WITHOUT INTERRUPTS (TIMER mode):
-> rps_stop_timer()
-> cancel_work_sync(rps->work)2) live_rc6_ctx_wa()
-> intel_gt_wait_for_idle()
-> intel_gt_retire_requests_timeout()
-> dma_fence_wait_timeout()
-> ops->wait() [i915_fence_wait()]
-> i915_request_wait_timeout()
-> intel_rps_boost()
-> intel_rps_is_active() [check ACTIVE]
[OPEN RACE WINDOW]
-> queue_work(rps->work)
-> retire_requests()
-> i915_request_retire()
-> intel_rps_dec_waiters() [from 1 to 0]If ASYNC1 and ASYNC2 would execute during [OPEN RACE WINDOW], then:
3) rps_work() executes from the workqueue and may satisfy "(!pm_iir && !client_boost)" test (in TIMER mode rps->pm_iir is zeroed by an earlier rps_work() call or never gets a new value after previous intel_rps_unpark() event), so it jumps to "out" label, bypassing intel_rps_is_active() guard and executes gen6_gt_pm_unmask_irq();
4) GT is parked and runtime PM wakelock is dropped, so only a raw reference in __gt_park() -> intel_display_power_put_async() remains for 100ms, then the MMIO write in gen6_gt_pm_unmask_irq() detects missing wakelock via assert_rpm_wakelock_held() and emits "RPM wakelock ref not held during HW access" tainting kernel.
Commit 3e7abf814193 ("drm/i915: Extract GT render power state management") dropped the "if (rps->interrupts_enabled)" guard that gen6_pm_rps_work() had around this unmask in i915_irq.c. INTEL_RPS_ACTIVE brackets the same window, since it is set in intel_rps_unpark() before rps_enable_interrupts() and rps_start_timer() and cleared in intel_rps_park() before rps_stop_timer() and rps_disable_interrupts().
Skip unmasking when RPS is no longer active (reaching unmask operation is independent of INTERRUPT mode). This does not prevent RPS operation from resuming on the next unpark. In interrupt mode, intel_rps_unpark() calls rps_enable_interrupts(), which enables and unmasks the PM interrupts. In timer mode, it calls rps_start_timer(), restarting periodic engine-busyness evaluation. The timer generates software RPS events and queues rps_work() directly, independently of PM interrupt delivery. Neither mode requires the late worker to unmask interrupts while the GT is parked
--- drivers/gpu/drm/i915/gt/intel_rps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/gt/intel_rps.c +2 -1
@@ -1874,7 +1874,8 @@ static void rps_work(struct work_struct out:spin_lock_irq (gt->irq_lock); -gen6_gt_pm_unmask_irq (gt, rps->pm_events); +if (intel_rps_is_active (rps)) +gen6_gt_pm_unmask_irq (gt, rps->pm_events);spin_unlock_irq (gt->irq_lock); }
Greg Kroah-Hartman
maintainerPATCH 477/1887 drm/vc4: drain the hangcheck timer and works on V3D unbind
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 94cf5971b1d04c6382437387c4dc3836cc7a1437 upstream.
Nothing stops the hangcheck timer that submitted jobs arm, or the job_done_work that the render-done interrupt queues, at teardown:vc4_irq_disable() cancels only overflow_mem_work, and vc4_gem_destroy() runs from the drm-managed release, after vc4_v3d_unbind() has already uninstalled the V3D interrupt and cleared vc4->v3d. A timer still armed by then reads V3D registers through the NULL vc4->v3d pointer, and the late callbacks run on the vc4_dev embedding them after it has been freed.
Drain them in vc4_v3d_unbind(): shut the timer down and cancel reset_work before the interrupt is taken down, because its vc4_irq_reset() re-enables it, then flush job_done_work so that completions queued at teardown still release their jobs.
This issue was found by an in-house static analysis tool.
--- drivers/gpu/drm/vc4/vc4_v3d.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/vc4/vc4_v3d.c +8 -0
@@ -9,6 +9,7 @@#include <linux/component.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/timer.h> #include "vc4_drv.h" #include "vc4_regs.h"
@@ -513,8 +514,15 @@ static void vc4_v3d_unbind(struct devicestruct drm_device *drm =dev_get_drvdata (master);struct vc4_dev *vc4 =to_vc4_dev (drm); +/* A straggler vc4_reset() re-enables the interrupt. */ +timer_shutdown_sync (&vc4->hangcheck.timer); +cancel_work_sync (&vc4->hangcheck.reset_work); +vc4_irq_uninstall (drm); +/* Flush rather than cancel, so queued completions release their jobs. */ +flush_work (&vc4->job_done_work); +/* Disable the binner's overflow memory address, so the next * driver probe (if any) doesn't try to reuse our old * allocation.
Greg Kroah-Hartman
maintainerPATCH 478/1887 drm/amdgpu: make Mac FB workaround generic
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit c7f44ec5c4ec760e74351f1843dcb8322f67cbf6 upstream.
Rather than adding a case of every chip where this is seen just check if the FB is at 0 and the ssid is apple. This should cover all chips which fall into this case.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +7 -10
@@ -652,20 +652,17 @@ void amdgpu_gmc_get_vbios_allocations(stcase CHIP_RENOIR : adev->mman.keep_stolen_vga_memory = true;break ; -case CHIP_POLARIS10 : -case CHIP_POLARIS11 : -case CHIP_POLARIS12 : -/* MacBookPros with switchable graphics put VRAM at 0 when -* the iGPU is enabled which results in cursor issues if -* the cursor ends up at 0. Reserve vram at 0 in that case. -*/ -if (adev->gmc.vram_start ==0 ) - adev->mman.keep_stolen_vga_memory = true; -break ;default : adev->mman.keep_stolen_vga_memory = false;break ; } +/* MacBookPros with switchable graphics put VRAM at 0 when +* the iGPU is enabled which results in cursor issues if +* the cursor ends up at 0. Reserve vram at 0 in that case. +*/ +if ((adev->pdev->subsystem_vendor ==PCI_VENDOR_ID_APPLE ) && + (adev->gmc.vram_start ==0 )) + adev->mman.keep_stolen_vga_memory = true;if (amdgpu_sriov_vf (adev) || !amdgpu_device_has_display_hardware (adev)) {
Greg Kroah-Hartman
maintainerPATCH 479/1887 fs: refuse fspick() on internal superblocks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 02587a4af82adccaef8e3b3624b4e7f1c401632d upstream.
There's a few instances where a internal superblock is reachable by fspick(). Block that. graft_tree() and fsmount() already refuse them. fanotify refuses mount and superblock marks on them for the same reason.
--- fs/fsopen.c | 3 +++ 1 file changed, 3 insertions(+)
fs/fsopen.c +3 -0
@@ -191,6 +191,9 @@ SYSCALL_DEFINE3(fspick, int, dfd, const ret = -EINVAL ;if (target.mnt->mnt_root != target.dentry) goto err_path; +/* kernel-internal superblocks are nobody's to reconfigure */ +if (target.dentry->d_sb->s_flags &SB_NOUSER ) + goto err_path; fc =fs_context_for_reconfigure (target.dentry,0 ,0 );if (IS_ERR (fc)) {
Greg Kroah-Hartman
maintainerPATCH 480/1887 namespace: check a submount for references right before unmounting it
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 32bf92416614a1e3ff3524fc6b780259c7aad3ef upstream.
shrink_submounts() and mark_mounts_for_expiry() first collect all the mounts they are allowed to unmount and then unmount them.
Whether a mount is busy is decided by propagate_mount_busy() on the tree. But unmounting the first mount changes the tree that the second one propagates into. propagate_umount()
moves a surviving overmount off a copy it unmounts and mounts it where the copy was mounted. If that's where the propagated copy of the second victim is looked up the overmount becomes a candidate of the second umount_tree(). It's childless and so trim_one() commits it without looking at its reference count.
So a synchronous umount pulls out a busy mount that is in use somewhere else and marks it MNT_SYNC_UMOUNT while it has users:
umount2(/tmp/plshrink/p1, 0) = 0 errno 0
cwd is (unreachable)
The same two umounts requested one after the other fail with EBUSY. This needs a mount with MNT_SHRINKABLE, i.e., automounted submounts of NFS, AFS and CIFS or the tracefs mount below debugfs. Bind mounts inherit the flag.
Check each mount right before it is unmounted under the same hold of namespace_sem and mount_lock as the umount itself. Make sure that the algorithm stays linear.
--- fs/namespace.c | 78 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 25 deletions(-)
fs/namespace.c +53 -25
@@ -3198,6 +3198,11 @@ void mark_mounts_for_expiry(struct list_ }while (!list_empty (&graveyard)) { mnt = list_first_entry(&graveyard, struct mount, mnt_expire); +/* an earlier umount_tree() may have moved a busy mount here */ +if (propagate_mount_busy (mnt,1 )) { +list_move (&mnt->mnt_expire, mounts); +continue ; + }touch_mnt_namespace (mnt->mnt_ns);umount_tree (mnt,UMOUNT_PROPAGATE |UMOUNT_SYNC ); }
@@ -3208,16 +3213,36 @@ void mark_mounts_for_expiry(struct list_EXPORT_SYMBOL_GPL (mark_mounts_for_expiry);/* +* Unmount @mnt if it's a shrinkable mount without children that nobody uses. +* +* mount_lock must be held for write +*/ +static bool shrink_submount (struct mount *mnt) +{ +if (propagate_mount_busy (mnt,1 )) +return false; +touch_mnt_namespace (mnt->mnt_ns); +umount_tree (mnt,UMOUNT_PROPAGATE |UMOUNT_SYNC ); +return true; +} + +/* * Ripoff of 'select_parent()' * -* search the list of submounts for a given mountpoint, and move any -* shrinkable submounts to the 'graveyard' list. +* unmount the shrinkable submounts of @parent that aren't busy, children +* before their parent, and say whether anything went +* +* The cursor into the children of @this_parent survives the umount of a +* child mount without child mounts. The mounts that get umounted together with +* it are located under receiving mounts of @this_parent and never under +* @this_parent itself. The one exception is @this_parent getting unmounted +* then the walk starts over. */ -static int select_submounts (struct mount *parent,struct list_head *graveyard) +static bool __shrink_submounts (struct mount *parent) {struct mount *this_parent = parent;struct list_head *next; -int found =0 ; +bool shrunk = false; repeat: next = this_parent->mnt_mounts.next;
@@ -3236,42 +3261,45 @@ resume: this_parent = mnt; goto repeat; } - -if (!propagate_mount_busy (mnt,1 )) { -list_move_tail (&mnt->mnt_expire, graveyard); - found++; - } +if (!shrink_submount (mnt)) +continue ; + shrunk = true; +if (unlikely (this_parent->mnt.mnt_flags &MNT_UMOUNT )) +return true; }/* * All done at this level ... ascend and resume the search */ if (this_parent != parent) { - next = this_parent->mnt_child.next; - this_parent = this_parent->mnt_parent; +struct mount *mnt = this_parent; + + next = mnt->mnt_child.next; + this_parent = mnt->mnt_parent; +/* its children are gone, maybe it can go as well */ +if (shrink_submount (mnt)) { + shrunk = true; +if (unlikely (this_parent->mnt.mnt_flags &MNT_UMOUNT )) +return true; + } goto resume; } -return found; +return shrunk; }/* -* process a list of expirable mountpoints with the intent of discarding any -* submounts of a specific parent mountpoint +* unmount the shrinkable submounts of @mnt that aren't busy +* +* The busy check and the umount of a mount are adjacent. An umount can +* still empty or move a mount in a part of the tree that was walked +* already, so walk again until nothing goes. * * mount_lock must be held for write */ static void shrink_submounts (struct mount *mnt) { -LIST_HEAD (graveyard); -struct mount *m; - -/* extract submounts of 'mountpoint' from the expiration list */ -while (select_submounts (mnt, &graveyard)) { -while (!list_empty (&graveyard)) { - m = list_first_entry(&graveyard, struct mount, - mnt_expire); -touch_mnt_namespace (m->mnt_ns); -umount_tree (m,UMOUNT_PROPAGATE |UMOUNT_SYNC ); - } +for (;;) { +if (!__shrink_submounts (mnt)) +break ; } }
Greg Kroah-Hartman
maintainerPATCH 481/1887 dcache: dont put a mountpoint on a dentry thats being removed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 75f4197f1e11d2eb75c2d6f916a7d4764db621e5 upstream.
rmdir(), unlink() and rename() call dont_mount() on the victim and then detach_mounts() with the victim's inode locked. do_lock_mount() takes the inode lock of the mountpoint and checks cant_mount() so a mount can't show up after detach_mounts().
But attach_recursive_mnt() makes a second mountpoint for the root of the source mount so that the mounts already located at the destination can be put on top of it. No inode is locked for that one and d_set_mounted() only refuses a dentry that is unlinked. Between detach_mounts() and d_delete() the victim is still hashed:
rmrace: b passed dont_mount() and detach_mounts(), sleeping
T2: move_mount(S, /tmp/plcant/x, BENEATH) = 0 errno 0 ()
T1: rmdir(/tmp/plcant/d/b) = 0 errno 0
109 107 0:61 /d/b//deleted /tmp/plcant/x rw,relatime - tmpfs tmpfs rw
108 109 0:63 / /tmp/plcant/x rw,relatime - tmpfs T rwA bind mount of the directory that's being removed is moved beneath an existing mount while the rmdir() is located between the two calls. The mount ends up on the removed directory and nothing will ever detach it.
Check cant_mount() in d_set_mounted() as well. dont_mount() raises the flag under d_lock before detach_mounts() runs so either the mountpoint is set first and detach_mounts() finds the mount or the flag is seen and the mount is refused.
--- fs/dcache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/dcache.c +3 -1
@@ -1502,6 +1502,8 @@ EXPORT_SYMBOL(path_has_submounts);* * Only one of d_invalidate() and d_set_mounted() must succeed. For * this reason take rename_lock and d_lock on dentry and ancestors. +* Likewise for dont_mount() which marks a dentry that is being removed +* under d_lock. */ int d_set_mounted (struct dentry *dentry) {
@@ -1518,7 +1520,7 @@ int d_set_mounted(struct dentry *dentry)spin_unlock (&p->d_lock); }spin_lock (&dentry->d_lock); -if (!d_unlinked (dentry)) { +if (!d_unlinked (dentry) && !cant_mount (dentry)) { ret = -EBUSY ;if (!d_mountpoint (dentry)) { dentry->d_flags |=DCACHE_MOUNTED ;
Greg Kroah-Hartman
maintainerPATCH 482/1887 namespace: refuse an automount below a mount that is in no namespace
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit ba985ce08471c555af2a2fbe217c1bc2e72a6d8c upstream.
It's possible to add autmounts even when the parent mount isn't in the mount namespace of the caller. The only requirement we have is that the parent mount namespace must not be NULL, i.e., unmounted.
Problem is that clone_private_mount() has MNT_NS_INTERNAL which makes that trivially true. So that passes the test and attach_recursive_mnt() accepts that as a mount point and funny enough, count_mounts() dereferences MNT_NS_INTERNAL. The problem is it is an error pointer...
So we can reach this in userspace via fanotify. A filesystem mark on the lower filesystem of an overlay reports paths on the layer clone and reading the event hands out a descriptor on it. For example with debugfs as the lower layer it goes kaboom:
openat(evfd, "tracing", O_DIRECTORY)
Oops: general protection fault KASAN: null-ptr-deref in range [0x1d0-0x1d7] RIP: 0010:count_mounts+0x35/0x200 attach_recursive_mnt finish_automount
And since that sleeping beauty happens under namespace_sem held for writing every mount operation on the system blocks from then on. Congrats.
Use is_mounted() instead which rejects unmounted and internal mounts alike. The open fails with EINVAL just as it did before clone_private_mount() used MNT_NS_INTERNAL.
--- fs/namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/namespace.c +1 -1
@@ -2965,7 +2965,7 @@ static int do_add_mount(struct mount *neif (!(mnt_flags &MNT_SHRINKABLE ))return -EINVAL ;/* ... and for those we'd better have mountpoint still alive */ -if (!parent->mnt_ns) +if (!is_mounted (&parent->mnt))return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 483/1887 drm/dp: dont mark the AUX backlight enabled when enabling failed
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Keri <[email protected]>
[ Upstream commit 707ce102521496c67860d81221b20c56d8255f2f ]
If drm_edp_backlight_enable() fails, dp_aux_backlight_update_status() still marks the backlight as enabled. From then on every brightness change only updates the level and the enable is never retried, so the panel stays dark until something blanks and unblanks the backlight.
Return the error instead, so the next update tries to enable again.
--- drivers/gpu/drm/display/drm_dp_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/display/drm_dp_helper.c +3 -1
@@ -3843,7 +3843,9 @@ static int dp_aux_backlight_update_status(struct backlight_device *bd)if (!backlight_is_blank (bd)) {if (!bl->enabled) { -drm_edp_backlight_enable (bl->aux, &bl->info, brightness); + ret =drm_edp_backlight_enable (bl->aux, &bl->info, brightness); +if (ret) +return ret; bl->enabled = true;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 484/1887 gpio: exar: initialize the ID before registering its cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Hoon Choi <[email protected]>
[ Upstream commit 4d69e74034b208588636ecc177e0dd43a7696af3 ]
devm_add_action_or_reset() invokes the cleanup action immediately when registering the action fails. gpio_exar_probe() currently stores the allocated ID in exar_gpio only after registering the action, so that failure makes exar_devm_ida_free() release ID 0. If the allocated ID is nonzero, this leaks that ID and can free ID 0 belonging to another device.
Store the ID before registering the cleanup action so both the immediate failure path and normal device teardown release the correct allocation.
--- drivers/gpio/gpio-exar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-exar.c +1 -1
@@ -196,6 +196,7 @@ static int gpio_exar_probe(struct platform_device *pdev) index =ida_alloc (&ida_index,GFP_KERNEL );if (index <0 )return index; + exar_gpio->index = index; ret =devm_add_action_or_reset (dev, exar_devm_ida_free, exar_gpio);if (ret)
@@ -211,7 +212,6 @@ static int gpio_exar_probe(struct platform_device *pdev) exar_gpio->gpio_chip.set = exar_set_value; exar_gpio->gpio_chip.base =-1 ; exar_gpio->gpio_chip.ngpio = ngpios; - exar_gpio->index = index; exar_gpio->first_pin = first_pin; ret =devm_gpiochip_add_data (dev, &exar_gpio->gpio_chip, exar_gpio);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 485/1887 drm/aspeed: Balance the display clock enable on teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit ecce445c6489895463b7ddec2af66338287fee4c ]
aspeed_gfx_load() enables the display clock without checking the return value and never disables it on probe failure or removal. devm_clk_get() only releases the clock reference, leaving the enable unbalanced.
Use devm_clk_get_enabled() to handle enable failures and automatically disable and unprepare the clock on probe failure or removal.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +2 -3
@@ -194,13 +194,12 @@ static int aspeed_gfx_load(struct drm_device *drm) }reset_control_deassert (priv->rst); - priv->clk =devm_clk_get (drm->dev,NULL ); + priv->clk =devm_clk_get_enabled (drm->dev,NULL );if (IS_ERR (priv->clk)) {dev_err (&pdev->dev, -"missing or invalid clk device tree entry" ); +"failed to get and enable clock\n" );return PTR_ERR (priv->clk); } -clk_prepare_enable (priv->clk);/* Sanitize control registers */ writel (0 , priv->base +CRT_CTRL1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 486/1887 drm/vc4: Free the BO cache size list on teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit b41ff8b529278216cba22a5dcdc93fea2a3a9619 ]
vc4_bo_cache_destroy() purges the cached BOs but never frees the size list, leaking it on every unbind.
--- drivers/gpu/drm/vc4/vc4_bo.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/vc4/vc4_bo.c +1 -0
@@ -1054,6 +1054,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)cancel_work_sync (&vc4->bo_cache.time_work);vc4_bo_cache_purge (dev); +kfree (vc4->bo_cache.size_list);for (i =0 ; i < vc4->num_labels; i++) {if (vc4->bo_labels[i].num_allocated) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 487/1887 net/sched: em_text: reject unterminated algo before autoload
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit c9728fcf2e7fb4a7a8d08ebd9524c3b02ae1a021 ]
This is a follow-up to commit 9c572a83037a ("net/sched: fix potential stack infoleak in em_text_dump()"), which zero-initialised the dump-side struct. Sashiko pointed at a pre-existing bug that exposed the change-side input-validation gap open.
em_text_change() casts the raw netlink attribute payload to struct tcf_em_text and passes conf->algo, a 16-byte array with no enforced NUL terminator, to textsearch_prepare(). On the TS_AUTOLOAD retry textsearch_prepare() calls request_module("ts_%s", algo); vsnprintf() walks %s until it finds a NUL, so an algo[] with no NUL reads past the array into the adjacent struct fields and payload and feeds those bytes to the usermode helper command line. This is an out-of-bounds read and a kernel memory disclosure.
Reject the attribute when no NUL exists within TC_EM_TEXT_ALGOSIZ bytes, matching the check xt_string has had since 3ab720881b6e.
Conditions to recreate the bug:
- CAP_NET_ADMIN on the target netns (namespace-local via unshare -Urn is enough)
- install clsact on an interface, then add a basic filter with one text ematch whose algo[] is 16 bytes with no NUL (e.g. "A"*16) and pattern_len at least 1
- the add fails with -ENOENT and the kernel invokes modprobe with a module name made of "ts_" plus the 16 bytes and the adjacent payload
--- net/sched/em_text.c | 3 +++ 1 file changed, 3 insertions(+)
net/sched/em_text.c +3 -0
@@ -58,6 +58,9 @@ static int em_text_change(struct net *net, void *data, int len,if (len <sizeof (*conf) || len < (sizeof (*conf) + conf->pattern_len))return -EINVAL ; +if (!memchr (conf->algo,'\0' ,sizeof (conf->algo))) +return -EINVAL ; +if (conf->from_layer > conf->to_layer)return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 488/1887 amt: send the relays General Query directly from the receive path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Omar Ramadan <[email protected]>
[ Upstream commit afae89de73dd693cfa329580ba0fba63bd3f0a11 ]
An skb queued in a qdisc can outlive the tunnel it references through a raw pointer in skb->cb. For example, with igmp_qrv set to 1 on the relay a tunnel lives for 135s, so a netem delay of 180s on the amt device outlives it; when the tunnel expires and is freed, the subsequent dequeue triggers a use-after-free in amt_dev_xmit().
BUG: KASAN: slab-use-after-free in amt_dev_xmit+0x2763/0x2e20 Call Trace: amt_dev_xmit+0x2763/0x2e20 [drivers/net/amt.c:1262] dev_hard_start_xmit+0x22f/0x620 sch_direct_xmit+0x12e/0xac0 netem_dequeue+0x333/0xc50 net_tx_action+0x35c/0xa60
amt_send_igmp_gq() and amt_send_mld_gq() are only called from amt_request_handler(), inside the rcu_read_lock_bh() section of amt_rcv(). amt_request_handler() already has the tunnel the query is
for: it found or created it inside that section. Queuing the query with dev_queue_xmit() only leads back into amt_dev_xmit(), which strips the Ethernet header and calls amt_send_membership_query() for that tunnel.
Make that call directly from the two senders instead, the same way amt_send_advertisement() transmits from the receive path. The query never waits in a qdisc, the tunnel is only dereferenced inside the RCU section that found or created it, and nothing is stored in skb->cb, so no lookup or refcount is needed. Remove the query branch of amt_dev_xmit(), amt_skb_cb() and struct amt_skb_cb, which have no users left.
Behaviour changes:
- The relay's own General Queries no longer pass through the amt device's egress path: its qdisc, tc egress (clsact/tcx), the netfilter egress hook and packet taps. They are still visible as UDP on the underlay.
- A query that is sent successfully is no longer counted as tx_dropped. The old query branch left through the unlock label, which counted every sent query as dropped.
- A query that reaches amt_dev_xmit() on a relay from elsewhere, such as a userspace querier, is now dropped at the IGMP/MLD type switch. Before, it trusted whatever skb->cb held, and a NULL tunnel hit the WARN_ON(1).
--- drivers/net/amt.c | 48 +++++++++++++++-------------------------------- include/net/amt.h | 4 ---- 2 files changed, 15 insertions(+), 37 deletions(-)
drivers/net/amt.c +15 -33
@@ -78,15 +78,6 @@ static struct in6_addr mld2_all_node = MLD2_ALL_NODE_INIT;static struct mld2_grec mldv2_zero_grec;#endif -static struct amt_skb_cb *amt_skb_cb (struct sk_buff *skb) -{ -BUILD_BUG_ON (sizeof (struct amt_skb_cb ) +sizeof (struct tc_skb_cb ) > - sizeof_field(struct sk_buff, cb)); - -return (struct amt_skb_cb *)((void *)skb->cb + -sizeof (struct tc_skb_cb )); -} -static void __amt_source_gc_work (void ) {struct amt_source_node *snode;
@@ -787,6 +778,11 @@ static void amt_send_request(struct amt_dev *amt, bool v6)rcu_read_unlock (); } +static bool amt_send_membership_query (struct amt_dev *amt, +struct sk_buff *skb, +struct amt_tunnel_list *tunnel, +bool v6); +static void amt_send_igmp_gq (struct amt_dev *amt,struct amt_tunnel_list *tunnel) {
@@ -796,8 +792,11 @@ static void amt_send_igmp_gq(struct amt_dev *amt,if (!skb)return ; -amt_skb_cb (skb)->tunnel = tunnel; -dev_queue_xmit (skb); +skb_pull (skb,sizeof (struct ethhdr )); +if (amt_send_membership_query (amt, skb, tunnel, false)) { + amt->dev->stats.tx_dropped++; +kfree_skb (skb); + } }#if IS_ENABLED (CONFIG_IPV6 )
@@ -881,8 +880,11 @@ static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)if (!skb)return ; -amt_skb_cb (skb)->tunnel = tunnel; - dev_queue_xmit(skb); +skb_pull (skb,sizeof (struct ethhdr )); +if (amt_send_membership_query (amt, skb, tunnel, true)) { + amt->dev->stats.tx_dropped++; +kfree_skb (skb); + } }#else static void amt_send_mld_gq (struct amt_dev *amt,struct amt_tunnel_list *tunnel)
@@ -1178,7 +1180,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)#endif bool report = false;struct igmphdr *ih; -bool query = false;struct iphdr *iph;bool data = false;bool v6 = false;
@@ -1196,9 +1197,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)case IGMP_HOST_MEMBERSHIP_REPORT : report = true;break ; -case IGMP_HOST_MEMBERSHIP_QUERY : - query = true; -break ;default : goto free; }
@@ -1220,9 +1218,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)case ICMPV6_MLD2_REPORT : report = true;break ; -case ICMPV6_MGM_QUERY : - query = true; -break ;default : goto free; }
@@ -1253,19 +1248,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev) goto free; goto unlock; }else if (amt->mode ==AMT_MODE_RELAY ) { -if (query) { - tunnel =amt_skb_cb (skb)->tunnel; -if (!tunnel) { -WARN_ON (1 ); - goto free; - } - -/* Do not forward unexpected query */ -if (amt_send_membership_query (amt, skb, tunnel, v6)) - goto free; - goto unlock; - } -if (!data) goto free;list_for_each_entry_rcu (tunnel, &amt->tunnel_list, list) {
include/net/amt.h +0 -4
@@ -231,10 +231,6 @@ struct amt_relay_headers { }; } __packed; -struct amt_skb_cb { -struct amt_tunnel_list *tunnel; -}; -struct amt_tunnel_list {struct list_head list;/* Protect All resources under an amt_tunne_list */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 489/1887 cxgb4/ch_ktls: disable softirqs around tid_list erases
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Hoon Choi <[email protected]>
[ Upstream commit 4c9dc0faca98084922caeb689579d338cf3e1c29 ]
chcr_ktls_cpl_act_open_rpl() inserts into tid_list from the receive path using xa_insert_bh(). The array is shared by the adapter's connections and initialized with XA_FLAGS_LOCK_BH. However, chcr_ktls_dev_del() and the chcr_ktls_dev_add() error path use xa_erase(), which takes the XArray lock without disabling softirqs.
When cleanup runs with softirqs enabled, a receive softirq for another connection on the same CPU can interrupt the erase and spin on the lock held by the interrupted task. Use xa_erase_bh() at both sites to match the insertion path.
--- .../net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c +2 -2
@@ -390,7 +390,7 @@ static void chcr_ktls_dev_del(struct net_device *netdev,cxgb4_remove_tid (&tx_info->adap->tids, tx_info->tx_chan, tx_info->tid, tx_info->ip_family); -xa_erase (&u_ctx->tid_list, tx_info->tid); +xa_erase_bh (&u_ctx->tid_list, tx_info->tid); } port_stats = &tx_info->adap->ch_ktls_stats.ktls_port[tx_info->port_id];
@@ -581,7 +581,7 @@ static int chcr_ktls_dev_add(struct net_device *netdev, struct sock *sk,cxgb4_remove_tid (&tx_info->adap->tids, tx_info->tx_chan, tx_info->tid, tx_info->ip_family); -xa_erase (&u_ctx->tid_list, tx_info->tid); +xa_erase_bh (&u_ctx->tid_list, tx_info->tid); put_module:/* release module refcount */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 490/1887 nvmet: use the local P2P device on metadata allocation failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sang-Hoon Choi <[email protected]>
[ Upstream commit 4aa9c0f377a4de5e8fddce76b34ee4529639a1ff ]
nvmet_req_alloc_p2pmem_sgls() assigns req->p2p_dev only after the data and metadata SGL allocations succeed. If the data allocation succeeds but the metadata allocation fails, out_free_sg passes req->p2p_dev to pci_p2pmem_free_sgl() before that assignment has taken place.
Pass the local p2p_dev argument instead, so cleanup uses the same PCI device as the successful data allocation.
--- drivers/nvme/target/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/target/core.c +1 -1
@@ -1053,7 +1053,7 @@ static int nvmet_req_alloc_p2pmem_sgls(struct pci_dev *p2p_dev,return 0 ; out_free_sg: -pci_p2pmem_free_sgl (req->p2p_dev, req->sg); +pci_p2pmem_free_sgl (p2p_dev, req->sg); out_err:return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 491/1887 ASoC: adau1372: allow sleepy powerdown GPIOs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alvin Šipraga <[email protected]>
[ Upstream commit 64dd172bbffe6135d79a06ddad53dd2da4d8bd62 ]
gpiod_set_value() emits a WARN when the GPIO provider indicates that it can sleep, as is typical for I2C controlled GPIO expanders. Since the powerdown GPIO is only manipulated in process context, use the _cansleep variant instead. This lets the driver use sleepy GPIOs to power off the chip.
--- sound/soc/codecs/adau1372.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
sound/soc/codecs/adau1372.c +3 -4
@@ -798,7 +798,7 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)if (ret)return ret;if (adau1372->pd_gpio) -gpiod_set_value (adau1372->pd_gpio,0 ); +gpiod_set_value_cansleep (adau1372->pd_gpio,0 );if (adau1372->switch_mode) adau1372->switch_mode (adau1372->dev);
@@ -818,8 +818,7 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)ADAU1372_CLK_CTRL_PLL_EN , 0);regcache_cache_only (adau1372->regmap, true); -if (adau1372->pd_gpio) -gpiod_set_value (adau1372->pd_gpio,1 ); +gpiod_set_value_cansleep (adau1372->pd_gpio,1 );clk_disable_unprepare (adau1372->mclk);return ret; }
@@ -836,7 +835,7 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)* map. No need to do any register writes to manually * turn things off. */ -gpiod_set_value (adau1372->pd_gpio,1 ); +gpiod_set_value_cansleep (adau1372->pd_gpio,1 );regcache_mark_dirty (adau1372->regmap); }else { regmap_update_bits(adau1372->regmap, ADAU1372_REG_CLK_CTRL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 492/1887 ASoC: adau1372: fix invalid default state of output ASRC and DAC muxes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alvin Šipraga <[email protected]>
[ Upstream commit 36d0e05815ce84266c8b138cd4f84c3feeaf15f4 ]
The chip has strange power-on reset values for the registers that control the output ASRC and DAC source muxes - the values are actually marked "Reserved" in the datasheet [1]. This means that until the underlying kcontrols are modified, the codec will not function as expected.
The registers in question are:
register / field reset value valid values
ASRCO_SOURCE_0_1 0x10 ASRC_OUT_SOURCE0 0 4 .. 16 ASRC_OUT_SOURCE1 1 4 .. 16 ASRCO_SOURCE_2_3 0x10 ASRC_OUT_SOURCE2 2 4 .. 16 ASRC_OUT_SOURCE3 3 4 .. 16 DAC_SOURCE_0_1 0x10 DAC_SOURCE_0 0 12 .. 13 DAC_SOURCE_1 1 12 .. 13
Set some sane defaults during the driver probe:
ADC Decimator0 -> Output ASRC0
ADC Decimator1 -> Output ASRC1
ADC Decimator2 -> Output ASRC2
ADC Decimator3 -> Output ASRC3
Input ASRC0 -> DAC0
Input ASRC1 -> DAC1
With this, the chip will behave as advertised by the default kcontrol state exposed by the driver.
[1] https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1372.pdf
--- sound/soc/codecs/adau1372.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
sound/soc/codecs/adau1372.c +11 -0
@@ -1000,6 +1000,17 @@ int adau1372_probe(struct device *dev, struct regmap *regmap,regmap_write (regmap,ADAU1372_REG_OP_STAGE_MUTE ,0x0 ); +/* +* Set sane default values for the Output ASRC and DAC input muxes, +* since the power-on reset defaults are invalid "Reserved" states. +*/ +regmap_write (regmap,ADAU1372_REG_ASRCO_SOURCE_0_1 , +0x54 );/* Decimator0, Decimator1 */ +regmap_write (regmap,ADAU1372_REG_ASRCO_SOURCE_2_3 , +0x76 );/* Decimator2, Decimator3 */ +regmap_write (regmap,ADAU1372_REG_DAC_SOURCE , +0xdc );/* Input ASRC0, Input ASRC1 */ +regmap_write (regmap,0x7 ,0x01 );/* CLOCK OUT */ return devm_snd_soc_register_component (dev, &adau1372_driver, &adau1372_dai_driver,1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 493/1887 ASoC: samsung: i2s: enable op_clk in probe to balance runtime PM
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Szyprowski <[email protected]>
[ Upstream commit 7529254014764ae0b8c33d5c61a58f36c65b1a1c ]
The probe function puts the device into the runtime PM active state with only the "iis" bus clock enabled, but it also sets priv->op_clk to the parent of the RCLK_SRC mux without enabling it. The runtime PM suspend callback disables both clocks, so the first runtime suspend after probe disables op_clk once more than it was enabled.
On Exynos5250 Arndale both clocks resolve to the same EXYNOS_I2S_BUS gate, so this triggers the following warning during boot:
WARNING: drivers/clk/clk.c:1270 at clk_core_disable+0xe4/0x23c, CPU#0: kworker/u8:3/45 i2s_bus already disabled ... Workqueue: pm pm_runtime_work Call trace: ... clk_core_disable from clk_disable+0x28/0x34 clk_disable from i2s_runtime_suspend+0x58/0x68 [snd_soc_i2s] i2s_runtime_suspend [snd_soc_i2s] from genpd_runtime_suspend+0xc4/0x298 genpd_runtime_suspend from __rpm_callback+0x48/0x18c __rpm_callback from rpm_callback+0x4c/0x50 rpm_callback from rpm_suspend+0xf4/0x718 rpm_suspend from pm_runtime_work+0x9c/0xa0 ...
Fix this by enabling op_clk in probe right after getting it, so the clock state matches the runtime PM active state, and by disabling it in remove.
--- sound/soc/samsung/i2s.c | 8 ++++++++ 1 file changed, 8 insertions(+)
sound/soc/samsung/i2s.c +8 -0
@@ -1531,9 +1531,16 @@ static int samsung_i2s_probe(struct platform_device *pdev) goto err_disable_pm; priv->op_clk =clk_get_parent (priv->clk_table[CLK_I2S_RCLK_SRC ]); + ret =clk_prepare_enable (priv->op_clk); +if (ret <0 ) { + priv->op_clk =NULL ; + goto err_unregister_clk; + }return 0 ; +err_unregister_clk: +i2s_unregister_clock_provider (priv); err_disable_pm:pm_runtime_disable (&pdev->dev); err_del_sec:
@@ -1556,6 +1563,7 @@ static int samsung_i2s_remove(struct platform_device *pdev)i2s_unregister_clock_provider (priv);i2s_delete_secondary_device (priv); +clk_disable_unprepare (priv->op_clk);clk_disable_unprepare (priv->clk);pm_runtime_put_noidle (&pdev->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 494/1887 flow_dissector: avoid u16 truncation of skb->len when computing thoff
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 99bda1ecbd56905f8bd934b9cdccd3bd251192b1 ]
__skb_flow_dissect() computes key_control->thoff using:
key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
min_t(u16, ...) casts both arguments to u16 before comparing them. Whenever skb->len (or hlen) modulo 65536 is smaller than nhoff, the truncated length wins and thoff is set to a bogus small value, even when the dissection succeeded. For example, an IPv4/TCP frame with skb->len == 65540 and nhoff == 34 gets thoff == 4, so callers such as skb_probe_transport_header() point the transport header inside the Ethernet header.
Such skbs are not exotic:
- At the time of commit d0c081b49137 ("flow_dissector: properly cap thoff field"), AF_PACKET with PACKET_VNET_HDR could already build GSO skbs larger than 64KB (MTU checks are skipped for GSO, and alloc_skb_with_frags() accepted up to MAX_SKB_FRAGS (17) order-0 pages on top of the linear part).
- BIG TCP now makes skbs larger than 64KB common.
- The following patch makes tun_get_user() dissect IFF_TAP frames before eth_type_trans() pulls the Ethernet header, so a GSO frame carrying a 65522..65535 byte L3 packet will be dissected with skb->len in [65536, 65549].
Compare as u32 instead. If the resulting offset cannot be represented in the u16 key_control->thoff, cap it to U16_MAX and report the dissection as failed rather than silently returning a wrong transport offset. thoff is still set on failure, as some callers (such as eth_get_headlen()) use it regardless of the return value.
--- net/core/flow_dissector.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/core/flow_dissector.c +8 -1
@@ -969,6 +969,7 @@ bool __skb_flow_dissect(const struct net *net,int mpls_lse =0 ;int num_hdrs =0 ;u8 ip_proto =0 ; +u32 thoff;bool ret;if (!data) {
@@ -1575,7 +1576,13 @@ bool __skb_flow_dissect(const struct net *net, ret = true; out: - key_control->thoff =min_t (u16, nhoff, skb ? skb->len : hlen); + thoff =min_t (u32, nhoff, skb ? skb->len : hlen); +if (unlikely (thoff >U16_MAX )) { +/* Cannot be represented in key_control->thoff. */ + thoff =U16_MAX ; + ret = false; + } + key_control->thoff = thoff; key_basic->n_proto = proto; key_basic->ip_proto = ip_proto;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 495/1887 flow_dissector: avoid u16 truncation of hlen in bpf_flow_dissect()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit f202578efc738b883cfa04889eb97328914265a7 ]
bpf_flow_dissect() sanitizes the offsets returned by the BPF program with clamp_t(u16, ..., hlen).
If hlen is bigger than 65535, the upper bound is truncated before the comparison. For instance, with hlen == 65536, both nhoff and thoff are forced to zero, even if the program returned sane values.
This is the same class of bug as the one fixed in commit 99bda1ecbd56 ("flow_dissector: avoid u16 truncation of skb->len when computing thoff"). That fix does not cover the BPF path, because __skb_flow_dissect() returns early when a BPF flow dissector handles the packet.
struct bpf_flow_keys stores nhoff and thoff as u16, so cap hlen to U16_MAX before clamping.
Found by sashiko while reviewing the commit above.
--- net/core/flow_dissector.c | 2 ++ 1 file changed, 2 insertions(+)
net/core/flow_dissector.c +2 -0
@@ -921,6 +921,8 @@ u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, result =bpf_prog_run_pin_on_cpu (prog, ctx); +/* bpf_flow_keys offsets are u16: do not let @hlen be truncated. */ + hlen =min_t (int, hlen,U16_MAX ); flow_keys->nhoff =clamp_t (u16, flow_keys->nhoff, nhoff, hlen); flow_keys->thoff =clamp_t (u16, flow_keys->thoff, flow_keys->nhoff, hlen);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 496/1887 net/mlx5e: Order ICOSQ cc update after CQ doorbell
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit b056ca4d3742d0769f91137bb1ce3215428398f7 ]
mlx5e_poll_ico_cq() requires sq->cc to be updated only after mlx5_cqwq_update_db_record(), otherwise a CQ overrun may occur.
The current implementation updates sq->cc before the CQ doorbell record, violating this ordering requirement.
Update the CQ doorbell record first and use dma_wmb() before updating sq->cc. This ensures that the CQ space is released to the device before the corresponding ICOSQ consumer index is updated by software.
--- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +4 -2
@@ -931,10 +931,12 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq) }while (!last_wqe); }while ((++i <MLX5E_TX_CQ_POLL_BUDGET ) && (cqe =mlx5_cqwq_get_cqe (&cq->wq))); - sq->cc = sqcc; -mlx5_cqwq_update_db_record (&cq->wq); +/* ensure cq space is freed before enabling more cqes */ +dma_wmb (); + + sq->cc = sqcc;return i; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 497/1887 net: openvswitch: validate transport header presence in set_ipv6_addr
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 3c6a4b11330fe424557538a98fca9f0a4c5bf313 ]
When executing IPv6 address rewrite actions on IPv6 fragments, set_ipv6_addr() calls update_ipv6_checksum(). If parse_ipv6hdr() processes a non-first IPv6 fragment, it sets key->ip.proto to NEXTHDR_FRAGMENT and returns early without calling skb_set_transport_header().
update_ipv6_checksum() unconditionally evaluates skb_transport_offset() on entry before checking l4_proto. Because skb->transport_header is uninitialized, this triggers a warning under CONFIG_DEBUG_NET=y although it is completely harmless.
Fix this by returning early in update_ipv6_checksum() if l4_proto is NEXTHDR_FRAGMENT. This avoids reading the uninitialized transport offset for fragments while preserving the debug warning for any other protocol where the transport header is unexpectedly missing.
See the syzbot trace:
!skb_transport_header_was_set(skb)
WARNING: ./include/linux/skbuff.h:3075 at skb_transport_header include/linux/skbuff.h:3075 [inline], CPU#1: syz-executor463/5635 WARNING: ./include/linux/skbuff.h:3075 at skb_transport_offset include/linux/skbuff.h:3250 [inline], CPU#1: syz-executor463/5635 WARNING: ./include/linux/skbuff.h:3075 at update_ipv6_checksum net/openvswitch/actions.c:361 [inline], CPU#1: syz-executor463/5635 WARNING: ./include/linux/skbuff.h:3075 at set_ipv6_addr+0x462/0x660 net/openvswitch/actions.c:399, CPU#1: syz-executor463/5635 [...] RIP: 0010:skb_transport_header include/linux/skbuff.h:3075 [inline] RIP: 0010:skb_transport_offset include/linux/skbuff.h:3250 [inline] RIP: 0010:update_ipv6_checksum net/openvswitch/actions.c:361 [inline] RIP: 0010:set_ipv6_addr+0x462/0x660 net/openvswitch/actions.c:399 [...] Call Trace: <TASK> set_ipv6 net/openvswitch/actions.c:531 [inline] do_execute_actions+0x557e/0x8600 net/openvswitch/actions.c:1366 ovs_execute_actions+0xde/0x520 net/openvswitch/actions.c:1592 ovs_packet_cmd_execute+0xb4f/0xf10 net/openvswitch/datapath.c:705 genl_family_rcv_msg_doit+0x233/0x340 net/netlink/genetlink.c:1114 genl_rcv_msg+0x614/0x7a0 net/netlink/genetlink.c:1209 netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572 genl_rcv+0x28/0x40 net/netlink/genetlink.c:1218 netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916 sock_sendmsg_nosec+0x14e/0x190 net/socket.c:800
--- net/openvswitch/actions.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
net/openvswitch/actions.c +6 -1
@@ -380,7 +380,12 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,static void update_ipv6_checksum (struct sk_buff *skb,u8 l4_proto,__be32 addr[4 ],const __be32 new_addr[4 ]) { -int transport_len = skb->len -skb_transport_offset (skb); +int transport_len; + +if (l4_proto ==NEXTHDR_FRAGMENT ) +return ; + + transport_len = skb->len -skb_transport_offset (skb);if (l4_proto ==NEXTHDR_TCP ) {if (likely (transport_len >=sizeof (struct tcphdr )))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 498/1887 mtd: Clean refcounting with MTD_PARTITIONED_MASTER
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
commit 264725e35fbc3b67e053a405e022393a6017e6da upstream.
The logic is way too convoluted, let's clean the kref_get/put section to clarify what this block does when using CONFIG_MTD_PARTITIONED_MASTER:
- Iterate through all the parent mtd devices
- Grab a reference over them all but the master
- Only grab the master whith CONFIG_MTD_PARTITIONED_MASTER Same logic must apply in the put path, otherwise it would be broken.
--- drivers/mtd/mtdcore.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
drivers/mtd/mtdcore.c +10 -7
@@ -1221,14 +1221,15 @@ int __get_mtd_device(struct mtd_info *mtreturn -ENODEV ; } -kref_get (&mtd->refcnt); - -while (mtd->parent) { -if (IS_ENABLED (CONFIG_MTD_PARTITIONED_MASTER ) || mtd->parent != master) -kref_get (&mtd->parent->refcnt); +while (mtd) { +if (mtd != master) +kref_get (&mtd->refcnt); mtd = mtd->parent; } +if (IS_ENABLED (CONFIG_MTD_PARTITIONED_MASTER )) +kref_get (&master->refcnt); +return 0 ; }EXPORT_SYMBOL_GPL (__get_mtd_device);
@@ -1312,10 +1313,12 @@ void __put_mtd_device(struct mtd_info *m {struct mtd_info *master =mtd_get_master (mtd); -while (mtd != master) { +while (mtd) { +/* kref_put() can relese mtd, so keep a reference mtd->parent */ struct mtd_info *parent = mtd->parent; -kref_put (&mtd->refcnt, mtd_device_release); +if (mtd != master) +kref_put (&mtd->refcnt, mtd_device_release); mtd = parent; }
Greg Kroah-Hartman
maintainerPATCH 499/1887 mtd: fix use-after-free in mtd release
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Usyskin <[email protected]>
commit e9714c22c1a8238a85d069b1517941fc723312f7 upstream.
I case of partition device_unregister() in mtd_device_release() calls mtd_release() which frees mtd_info structure for partition. All code after device_unregister in mtd_device_release thus uses already freed memory.
Move part of code to mtd_release() and restict mtd->dev cleanup to non-partion object.
For partition object such cleanup have no sense as partition mtd_info is removed.
--- drivers/mtd/mtdcore.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/mtd/mtdcore.c +11 -5
@@ -92,6 +92,9 @@ static void mtd_release(struct device *dstruct mtd_info *mtd =dev_get_drvdata (dev);dev_t index =MTD_DEVT (mtd->index); +idr_remove (&mtd_idr, mtd->index); +of_node_put (mtd_get_of_node (mtd)); +if (mtd_is_partition (mtd))release_mtd_partition (mtd);
@@ -102,6 +105,7 @@ static void mtd_release(struct device *dstatic void mtd_device_release (struct kref *kref) { struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt); +bool is_partition =mtd_is_partition (mtd);debugfs_remove_recursive (mtd->dbg.dfs_dir);
@@ -110,11 +114,13 @@ static void mtd_device_release(struct krdevice_unregister (&mtd->dev); -/* Clear dev so mtd can be safely re-registered later if desired */ -memset (&mtd->dev,0 ,sizeof (mtd->dev)); - -idr_remove (&mtd_idr, mtd->index); -of_node_put (mtd_get_of_node (mtd)); +/* +* Clear dev so mtd can be safely re-registered later if desired. +* Should not be done for partition, +* as it was already destroyed in device_unregister(). +*/ +if (!is_partition) +memset (&mtd->dev,0 ,sizeof (mtd->dev));module_put (THIS_MODULE ); }
Greg Kroah-Hartman
maintainerPATCH 500/1887 mtd: maps: vmu-flash: Fix the (mtd core) switch to ref counters
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <[email protected]>
commit a7d84a2e7663bbe12394cc771107e04668ea313a upstream.
While switching to ref counters for track mtd devices use, the vmu-flash driver was forgotten. The reason for reading the ref counter seems debatable, but let's just fix the build for now.
--- drivers/mtd/maps/vmu-flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/maps/vmu-flash.c +1 -1
@@ -720,7 +720,7 @@ static int vmu_can_unload(struct maple_d card =maple_get_drvdata (mdev);for (x =0 ; x < card->partitions; x++) { mtd = &((card->mtd)[x]); -if (mtd->usecount >0 ) +if (kref_read (&mtd->refcnt))return 0 ; }return 1 ;
Greg Kroah-Hartman
maintainerPATCH 501/1887 mtd: fix double free and WARN_ON in add_mtd_device() error paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xue Lei <[email protected]>
commit 9d4af746af8ce27eefc2338b2feaa1e01f28b6c3 upstream.
When device_register() or mtd_nvmem_add() fails inside add_mtd_device() for a partition, the error handling triggers mtd_release() via put_device() or device_unregister(). mtd_release() calls release_mtd_partition() which frees the mtd_info structure. However, callers such as mtd_add_partition() and add_mtd_partitions() also call free_partition() in their error paths, resulting in a double free.
Additionally, release_mtd_partition() hits WARN_ON(!list_empty( &mtd->part.node)) because the partition node is still linked in the parent's partitions list when the release callback fires from the add_mtd_device() error path.
Fix this by overriding dev->type and dev->release before put_device() in the error paths, so that device_release() invokes a no-op function instead of mtd_release(). For the mtd_nvmem_add() failure case, device_unregister() is replaced with device_del() to separate the device removal from the final kobject reference drop, allowing the override to take effect before put_device() is called.
The callers' error paths (list_del + free_partition) remain the sole owners of mtd_info lifetime on add_mtd_device() failure, which is the expected contract.
The normal partition teardown path is not affected: del_mtd_device() goes through kref_put() -> mtd_device_release() -> device_unregister() with dev->type still set to &mtd_devtype, so mtd_release() -> release_mtd_partition() continues to work correctly for the regular removal case.
--- drivers/mtd/mtdcore.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-)
drivers/mtd/mtdcore.c +19 -4
@@ -102,6 +102,15 @@ static void mtd_release(struct device *ddevice_destroy (&mtd_class, index +1 ); } +/* +* No-op device release used in add_mtd_device() error paths. +* Prevents mtd_release() from being called via device_release(), +* which would free the mtd_info that the caller still manages. +*/ +static void mtd_dev_release_nop (struct device *dev) +{ +} +static void mtd_device_release (struct kref *kref) { struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
@@ -752,10 +761,8 @@ int add_mtd_device(struct mtd_info *mtd)mtd_check_of_node (mtd);of_node_get (mtd_get_of_node (mtd)); error =device_register (&mtd->dev); -if (error) { -put_device (&mtd->dev); +if (error) goto fail_added; - }/* Add the nvmem provider */ error =mtd_nvmem_add (mtd);
@@ -782,8 +789,16 @@ int add_mtd_device(struct mtd_info *mtd)return 0 ; fail_nvmem_add: -device_unregister (&mtd->dev); +device_del (&mtd->dev); fail_added: +/* +* Clear type and set nop release to prevent mtd_release() -> +* release_mtd_partition() -> free_partition() from freeing mtd. +* The caller handles cleanup on failure. +*/ + mtd->dev.type =NULL ; + mtd->dev.release = mtd_dev_release_nop; +put_device (&mtd->dev);of_node_put (mtd_get_of_node (mtd));idr_remove (&mtd_idr, i); fail_locked:
Greg Kroah-Hartman
maintainerPATCH 502/1887 dlm: validate length in dlm_search_rsb_tree
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ezrak1e <[email protected]>
[ Upstream commit 080e5563f878c64e697b89e7439d730d0daad882 ]
The len parameter in dlm_dump_rsb_name() is not validated and comes from network messages. When it exceeds DLM_RESNAME_MAXLEN, it can cause out-of-bounds write in dlm_search_rsb_tree().
Add length validation to prevent potential buffer overflow.
[ Contextual conflict due to dlm_search_rsb_tree() using the RB-tree implementation instead of rhashtable.]
--- fs/dlm/lock.c | 2 ++ 1 file changed, 2 insertions(+)
fs/dlm/lock.c +2 -0
@@ -456,6 +456,8 @@ int dlm_search_rsb_tree(struct rb_root *tree, const void *name, int len,struct dlm_rsb *r;int rc; +if (len >DLM_RESNAME_MAXLEN ) +return -EINVAL ;while (node) { r = rb_entry(node, struct dlm_rsb, res_hashnode); rc =rsb_cmp (r, name, len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 503/1887 can: fix unique skb identifier regression under RPS
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Hartkopp <[email protected]>
commit 7093c3b8314a4ef7405c4066a2521398c455efe7 upstream.
Commit d4fb6514ff8e ("can: use skb hash instead of private variable in headroom") moved the per-skb unique identifier used for raw_rcv() duplicate detection into skb->hash.
With RPS enabled, get_rps_cpu() calls skb_get_hash() before the frame reaches the CAN subsystem. Since CAN skbs have no L3/L4 headers, the flow dissector assigns every CAN frame the same non-zero software hash. can_set_skb_uid() only generated a new identifier when skb->hash was 0, so it kept this constant hash. When the SLAB allocator later reused the same skb address, raw_rcv() mistook the next legitimate frame for a duplicate and dropped it.
Fix this by storing the CAN UID in the CAN skb extension (struct can_skb_ext::can_skb_uid) instead of skb->hash, decoupling it from any hash the network stack may compute. can_set_skb_uid() keeps its "assign only if unset" behaviour, which preserves UIDs set before transmission (e.g. by isotp to identify echo frames) across the local loopback path.
Frames whose extension is shared with another clone (e.g. via tc mirred or netem duplicate) are given a private extension copy before the UID is assigned, so that independently received skb clones from real CAN interfaces (skbcnt = 0) don't end up with the same UID.
The limitation that tc mirred/netem skb duplicates might be dropped in raw_rcv for looped back isotp echo frame skbs is accepted. There is no valid use-case for tc mirred or netem together with isotp which is not capable to operate on different CAN interfaces simultaneously. For routing and modifying CAN frames together with isotp use can-gw.
can-gw and vxcan additionally clear the UID of forwarded/duplicated frames so each newly routed frame gets its own unique identifier.
[ backport to 6.1: no CAN skb extensions available, so the UID is kept
in struct can_skb_priv::skbcnt in the headroom (effectively reverting d4fb6514ff8e) and isotp is adapted accordingly. As skb clones share the headroom, the private extension copy for tc mirred/netem duplicates is not applicable. The UID resets in can-gw and vxcan are omitted, as writing to the shared headroom of cloned skbs would also alter the UID of the original skb. This keeps the pre-d4fb6514ff8e behaviour for routed and vxcan forwarded frames. ]
--- drivers/net/can/dev/skb.c | 2 ++ include/linux/can/skb.h | 2 ++ net/can/af_can.c | 6 ++---- net/can/bcm.c | 2 ++ net/can/isotp.c | 11 +++++++---- net/can/j1939/socket.c | 1 + net/can/j1939/transport.c | 2 ++ net/can/raw.c | 7 ++++--- 8 files changed, 22 insertions(+), 11 deletions(-)
drivers/net/can/dev/skb.c +2 -0
@@ -202,6 +202,7 @@ static void init_can_skb_reserve(struct sk_buff *skb)skb_reset_transport_header (skb);can_skb_reserve (skb); +can_skb_prv (skb)->skbcnt =0 ; }struct sk_buff *alloc_can_skb (struct net_device *dev,struct can_frame **cf)
@@ -311,6 +312,7 @@ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)if (skb->ip_summed ==CHECKSUM_NONE ) {/* init headroom */ can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ; skb->ip_summed =CHECKSUM_UNNECESSARY ;
include/linux/can/skb.h +2 -0
@@ -49,11 +49,13 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);/** * struct can_skb_priv - private additional data inside CAN sk_buffs * @ifindex: ifindex of the first interface the CAN frame appeared on +* @skbcnt: atomic counter to have an unique id together with skb pointer * @frame_len: length of CAN frame in data link layer * @cf: align to the following CAN frame at skb->data */ struct can_skb_priv {int ifindex; +u32 skbcnt;unsigned int frame_len;struct can_frame cf[]; };
net/can/af_can.c +2 -4
@@ -643,10 +643,8 @@ static int can_rcv_filter(struct can_dev_rcv_lists *dev_rcv_lists, struct sk_bufvoid can_set_skb_uid (struct sk_buff *skb) {/* create non-zero unique skb identifier together with *skb */ -while (!(skb->hash)) - skb->hash =atomic_inc_return (&skbcounter); - - skb->sw_hash =1 ; +while (!(can_skb_prv (skb)->skbcnt)) +can_skb_prv (skb)->skbcnt =atomic_inc_return (&skbcounter); }EXPORT_SYMBOL (can_set_skb_uid);
net/can/bcm.c +2 -0
@@ -338,6 +338,7 @@ static void bcm_can_tx(struct bcm_op *op, struct canfd_frame *cf)can_skb_reserve (skb);can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;skb_put_data (skb, cf, op->cfsiz);
@@ -1581,6 +1582,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk, }can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ; skb->dev = dev;can_skb_set_owner (skb, sk); err =can_send (skb,1 );/* send with loopback */
net/can/isotp.c +7 -4
@@ -287,6 +287,7 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus)can_skb_reserve (nskb);can_skb_prv (nskb)->ifindex = dev->ifindex; +can_skb_prv (nskb)->skbcnt =0 ; nskb->dev = dev;can_skb_set_owner (nskb, sk);
@@ -848,6 +849,7 @@ static void isotp_send_cframe(struct isotp_sock *so)can_skb_reserve (skb);can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;/* set uid in tx skb to identify CF echo frames */ can_set_skb_uid (skb);
@@ -876,7 +878,7 @@ static void isotp_send_cframe(struct isotp_sock *so)pr_notice_once ("can-isotp: cfecho is %08X != 0\n" , old_cfecho);/* set consecutive frame echo tag */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho,can_skb_prv (skb)->skbcnt);/* send frame with local echo enabled */ can_send_ret =can_send (skb,1 );
@@ -939,7 +941,7 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)spin_lock (&so->rx_lock);/* so->cfecho may since belong to a new transfer; recheck under lock */ -if (READ_ONCE (so->cfecho) != skb->hash) +if (READ_ONCE (so->cfecho) !=can_skb_prv (skb)->skbcnt) goto out_unlock;/* cancel local echo timeout */
@@ -1161,6 +1163,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)can_skb_reserve (skb);can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;/* set uid in tx skb to identify CF echo frames */ can_set_skb_uid (skb);
@@ -1202,7 +1205,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) cf->data[ae] |= size;/* set CF echo tag for isotp_rcv_echo() (SF-mode) */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho,can_skb_prv (skb)->skbcnt); }else {/* send first frame */
@@ -1219,7 +1222,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) so->txfc.bs =0 ;/* set CF echo tag for isotp_rcv_echo() (CF-mode) */ -WRITE_ONCE (so->cfecho, skb->hash); +WRITE_ONCE (so->cfecho,can_skb_prv (skb)->skbcnt); }else {/* standard flow control check */ new_state =ISOTP_WAIT_FIRST_FC ;
net/can/j1939/socket.c +1 -0
@@ -895,6 +895,7 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,can_skb_reserve (skb);can_skb_prv (skb)->ifindex = ndev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;skb_reserve (skb, offsetof(struct can_frame , data)); ret =memcpy_from_msg (skb_put (skb, size), msg, size);
net/can/j1939/transport.c +2 -0
@@ -613,6 +613,7 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv, skb->dev = priv->ndev;can_skb_reserve (skb);can_skb_prv (skb)->ifindex = priv->ndev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;/* reserve CAN header */ skb_reserve (skb, offsetof(struct can_frame , data));
@@ -1552,6 +1553,7 @@ j1939_session *j1939_session_fresh_new(struct j1939_priv *priv, skb->dev = priv->ndev;can_skb_reserve (skb);can_skb_prv (skb)->ifindex = priv->ndev->ifindex; +can_skb_prv (skb)->skbcnt =0 ; skcb =j1939_skb_to_cb (skb);memcpy (skcb, rel_skcb,sizeof (*skcb));
net/can/raw.c +4 -3
@@ -75,8 +75,8 @@ MODULE_ALIAS("can-proto-1");*/ struct uniqframe { +u32 skbcnt;const struct sk_buff *skb; -u32 hash;unsigned int join_rx_count; };
@@ -140,7 +140,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)/* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr (ro->uniq)->skb == oskb && -this_cpu_ptr (ro->uniq)->hash == oskb->hash) { +this_cpu_ptr (ro->uniq)->skbcnt ==can_skb_prv (oskb)->skbcnt) {if (!ro->join_filters)return ;
@@ -150,7 +150,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)return ; }else {this_cpu_ptr (ro->uniq)->skb = oskb; -this_cpu_ptr (ro->uniq)->hash = oskb->hash; +this_cpu_ptr (ro->uniq)->skbcnt =can_skb_prv (oskb)->skbcnt;this_cpu_ptr (ro->uniq)->join_rx_count =1 ;/* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count >1 )
@@ -870,6 +870,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)can_skb_reserve (skb);can_skb_prv (skb)->ifindex = dev->ifindex; +can_skb_prv (skb)->skbcnt =0 ;/* fill the skb before testing for valid CAN frames */ err =memcpy_from_msg (skb_put (skb, size), msg, size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 504/1887 drm/amd/display: Dont replace a sink mode that shares the native totals
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Betschart <[email protected]>
commit 54c998c55fc9cbc391b350d67b86e0c2a0748f1a upstream.
decide_crtc_timing_for_drm_display_mode() copies the native mode's CRTC timing into the requested mode when clock, htotal and vtotal match. That is meant for the modes amdgpu inserts itself:amdgpu_dm_create_common_mode() duplicates the native mode and changes only hdisplay and vdisplay, so those are sent with the native timing and scaled.
A sink can also offer a real mode with the same clock and totals as its native mode. CTA-861 VIC 102 (4096x2160@60) and VIC 97 (3840x2160@60) both use 594 MHz and 4400x2250. With 3840x2160@60 as the preferred mode, a 4096x2160@60 request goes out with the 3840x2160 timing and the framebuffer scaled into it (dst 3840x2025 at y=67), while the AVI InfoFrame still carries VIC 102. A JVC projector then reports 3840x2160 and shows a corrupted right edge. 4096x2160@24, whose totals differ, is sent and displayed correctly.
Inserted modes keep the native sync positions; a real mode with its own active width does not. Compare those too, so only inserted modes are patched.
[ Adrian: this tree keeps the function in amdgpu_dm.c, with the equal-totals
case as its own else-if; added the sync checks there. Dropped the KUnit test, its file does not exist here. ]
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +6 -1
@@ -5607,11 +5607,16 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,const struct drm_display_mode *native_mode, bool scale_enabled) { + /* Inserted modes copy the native sync; a sink mode with equal totals may not */ if (scale_enabled) {copy_crtc_timing_for_drm_display_mode (native_mode ,drm_mode ); } else if (native_mode->clock == drm_mode->clock && native_mode->htotal == drm_mode->htotal && - native_mode->vtotal == drm_mode->vtotal) { + native_mode->vtotal == drm_mode->vtotal && + native_mode->hsync_start == drm_mode->hsync_start && + native_mode->hsync_end == drm_mode->hsync_end && + native_mode->vsync_start == drm_mode->vsync_start && + native_mode->vsync_end == drm_mode->vsync_end) {copy_crtc_timing_for_drm_display_mode (native_mode, drm_mode); }else {/* no scaling nor amdgpu inserted, no need to patch */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 505/1887 HID: hid-steam: Fix cleanup in probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit a9f1da09c69f13ef471db8b22107a28042d230ca ]
There are a number of issues in this code. First of all if steam_create_client_hid() fails then it leads to an error pointer dereference when we call hid_destroy_device(steam->client_hdev).
Also there are a number of leaks. hid_hw_stop() is not called if hid_hw_open() fails for example. And it doesn't call steam_unregister() or hid_hw_close().
[Lee: Move client_hdev creation after steam_register() and omit
mode_switch and rumble_work cancellation as 691ead124a0c and e133dc99fc07 are not present]
--- drivers/hid/hid-steam.c | 43 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 20 deletions(-)
drivers/hid/hid-steam.c +23 -20
@@ -751,31 +751,20 @@ static int steam_probe(struct hid_device *hdev,INIT_WORK (&steam->work_connect, steam_work_connect_cb);INIT_LIST_HEAD (&steam->list); - steam->client_hdev =steam_create_client_hid (hdev); -if (IS_ERR (steam->client_hdev)) { - ret =PTR_ERR (steam->client_hdev); - goto client_hdev_fail; - } - steam->client_hdev->driver_data = steam; -/* * With the real steam controller interface, do not connect hidraw. * Instead, create the client_hid and connect that. */ ret =hid_hw_start (hdev,HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW );if (ret) - goto hid_hw_start_fail; - - ret =hid_add_device (steam->client_hdev); -if (ret) - goto client_hdev_add_fail; + goto err_cancel_work; ret =hid_hw_open (hdev);if (ret) {hid_err (hdev,"%s:hid_hw_open\n" , __func__); - goto hid_hw_open_fail; + goto err_hw_stop; }if (steam->quirks &STEAM_QUIRK_WIRELESS ) {
@@ -791,19 +780,33 @@ static int steam_probe(struct hid_device *hdev,hid_err (hdev,"%s:steam_register failed with error %d\n" , __func__, ret); - goto input_register_fail; + goto err_hw_close; } } + steam->client_hdev =steam_create_client_hid (hdev); +if (IS_ERR (steam->client_hdev)) { + ret =PTR_ERR (steam->client_hdev); + goto err_stream_unregister; + } + steam->client_hdev->driver_data = steam; + + ret =hid_add_device (steam->client_hdev); +if (ret) + goto err_destroy; +return 0 ; -input_register_fail: -hid_hw_open_fail: -client_hdev_add_fail: -hid_hw_stop (hdev); -hid_hw_start_fail: +err_destroy:hid_destroy_device (steam->client_hdev); -client_hdev_fail: +err_stream_unregister: +if (steam->connected) +steam_unregister (steam); +err_hw_close: +hid_hw_close (hdev); +err_hw_stop: +hid_hw_stop (hdev); +err_cancel_work:cancel_work_sync (&steam->work_connect); steam_alloc_fail: hid_err(hdev, "%s: failed with error %d\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 506/1887 HID: hid-steam: Make client_opened a counter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <[email protected]>
[ Upstream commit 555b818adb97eca70210a49ba3f1d27882dde092 ]
The client_opened variable was used to track if the hidraw was opened by any clients to silence keyboard/mouse events while opened. However, there was no counting of how many clients were opened, so opening two at the same time and then closing one would fool the driver into thinking it had no remaining opened clients.
[Lee: Adapt steam_client_ll_open() and steam_client_ll_close() as
691ead124a0c and e1147961b214 are not present]
--- drivers/hid/hid-steam.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/hid/hid-steam.c +7 -7
@@ -114,7 +114,7 @@ struct steam_device {spinlock_t lock;struct hid_device *hdev, *client_hdev;struct mutex mutex; -bool client_opened; +unsigned long client_opened;struct input_dev __rcu *input;unsigned long quirks;struct work_struct work_connect;
@@ -509,7 +509,7 @@ static void steam_battery_unregister(struct steam_device *steam)static int steam_register (struct steam_device *steam) {int ret; -bool client_opened; +unsigned long client_opened;/* * This function can be called several times in a row with the
@@ -634,7 +634,7 @@ static int steam_client_ll_open(struct hid_device *hdev)struct steam_device *steam = hdev->driver_data;mutex_lock (&steam->mutex); - steam->client_opened = true; + steam->client_opened++;mutex_unlock (&steam->mutex);steam_input_unregister (steam);
@@ -654,12 +654,12 @@ static void steam_client_ll_close(struct hid_device *hdev)spin_unlock_irqrestore (&steam->lock, flags);mutex_lock (&steam->mutex); - steam->client_opened = false; -if (connected) + steam->client_opened--; +if (connected && !steam->client_opened)steam_set_lizard_mode (steam, lizard_mode);mutex_unlock (&steam->mutex); -if (connected) +if (connected && !steam->client_opened)steam_input_register (steam); }
@@ -824,7 +824,7 @@ static void steam_remove(struct hid_device *hdev) }hid_destroy_device (steam->client_hdev); - steam->client_opened = false; + steam->client_opened =0 ;cancel_work_sync (&steam->work_connect);if (steam->quirks &STEAM_QUIRK_WIRELESS ) {hid_info (hdev,"Steam wireless receiver disconnected" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 507/1887 HID: steam: Fully unregister controller when hidraw is opened
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <[email protected]>
[ Upstream commit cd33a91d37eb4d7c6ce56aa7f4688066309808eb ]
To avoid conflicts between anything touching the hidraw and the driver we had previously detached the evdev nodes when the hidraw is opened. However, this isn't sufficient to avoid FEATURE reports from conflicting, so we change to fully unregistering the controller internally, leaving only the hidraw active until it's closed.
This also unifies the unregister and connect callbacks, as now the logic between these two callbacks is identical.
[Lee: Convert steam_client_ll_open() and steam_client_ll_close() to
schedule work_connect directly and omit sensors, rumble_work, mode_switch and unregister_work changes as e133dc99fc07, e1147961b214 and 1d4549fd1115 are not present]
--- drivers/hid/hid-steam.c | 78 ++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 36 deletions(-)
drivers/hid/hid-steam.c +42 -36
@@ -380,6 +380,7 @@ static int steam_battery_register(struct steam_device *steam) &steam->battery_desc, &battery_cfg);if (IS_ERR (battery)) { ret =PTR_ERR (battery); +devm_kfree (&steam->hdev->dev, steam->battery_desc.name);hid_err (steam->hdev,"%s:power_supply_register failed with error %d\n" , __func__, ret);
@@ -504,12 +505,15 @@ static void steam_battery_unregister(struct steam_device *steam)RCU_INIT_POINTER (steam->battery,NULL );synchronize_rcu ();power_supply_unregister (battery); +devm_kfree (&steam->hdev->dev, steam->battery_desc.name); }static int steam_register (struct steam_device *steam) {int ret;unsigned long client_opened; +unsigned long flags; +bool do_add;/* * This function can be called several times in a row with the
@@ -535,38 +539,47 @@ static int steam_register(struct steam_device *steam)if (steam->quirks &STEAM_QUIRK_WIRELESS )steam_battery_register (steam); -mutex_lock (&steam_devices_lock); -if (list_empty (&steam->list)) -list_add (&steam->list, &steam_devices); -mutex_unlock (&steam_devices_lock); + do_add = true; } -mutex_lock (&steam->mutex); +spin_lock_irqsave (&steam->lock, flags); client_opened = steam->client_opened; -if (!client_opened) -steam_set_lizard_mode (steam, lizard_mode); -mutex_unlock (&steam->mutex); +spin_unlock_irqrestore (&steam->lock, flags); -if (!client_opened) +if (!client_opened) { +mutex_lock (&steam->mutex); +steam_set_lizard_mode (steam, lizard_mode); +mutex_unlock (&steam->mutex); ret =steam_input_register (steam); -else - ret =0 ; +if (ret !=0 ) + goto steam_register_input_fail; + } + +if (do_add) { +mutex_lock (&steam_devices_lock); +if (list_empty (&steam->list)) +list_add (&steam->list, &steam_devices); +mutex_unlock (&steam_devices_lock); + } +return 0 ; +steam_register_input_fail:return ret; }static void steam_unregister (struct steam_device *steam) { +if (!steam->serial_no[0 ]) +return ; + +hid_info (steam->hdev,"Steam Controller '%s' disconnected" , + steam->serial_no);steam_battery_unregister (steam);steam_input_unregister (steam); -if (steam->serial_no[0 ]) { -hid_info (steam->hdev,"Steam Controller '%s' disconnected" , - steam->serial_no); -mutex_lock (&steam_devices_lock); -list_del_init (&steam->list); -mutex_unlock (&steam_devices_lock); - steam->serial_no[0 ] =0 ; - } +mutex_lock (&steam_devices_lock); +list_del_init (&steam->list); +mutex_unlock (&steam_devices_lock); + steam->serial_no[0 ] =0 ; }static void steam_work_connect_cb (struct work_struct *work)
@@ -575,19 +588,20 @@ static void steam_work_connect_cb(struct work_struct *work) work_connect);unsigned long flags;bool connected; +bool opened;int ret;spin_lock_irqsave (&steam->lock, flags); + opened = steam->client_opened; connected = steam->connected;spin_unlock_irqrestore (&steam->lock, flags); -if (connected) { +if (connected && !opened) { ret =steam_register (steam); -if (ret) { +if (ret)hid_err (steam->hdev,"%s:steam_register failed with error %d\n" , __func__, ret); - } }else {steam_unregister (steam); }
@@ -632,12 +646,13 @@ static void steam_client_ll_stop(struct hid_device *hdev)static int steam_client_ll_open (struct hid_device *hdev) {struct steam_device *steam = hdev->driver_data; +unsigned long flags; -mutex_lock (&steam->mutex); +spin_lock_irqsave (&steam->lock, flags); steam->client_opened++; -mutex_unlock (&steam->mutex); +spin_unlock_irqrestore (&steam->lock, flags); -steam_input_unregister (steam); +schedule_work (&steam->work_connect);return 0 ; }
@@ -645,22 +660,13 @@ static int steam_client_ll_open(struct hid_device *hdev)static void steam_client_ll_close (struct hid_device *hdev) {struct steam_device *steam = hdev->driver_data; -unsigned long flags; -bool connected;spin_lock_irqsave (&steam->lock, flags); - connected = steam->connected; -spin_unlock_irqrestore (&steam->lock, flags); - -mutex_lock (&steam->mutex); steam->client_opened--; -if (connected && !steam->client_opened) -steam_set_lizard_mode (steam, lizard_mode); -mutex_unlock (&steam->mutex); +spin_unlock_irqrestore (&steam->lock, flags); -if (connected && !steam->client_opened) -steam_input_register (steam); +schedule_work (&steam->work_connect); } static int steam_client_ll_raw_request(struct hid_device *hdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 508/1887 HID: steam: Rearrange teardown sequence
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <[email protected]>
[ Upstream commit ddce9641ce924ed91ec8304577e463823a29ffaf ]
This fixes a narrow window during the teardown sequence where callbacks could still be scheduled during cleanup that would then have a dangling pointer to the now-freed steam struct.
This also puts work canceling for rumble and mode switch in steam_unregister, as that shouldn't persist while the client hdev is open.
[Lee: Omit rumble_work, coalesce_rumble_work and mode_switch
cancellation as e133dc99fc07 and 1d4549fd1115 are not present]
--- drivers/hid/hid-steam.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hid/hid-steam.c +3 -2
@@ -829,15 +829,16 @@ static void steam_remove(struct hid_device *hdev)return ; } +hid_hw_close (hdev);hid_destroy_device (steam->client_hdev); + steam->client_hdev =NULL ; steam->client_opened =0 ;cancel_work_sync (&steam->work_connect);if (steam->quirks &STEAM_QUIRK_WIRELESS ) {hid_info (hdev,"Steam wireless receiver disconnected" ); } -hid_hw_close (hdev); -hid_hw_stop (hdev);steam_unregister (steam); +hid_hw_stop (hdev); }static void steam_do_connect_event (struct steam_device *steam,bool connected)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 509/1887 HID: steam: Refactor registration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <[email protected]>
[ Upstream commit 6f9b740c31ba7e061b2ebb330d9a3d63f1358f29 ]
This refactors and simplifies the registration/unregistration flow. Since we now only perform registration when the client isn't opened anymore, the logic for handling that can be removed, and the rest of the function streamlined.
We also remove the previous assumption that we have a serial number to show we're registered, replacing it with a single purpose boolean.
In a previous refactor the code for unregistering a battery if later registration steps failed was accidentally left out. As a result, a lingering power_supply object could get left over after the steam object was torn down. This is also fixed here.
[Lee: Omit sensors, steam_get_attributes(), rumble_work,
coalesce_rumble_work and mode_switch changes as e133dc99fc07, a0fbd9437d7d and 1d4549fd1115 are not present]
--- drivers/hid/hid-steam.c | 70 ++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 39 deletions(-)
drivers/hid/hid-steam.c +31 -39
@@ -119,6 +119,7 @@ struct steam_device {unsigned long quirks;struct work_struct work_connect;bool connected; +bool registered;char serial_no[STEAM_SERIAL_LEN +1 ];struct power_supply_desc battery_desc;struct power_supply __rcu *battery;
@@ -511,9 +512,6 @@ static void steam_battery_unregister(struct steam_device *steam)static int steam_register (struct steam_device *steam) {int ret; -unsigned long client_opened; -unsigned long flags; -bool do_add;/* * This function can be called several times in a row with the
@@ -521,59 +519,53 @@ static int steam_register(struct steam_device *steam)* another client send a get_connection_status command, for example. * The battery and serial number are set just once per device. */ -if (!steam->serial_no[0 ]) { -/* -* Unlikely, but getting the serial could fail, and it is not so -* important, so make up a serial number and go on. -*/ -mutex_lock (&steam->mutex); -if (steam_get_serial (steam) <0 ) -strscpy (steam->serial_no,"XXXXXXXXXX" , -sizeof (steam->serial_no)); -mutex_unlock (&steam->mutex); - -hid_info (steam->hdev,"Steam Controller '%s' connected" , - steam->serial_no); +if (steam->registered) +return 0 ; -/* ignore battery errors, we can live without it */ -if (steam->quirks &STEAM_QUIRK_WIRELESS ) -steam_battery_register (steam); +/* +* Unlikely, but getting the serial could fail, and it is not so +* important, so make up a serial number and go on. +*/ +mutex_lock (&steam->mutex); +if (steam_get_serial (steam) <0 || !steam->serial_no[0 ]) +strscpy (steam->serial_no,"XXXXXXXXXX" , +sizeof (steam->serial_no)); +mutex_unlock (&steam->mutex); - do_add = true; - } +hid_info (steam->hdev,"Steam Controller '%s' connected" , + steam->serial_no); -spin_lock_irqsave (&steam->lock, flags); - client_opened = steam->client_opened; -spin_unlock_irqrestore (&steam->lock, flags); +/* ignore battery errors, we can live without it */ +if (steam->quirks &STEAM_QUIRK_WIRELESS ) +steam_battery_register (steam); -if (!client_opened) { -mutex_lock (&steam->mutex); -steam_set_lizard_mode (steam, lizard_mode); -mutex_unlock (&steam->mutex); - ret =steam_input_register (steam); -if (ret !=0 ) - goto steam_register_input_fail; - } +mutex_lock (&steam->mutex); +steam_set_lizard_mode (steam, lizard_mode); +mutex_unlock (&steam->mutex); + ret =steam_input_register (steam); +if (ret !=0 ) + goto steam_register_input_fail; -if (do_add) { -mutex_lock (&steam_devices_lock); -if (list_empty (&steam->list)) -list_add (&steam->list, &steam_devices); -mutex_unlock (&steam_devices_lock); - } + steam->registered = true; +mutex_lock (&steam_devices_lock); +if (list_empty (&steam->list)) +list_add (&steam->list, &steam_devices); +mutex_unlock (&steam_devices_lock);return 0 ; steam_register_input_fail: +steam_battery_unregister (steam);return ret; }static void steam_unregister (struct steam_device *steam) { -if (!steam->serial_no[0 ]) +if (!steam->registered)return ;hid_info (steam->hdev,"Steam Controller '%s' disconnected" , steam->serial_no); + steam->registered = false;steam_battery_unregister (steam);steam_input_unregister (steam);mutex_lock (&steam_devices_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 510/1887 HID: steam: Clean up locking
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <[email protected]>
[ Upstream commit de1d341b9b3ec9655f31fb8b44f784cca5e670ad ]
This cleans up several issues with locking behavior, including RCU accesses not being guarded behind a lock.
[Lee: Adapt to steam->mutex and omit Steam Deck sensors, mode_switch,
rumble_work, coalesce_rumble_work and Ibex changes as 691ead124a0c, e133dc99fc07, a0fbd9437d7d, 1d4549fd1115, fcfa7db89f7a and 0a80b4e8ec6a are not present]
--- drivers/hid/hid-steam.c | 59 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 22 deletions(-)
drivers/hid/hid-steam.c +37 -22
@@ -114,6 +114,7 @@ struct steam_device {spinlock_t lock;struct hid_device *hdev, *client_hdev;struct mutex mutex; +struct mutex registration_mutex;unsigned long client_opened;struct input_dev __rcu *input;unsigned long quirks;
@@ -294,22 +295,30 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)static int steam_input_open (struct input_dev *dev) {struct steam_device *steam =input_get_drvdata (dev); +unsigned long flags; +bool client_opened; -mutex_lock (&steam->mutex); -if (!steam->client_opened && lizard_mode) +spin_lock_irqsave (&steam->lock, flags); + client_opened = steam->client_opened; +spin_unlock_irqrestore (&steam->lock, flags); +guard (mutex)(&steam->mutex); +if (!client_opened && lizard_mode)steam_set_lizard_mode (steam, false); -mutex_unlock (&steam->mutex);return 0 ; }static void steam_input_close (struct input_dev *dev) {struct steam_device *steam =input_get_drvdata (dev); +unsigned long flags; +bool client_opened; -mutex_lock (&steam->mutex); -if (!steam->client_opened && lizard_mode) +spin_lock_irqsave (&steam->lock, flags); + client_opened = steam->client_opened; +spin_unlock_irqrestore (&steam->lock, flags); +guard (mutex)(&steam->mutex); +if (!client_opened && lizard_mode)steam_set_lizard_mode (steam, true); -mutex_unlock (&steam->mutex); }static enum power_supply_property steam_battery_props[] = {
@@ -513,40 +522,43 @@ static int steam_register(struct steam_device *steam) {int ret; +mutex_lock (&steam->registration_mutex);/* * This function can be called several times in a row with the * wireless adaptor, without steam_unregister() between them, because * another client send a get_connection_status command, for example. * The battery and serial number are set just once per device. */ -if (steam->registered) +if (steam->registered) { +mutex_unlock (&steam->registration_mutex);return 0 ; + } +mutex_lock (&steam->mutex);/* * Unlikely, but getting the serial could fail, and it is not so * important, so make up a serial number and go on. */ -mutex_lock (&steam->mutex);if (steam_get_serial (steam) <0 || !steam->serial_no[0 ])strscpy (steam->serial_no,"XXXXXXXXXX" ,sizeof (steam->serial_no)); -mutex_unlock (&steam->mutex);hid_info (steam->hdev,"Steam Controller '%s' connected" , steam->serial_no); +steam_set_lizard_mode (steam, lizard_mode); +mutex_unlock (&steam->mutex); +/* ignore battery errors, we can live without it */ if (steam->quirks &STEAM_QUIRK_WIRELESS )steam_battery_register (steam); -mutex_lock (&steam->mutex); -steam_set_lizard_mode (steam, lizard_mode); -mutex_unlock (&steam->mutex); ret =steam_input_register (steam);if (ret !=0 ) goto steam_register_input_fail; steam->registered = true; +mutex_unlock (&steam->registration_mutex);mutex_lock (&steam_devices_lock);if (list_empty (&steam->list))list_add (&steam->list, &steam_devices);
@@ -555,6 +567,7 @@ static int steam_register(struct steam_device *steam) steam_register_input_fail:steam_battery_unregister (steam); +mutex_unlock (&steam->registration_mutex);return ret; }
@@ -565,9 +578,11 @@ static void steam_unregister(struct steam_device *steam)hid_info (steam->hdev,"Steam Controller '%s' disconnected" , steam->serial_no); +mutex_lock (&steam->registration_mutex); steam->registered = false;steam_battery_unregister (steam);steam_input_unregister (steam); +mutex_unlock (&steam->registration_mutex);mutex_lock (&steam_devices_lock);list_del_init (&steam->list);mutex_unlock (&steam_devices_lock);
@@ -745,6 +760,7 @@ static int steam_probe(struct hid_device *hdev,hid_set_drvdata (hdev, steam);spin_lock_init (&steam->lock);mutex_init (&steam->mutex); +mutex_init (&steam->registration_mutex); steam->quirks = id->driver_data;INIT_WORK (&steam->work_connect, steam_work_connect_cb);INIT_LIST_HEAD (&steam->list);
@@ -835,13 +851,10 @@ static void steam_remove(struct hid_device *hdev)static void steam_do_connect_event (struct steam_device *steam,bool connected) { -unsigned long flags;bool changed; -spin_lock_irqsave (&steam->lock, flags); changed = steam->connected != connected; steam->connected = connected; -spin_unlock_irqrestore (&steam->lock, flags);if (changed &&schedule_work (&steam->work_connect) ==0 ) dbg_hid("%s: connected=%d event already queued\n",
@@ -1008,8 +1021,6 @@ static void steam_do_input_event(struct steam_device *steam,static void steam_do_battery_event (struct steam_device *steam,struct power_supply *battery,u8 *data) { -unsigned long flags; -s16 volts =steam_le16 (data +12 );u8 batt = data[14 ];
@@ -1017,10 +1028,8 @@ static void steam_do_battery_event(struct steam_device *steam,rcu_read_lock (); battery =rcu_dereference (steam->battery);if (likely (battery)) { -spin_lock_irqsave (&steam->lock, flags); steam->voltage = volts; steam->battery_charge = batt; -spin_unlock_irqrestore (&steam->lock, flags);power_supply_changed (battery); }rcu_read_unlock ();
@@ -1037,6 +1046,7 @@ static int steam_raw_event(struct hid_device *hdev,if (!steam)return 0 ; +guard (spinlock_irqsave)(&steam->lock);if (steam->client_opened)hid_input_report (steam->client_hdev,HID_FEATURE_REPORT , data, size,0 );
@@ -1108,6 +1118,8 @@ static int steam_param_set_lizard_mode(const char *val, {struct steam_device *steam;int ret; +bool client_opened; +unsigned long flags; ret =param_set_bool (val, kp);if (ret)
@@ -1115,10 +1127,13 @@ static int steam_param_set_lizard_mode(const char *val,mutex_lock (&steam_devices_lock);list_for_each_entry (steam, &steam_devices, list) { -mutex_lock (&steam->mutex); -if (!steam->client_opened) +spin_lock_irqsave (&steam->lock, flags); + client_opened = steam->client_opened; +spin_unlock_irqrestore (&steam->lock, flags); +if (!client_opened) { +guard (mutex)(&steam->mutex);steam_set_lizard_mode (steam, lizard_mode); -mutex_unlock (&steam->mutex); + } }mutex_unlock (&steam_devices_lock);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 511/1887 tracing: Set the trace clock before registering the histogram trigger
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donggeun Yoo <[email protected]>
[ Upstream commit 6ede78d0563a2a3ae3e46f9c07cedb5d79645429 ]
hist_register_trigger() puts the trigger on the global named_triggers list in cmd_ops->init(), and only then sets the trace clock:
if (data->cmd_ops->init) {
ret = data->cmd_ops->init(data);
if (ret < 0)
goto out;
}
if (hist_data->enable_timestamps) {
ret = tracing_set_clock(file->tr, hist_data->attrs->clock);
if (ret) {
hist_err(tr, HIST_ERR_SET_CLOCK_FAIL, errpos(clock));
goto out;
}The clock string is not checked anywhere before that call, so a named trigger using common_timestamp with an unknown clock fails after it has already become findable. event_hist_trigger_parse() then frees it without taking it off the list, and the next lookup by name reads the freed object:
~# cd /sys/kernel/tracing/events/sched/sched_switch
~# echo 'hist:name=foo:keys=common_pid:ts=common_timestamp:clock=bogus' > trigger
bash: echo: write error: Invalid argument
~# echo 'hist:name=foo:keys=common_pid' > trigger
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff88800915d760 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0x900 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 63: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Set the clock before the trigger is registered, so that nothing which can fail runs after it is published, the way commit 6f86bdeab633 ("tracing: Fix bad hist from corrupting named_triggers list") moved the registration below the rest of the setup.
tracing_set_filter_buffering() is reference counted, so the init failure path has to drop the reference that the clock block now takes first.
[Lee: Call data->ops->init(data) as b052d70f7c9c ("tracing: Merge struct
event_trigger_ops into struct event_command") is not present]
--- kernel/trace/trace_events_hist.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
kernel/trace/trace_events_hist.c +9 -6
@@ -6244,12 +6244,6 @@ static int hist_register_trigger(char *glob, data->ops = &event_hist_trigger_named_ops; } -if (data->ops->init) { - ret = data->ops->init (data); -if (ret <0 ) - goto out; - } -if (hist_data->enable_timestamps) {char *clock = hist_data->attrs->clock;
@@ -6262,6 +6256,15 @@ static int hist_register_trigger(char *glob,tracing_set_filter_buffering (file->tr, true); } +if (data->ops->init) { + ret = data->ops->init (data); +if (ret <0 ) { +if (hist_data->enable_timestamps) +tracing_set_filter_buffering (file->tr, false); + goto out; + } + } +if (named_data) {remove_hist_vars (hist_data);destroy_hist_data (hist_data);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 512/1887 ip6_gre: remove obsolete ERSPAN PMTU update
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
[ Upstream commit 8bc60db48e8cba35488bbd6e1f94aa990afa275a ]
A tc tunnel_key action can attach a METADATA_IP_TUNNEL dst to an skb, and mirred can redirect it to a native ip6erspan device. The legacy PMTU update in ip6erspan_tunnel_xmit() treats that metadata dst as a route. Since it has no output device, dst_dev(dst)->mtu dereferences NULL.
On v7.2 with KASAN, an initial UID/GID 65534 process with CapEff 0 used self-created user and network namespaces to trigger:
KASAN: null-ptr-deref RIP: ip6erspan_tunnel_xmit+0x10fc/0x2cc0 Kernel panic - not syncing: Fatal exception in interrupt
The update is obsolete. Commit fe1a4ca0a2b7 ("ip6_gre: process toobig in a better way") changed IPv6 GRE Too Big handling to update the underlay route and removed the equivalent block from __gre6_xmit(). ip6_tnl_xmit() then propagates the underlay PMTU to the overlay route.
Remove the stale ERSPAN copy and its now-unused dst variable. This eliminates the metadata-dst dereference and keeps ERSPAN aligned with IPv6 GRE PMTU handling.
--- net/ipv6/ip6_gre.c | 5 ----- 1 file changed, 5 deletions(-)
net/ipv6/ip6_gre.c +0 -5
@@ -962,7 +962,6 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, {struct ip_tunnel_info *tun_info =NULL ;struct ip6_tnl *t =netdev_priv (dev); -struct dst_entry *dst =skb_dst (skb);bool truncate = false;int encap_limit =-1 ;__u8 dsfield = false;
@@ -1094,10 +1093,6 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,/* Push GRE header. */ gre_build_header (skb,8 ,TUNNEL_SEQ , proto,0 ,htonl (atomic_fetch_inc (&t->o_seqno))); -/* TooBig packet may have updated dst->dev's mtu */ -if (!t->parms.collect_md && dst &&dst_mtu (dst) > dst->dev->mtu) - dst->ops->update_pmtu (dst,NULL , skb, dst->dev->mtu, false); - err =ip6_tnl_xmit (skb, dev, dsfield, &fl6, encap_limit, &mtu,NEXTHDR_GRE );if (err !=0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 513/1887 ice: fix metadata_dst refcount handling on representor teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 58858b8f14803a7eeac297b3ce20f3b21bf2ff66 ]
ice_eswitch_release_repr() uses metadata_dst_free() to release the representor's metadata_dst. metadata_dst_free() directly frees the underlying memory without checking the dst_entry refcount.
When ice_eswitch_port_start_xmit() processes a packet, it takes a reference via dst_hold() and attaches the metadata_dst to the skb. If the representor is torn down while packets are still queued on the lower device (e.g. in a qdisc), the metadata_dst is freed while references are still held.
Use dst_release() instead, which correctly decrements the refcount and only frees the object when all references are dropped. The dst subsystem already handles metadata_dst cleanup in dst_destroy() when DST_METADATA is set.
Other drivers sharing this pattern (nfp, airoha, bnxt) already use dst_release() for their metadata_dst lifecycle.
--- drivers/net/ethernet/intel/ice/ice_eswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_eswitch.c +1 -1
@@ -235,7 +235,7 @@ ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi)continue ;ice_vsi_update_security (vsi, ice_vsi_ctx_set_antispoof); -metadata_dst_free (vf->repr->dst); +dst_release (&vf->repr->dst->dst); vf->repr->dst =NULL ;ice_fltr_add_mac_and_broadcast (vsi, vf->hw_lan_addr.addr,ICE_FWD_TO_VSI );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 514/1887 selinux: fix data race on AVC latest_notif
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Göttsche <[email protected]>
[ Upstream commit 1ca924044bf0de879a1648be93a56939652267d3 ]
avc_policy_seqno() reads latest_notif without holding notif_lock, while avc_latest_notif_update() can update it under that lock. KCSAN reports these concurrent accesses during policy boolean updates and permission checks.
Use READ_ONCE() for the lockless read and WRITE_ONCE() for the update. The spinlock continues to serialize the comparison and update against other writers. Reads made while holding notif_lock cannot race with a writer and can remain plain accesses.
This marks both sides of the intentional concurrent access and constrains compiler transformations, without suppressing checking with data_race().
--- security/selinux/avc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
security/selinux/avc.c +3 -2
@@ -589,7 +589,7 @@ static int avc_latest_notif_update(struct selinux_avc *avc, } }else {if (seqno > avc->avc_cache.latest_notif) - avc->avc_cache.latest_notif = seqno; +WRITE_ONCE (avc->avc_cache.latest_notif, seqno); }spin_unlock_irqrestore (¬if_lock, flag);
@@ -1202,7 +1202,8 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,u32 avc_policy_seqno (struct selinux_state *state) { -return state->avc->avc_cache.latest_notif; +/* Writers hold notif_lock; readers only sample the sequence number. */ +return READ_ONCE (state->avc->avc_cache.latest_notif); }void avc_disable (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 515/1887 EDAC/amd64: Mask UMC chip select to the four implemented selects
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vishal Badole <[email protected]>
[ Upstream commit 7484bc43ba6b8e189b482db5b75e7842890a82b1 ]
For DRAM ECC errors, the chip select value can be found in the MCA_SYND[ErrorInformation] field.
ErrorInformation[2:0] was first documented in Zen1. The 3 bit field implied that up to 8 chip selects may be used.
However, all Zen-based systems have only ever had up to 4 chip selects. So only bits [1:0] would contain a valid chip select value.
Future systems are redefining the field to ErrorInformation[1:0]. This matches the existing 'up to 4 chip selects' implementations. And it frees up the extra bit for other decoding.
Change the current chip select mask from 0x7 to 0x3 to prepare for the decode change.
--- drivers/edac/amd64_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/edac/amd64_edac.c +1 -1
@@ -3300,7 +3300,7 @@ static void decode_umc_error(int node_id, struct mce *m) err.err_code =ERR_CHANNEL ; } - err.csrow = m->synd &0x7 ; + err.csrow = m->synd &0x3 ;if (umc_normaddr_to_sysaddr (m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { err.err_code =ERR_NORM_ADDR ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 516/1887 mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 597e4b9ab48a3f841080f627722064853d3f650e ]
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap() operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions occur between existing mremap() operations and the original VMA.
Fix another of these - partial copies.
The long-standing mremap() partial VMA logic has the baked-in assumption that the originating VMA is unmapped and thus moved.
However MREMAP_DONTUNMAP defeats this by performing a partial copy instead since it keeps the source VMA around.
An mremap(..., MREMAP_DONTUNMAP) operation disallows resizing of the VMA, but the operation can be performed partially:
|-----------------|
| |
| v
<------> <------>
.new_sz. new_sz
|--.------.--| |------|
| .source. | | dest |
|--.------.--| |------|
<------------>
old_szThe page tables in the specified range are moved, but the original VMA is kept intact.
This interacts poorly with mlock()'d VMAs, as the VMA_LOCKED_BIT flag is cleared for the entire source VMA and set for the entire destination VMA.
This results in an mm->locked_vm leak as the change is therefore not accounted correctly.
The clear solution here is to make the portion of the source VMA which is mremap()'d distinct from the rest of it, a.k.a. split it.
Therefore resolve this issue by splitting it ahead of the rest of the mremap() operation if the VMA is mlock()'d.
This is valid, as the source VMA will lose its VMA_LOCKED_BIT flag, so if a partial remap it will become distinct from the rest of the VMA.
In order to make this change re-expose split_vma() in vma.h for CONFIG_MMU (nommu doesn't compile mremap.c and uses a static helper instead).
Finally, update the sys_map_count check to account for this case.
Note that the early check does not use needs_pre_split() - this is because the VMA has not been looked up by this point, so be conservative and assume that the VMA is mlock()'d in this case for the purposes of the sys_map_count check.
--- mm/mremap.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
mm/mremap.c +17 -2
@@ -585,6 +585,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,int split =0 ;int err =0 ;bool need_rmap_locks; +const bool split_before = vma->vm_start != old_addr; +const bool split_after = vma->vm_end != old_addr + old_len;/* * We'd prefer to avoid failure later on in do_munmap:
@@ -597,9 +599,9 @@ static unsigned long move_vma(struct vm_area_struct *vma, to_account = new_len;if (vma->vm_ops && vma->vm_ops->may_split) { -if (vma->vm_start != old_addr) +if (split_before) err = vma->vm_ops->may_split (vma, old_addr); -if (!err && vma->vm_end != old_addr + old_len) +if (!err && split_after) err = vma->vm_ops->may_split (vma, old_addr + old_len);if (err)return err;
@@ -617,6 +619,19 @@ static unsigned long move_vma(struct vm_area_struct *vma,if (err)return err; +/* +* To account mlock()'d pages correctly in the MREMAP_DONTUNMAP +* case perform any split ahead of time for an mlock()'d VMA. +*/ +if ((flags &MREMAP_DONTUNMAP ) && (vma->vm_flags &VM_LOCKED )) { +if (split_before) + err =split_vma (mm, vma, old_addr,1 ); +if (!err && split_after) + err =split_vma (mm, vma, old_addr + old_len,0 ); +if (err) +return err; + } +if (vm_flags &VM_ACCOUNT ) {if (security_vm_enough_memory_mm (mm, to_account >>PAGE_SHIFT ))return -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 517/1887 mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <[email protected]>
[ Upstream commit 838bb60dc21553e32df90f2f3bac5b905376e7aa ]
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap() operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions occur between existing mremap() operations and the original VMA.
Fix another of these - self-merge.
Self-merge occurs when a VMA is moved in front of or behind itself and the attributes of the VMA permit such a merge.
Practically this can only happen for unfaulted anonymous VMAs due to the page offset equality requirement for merge:
|------------|
| |
| v
|...........||-----------||...........|
| || unfaulted || |
|...........||-----------||...........|
^ |
| |
|------------|This becomes problematic if the VMA is configured by the user to mlock-on-fault, i.e. the VMA_LOCKED_BIT, VMA_LOCKONFAULT_BIT VMA flags are set.
MREMAP_DONTUNMAP clears mlock flags for the source VMA and maintains them for the destination VMA.
Self-merge makes this impossible (there is only one VMA) and incorrectly clears the destination VMA's mlock flags.
This causes a leak in mm->locked_vm as clearing this flag does not decrement the counter and the VMA no longer has VMA_LOCKED_BIT set so it is not decremented on unmap.
Resolve this by simply disallowing a self-merge in this case - the source and destination VMAs are kept distinct and then are able to have distinct mlock() flags.
Update to make the now-redundant self-merge check a VM_WARN_ON_ONCE() instead to guard against future regressions.
--- include/linux/mm.h | 2 +- mm/mmap.c | 23 +++++++++++++++++++---- mm/mremap.c | 7 +++++-- 3 files changed, 25 insertions(+), 7 deletions(-)
include/linux/mm.h +1 -1
@@ -2822,7 +2822,7 @@ extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *);extern void unlink_file_vma (struct vm_area_struct *);extern struct vm_area_struct *copy_vma (struct vm_area_struct **,unsigned long addr,unsigned long len,pgoff_t pgoff, -bool *need_rmap_locks); +bool *need_rmap_locks,bool keep_source);extern void exit_mmap (struct mm_struct *);void vma_mas_store (struct vm_area_struct *vma,struct ma_state *mas);
mm/mmap.c +19 -4
@@ -3337,13 +3337,14 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)*/ struct vm_area_struct *copy_vma (struct vm_area_struct **vmap,unsigned long addr,unsigned long len,pgoff_t pgoff, -bool *need_rmap_locks) +bool *need_rmap_locks,bool keep_source) {struct vm_area_struct *vma = *vmap;unsigned long vma_start = vma->vm_start;struct mm_struct *mm = vma->vm_mm;struct vm_area_struct *new_vma, *prev;bool faulted_in_anon_vma = true; +bool can_self_merge = false;validate_mm_mt (mm);/*
@@ -3353,15 +3354,29 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,if (unlikely (vma_is_anonymous (vma) && !vma->anon_vma)) { pgoff = addr >>PAGE_SHIFT ; faulted_in_anon_vma = false; + can_self_merge = true; } new_vma =find_vma_prev (mm, addr, &prev);if (new_vma && new_vma->vm_start < addr + len)return NULL ;/* should never get here */ - new_vma =vma_merge (mm, prev, addr, addr + len, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff,vma_policy (vma), - vma->vm_userfaultfd_ctx,anon_vma_name (vma)); +/* +* If the original VMA is kept (MREMAP_DONTUNMAP), the source and +* destination VMA must be treated distinctly. +* +* A merge violates this, so in this case disallow a self-merge. A +* self-merge can only occur if the new range is immediately adjacent to +* the source VMA, so simply do not attempt to merge in that case. +*/ +if (can_self_merge && keep_source && + (addr == vma->vm_end || vma->vm_start == addr + len)) + new_vma =NULL ; +else + new_vma =vma_merge (mm, prev, addr, addr + len, vma->vm_flags, + vma->anon_vma, vma->vm_file, pgoff, +vma_policy (vma), vma->vm_userfaultfd_ctx, +anon_vma_name (vma));if (new_vma) {/* * Source vma may have been merged into new_vma
mm/mremap.c +5 -2
@@ -639,7 +639,7 @@ static unsigned long move_vma(struct vm_area_struct *vma, new_pgoff = vma->vm_pgoff + ((old_addr - vma->vm_start) >>PAGE_SHIFT ); new_vma =copy_vma (&vma, new_addr, new_len, new_pgoff, - &need_rmap_locks); + &need_rmap_locks, flags &MREMAP_DONTUNMAP );if (!new_vma) {if (vm_flags &VM_ACCOUNT )vm_unacct_memory (to_account >>PAGE_SHIFT );
@@ -700,6 +700,9 @@ static unsigned long move_vma(struct vm_area_struct *vma,untrack_pfn_clear (vma);if (unlikely (!err && (flags &MREMAP_DONTUNMAP ))) { +/* Self-merge is disallowed. */ +VM_WARN_ON_ONCE (new_vma == vma); +/* We always clear VM_LOCKED[ONFAULT] on the old vma */ vma->vm_flags &=VM_LOCKED_CLEAR_MASK ;
@@ -707,7 +710,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,* anon_vma links of the old vma is no longer needed after its page * table has been moved. */ -if (new_vma != vma && vma->vm_start == old_addr && +if (vma->vm_start == old_addr && vma->vm_end == (old_addr + old_len)) {const pgoff_t pgoff_unfaulted = vma->vm_start >>PAGE_SHIFT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 518/1887 wireguard: queueing: preserve tstamp_type when encapsulating packet
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ramses de Norre <[email protected]>
[ Upstream commit 65ab9de4bdd4c05d8277cfc20ae0b9f5aff60897 ]
Sending traffic through a wireguard tunnel on a host using the fq qdisc fills the log with:
fq: likely mono tstamp with tstamp_type 0
An skb carries a timestamp in skb->tstamp and, separately, a skb->tstamp_type field recording which clock that timestamp came from. The two have to agree.
When wireguard encapsulates a packet it calls wg_reset_packet(), which clears the fields that must not leak from the inner packet into the tunnel packet. It does so in two steps:
skb_scrub_packet(skb, true); memset(&skb->headers, 0, sizeof(skb->headers));
skb_scrub_packet() deliberately keeps skb->tstamp when it holds a monotonic timestamp: that value is the time the packet is scheduled to be sent, and the qdisc still needs it. The memset then zeroes skb->tstamp_type, because that field sits inside the headers group while skb->tstamp does not. The packet therefore leaves wireguard carrying a monotonic timestamp labelled as a realtime one.
Nothing noticed until commit c4f796c4f16b ("net_sched: sch_fq: convert skb->tstamp if not monotonic"): fq used to assume every timestamp was monotonic. It now consults tstamp_type, spots the mismatch, warns, and falls back to treating the value as monotonic. Pacing still ends up correct, so the log spam is the actual problem.
Save tstamp_type before the memset and restore it when encapsulating, next to the hash fields that are already carried over this way. When decapsulating it stays zeroed, which is right: an incoming packet's timestamp is a realtime receive timestamp.
--- drivers/net/wireguard/queueing.h | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireguard/queueing.h +2 -0
@@ -78,12 +78,14 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)u8 l4_hash = skb->l4_hash;u8 sw_hash = skb->sw_hash;u32 hash = skb->hash; +u8 mono_delivery_time = skb->mono_delivery_time;skb_scrub_packet (skb, true);memset (&skb->headers,0 ,sizeof (skb->headers));if (encapsulating) { skb->l4_hash = l4_hash; skb->sw_hash = sw_hash; skb->hash = hash; + skb->mono_delivery_time = mono_delivery_time; } skb->queue_mapping =0 ; skb->nohdr =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 519/1887 xfrm: prevent policy_hthresh.work from racing with netns teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tahera Fahimi <[email protected]>
An XFRM_MSG_NEWSPDINFO request can queue the per-net work item policy_hthresh.work onto the system workqueue. xfrm_hash_rebuild() retrieves the enclosing struct net from the work item, so the callback can dereference freed memory if it runs after net namespace teardown.
Mainline commit 29fe3a61bcdc ("xfrm: prevent policy_hthresh.work from racing with netns teardown") fixes this issue using disable_work_sync(). That API is not available in Linux 6.1, so the mainline change cannot be directly backported.
Provide the same guarantee with an XFRM-local work_disabled flag. Protect the flag and schedule_work() with the existing policy_hthresh seqlock so teardown can atomically stop new queueing attempts. Then use cancel_work_sync() to synchronize work that was queued before the flag was set. This ensures policy_hthresh.work cannot outlive its struct net.
--- include/net/netns/xfrm.h | 1 + net/xfrm/xfrm_policy.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-)
include/net/netns/xfrm.h +1 -0
@@ -23,6 +23,7 @@ struct xfrm_policy_hash {struct xfrm_policy_hthresh {struct work_struct work;seqlock_t lock; +bool work_disabled;u8 lbits4;u8 rbits4;u8 lbits6;
net/xfrm/xfrm_policy.c +18 -1
@@ -1381,7 +1381,10 @@ static void xfrm_hash_rebuild(struct work_struct *work)void xfrm_policy_hash_rebuild (struct net *net) { -schedule_work (&net->xfrm.policy_hthresh.work); +write_seqlock (&net->xfrm.policy_hthresh.lock); +if (!net->xfrm.policy_hthresh.work_disabled) +schedule_work (&net->xfrm.policy_hthresh.work); +write_sequnlock (&net->xfrm.policy_hthresh.lock); }EXPORT_SYMBOL (xfrm_policy_hash_rebuild);
@@ -4094,6 +4097,7 @@ static int __net_init xfrm_policy_init(struct net *net) net->xfrm.policy_hthresh.rbits6 =128 ;seqlock_init (&net->xfrm.policy_hthresh.lock); + net->xfrm.policy_hthresh.work_disabled = false;INIT_LIST_HEAD (&net->xfrm.policy_all);INIT_LIST_HEAD (&net->xfrm.inexact_bins);
@@ -4119,6 +4123,19 @@ static void xfrm_policy_fini(struct net *net)unsigned int sz;int dir; +/* Prevent new policy hash rebuilds before draining the work item. +* +* The upstream fix uses disable_work_sync(), which is unavailable +* in v6.6. Protecting work_disabled and schedule_work() with the +* same seqlock closes the check-to-queue race, while the subsequent +* cancel_work_sync() drains work that was queued or running before +* teardown disabled it. +*/ +write_seqlock (&net->xfrm.policy_hthresh.lock); + net->xfrm.policy_hthresh.work_disabled = true; +write_sequnlock (&net->xfrm.policy_hthresh.lock); +cancel_work_sync (&net->xfrm.policy_hthresh.work); +flush_work (&net->xfrm.policy_hash_work);#ifdef CONFIG_XFRM_SUB_POLICY xfrm_policy_flush (net,XFRM_POLICY_TYPE_SUB , false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 520/1887 netfilter: nf_tables: fix bidirectional offload regression
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <[email protected]>
[ Upstream commit 84443741faab9045d53f022a9ac6a6633067a481 ]
Commit 8f84780b84d6 ("netfilter: flowtable: allow unidirectional rules") made unidirectional flow offload possible, while completely ignoring (and breaking) bidirectional flow offload for nftables.
Add the missing flag that was left out as an exercise for the reader :)
--- net/netfilter/nft_flow_offload.c | 1 + 1 file changed, 1 insertion(+)
net/netfilter/nft_flow_offload.c +1 -0
@@ -374,6 +374,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,if (tcph)flow_offload_ct_tcp (ct); +__set_bit (NF_FLOW_HW_BIDIRECTIONAL , &flow->flags); ret =flow_offload_add (flowtable, flow);if (ret <0 ) goto err_flow_add;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 521/1887 net: team: Remove unused team_mode_op, port_enabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Harvey <[email protected]>
[ Upstream commit 014f249121d73909528df320818fba7693d0ec92 ]
This team_mode_op wasn't used by any of the team modes, so remove it.
Stable-dep-of: b7454f1940c5 ("net: team: stop reusing skb after queue override")
--- drivers/net/team/team.c | 2 -- include/linux/if_team.h | 1 - 2 files changed, 3 deletions(-)
drivers/net/team/team.c +0 -2
@@ -945,8 +945,6 @@ static void team_port_enable(struct team *team, team_port_index_hash(team, port->index));team_adjust_ops (team);team_queue_override_port_add (team, port); -if (team->ops.port_enabled) - team->ops.port_enabled (team, port);team_notify_peers (team);team_mcast_rejoin (team);team_lower_state_changed (port);
include/linux/if_team.h +0 -1
@@ -121,7 +121,6 @@ struct team_mode_ops {int (*port_enter)(struct team *team,struct team_port *port);void (*port_leave)(struct team *team,struct team_port *port);void (*port_change_dev_addr)(struct team *team,struct team_port *port); -void (*port_enabled)(struct team *team,struct team_port *port);void (*port_disabled)(struct team *team,struct team_port *port); };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 522/1887 net: team: Rename port_disabled team mode op to port_tx_disabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Harvey <[email protected]>
[ Upstream commit cfa477df2cc62ba53cb936669886361152b594a7 ]
This team mode op is only used by the load balance mode, and it only uses it in the tx path.
Stable-dep-of: b7454f1940c5 ("net: team: stop reusing skb after queue override")
--- drivers/net/team/team.c | 4 ++-- drivers/net/team/team_mode_loadbalance.c | 4 ++-- include/linux/if_team.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/team/team.c +2 -2
@@ -969,8 +969,8 @@ static void team_port_disable(struct team *team, {if (!team_port_enabled (port))return ; -if (team->ops.port_disabled) - team->ops.port_disabled (team, port); +if (team->ops.port_tx_disabled) + team->ops.port_tx_disabled (team, port);hlist_del_rcu (&port->hlist);__reconstruct_port_hlist (team, port->index); port->index =-1 ;
drivers/net/team/team_mode_loadbalance.c +2 -2
@@ -672,7 +672,7 @@ static void lb_port_leave(struct team *team, struct team_port *port)free_percpu (lb_port_priv->pcpu_stats); } -static void lb_port_disabled (struct team *team,struct team_port *port) +static void lb_port_tx_disabled (struct team *team,struct team_port *port) {lb_tx_hash_to_port_mapping_null_port (team, port); }
@@ -682,7 +682,7 @@ static const struct team_mode_ops lb_mode_ops = { .exit = lb_exit, .port_enter = lb_port_enter, .port_leave = lb_port_leave, - .port_disabled = lb_port_disabled, + .port_tx_disabled = lb_port_tx_disabled, .receive = lb_receive, .transmit = lb_transmit, };
include/linux/if_team.h +1 -1
@@ -121,7 +121,7 @@ struct team_mode_ops {int (*port_enter)(struct team *team,struct team_port *port);void (*port_leave)(struct team *team,struct team_port *port);void (*port_change_dev_addr)(struct team *team,struct team_port *port); -void (*port_disabled)(struct team *team,struct team_port *port); +void (*port_tx_disabled)(struct team *team,struct team_port *port); };extern int team_modeop_port_enter (struct team *team,struct team_port *port);
Signature · 1 line
2.53.0