6.19.9-rc1 review
Subsystems (5)
Greg Kroah-Hartman
maintainerPATCH 142/378 USB: add QUIRK_NO_BOS for video capture several devices
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: A1RM4X <[email protected]>
commit 93cd0d664661f58f7e7bed7373714ab2ace41734 upstream.
Several USB capture devices also need the USB_QUIRK_NO_BOS set for them to work properly, odds are they are all the same chip inside, just different vendor/product ids.
This fixes up:
- ASUS TUF 4K PRO
- Avermedia Live Gamer Ultra 2.1 (GC553G2)
- UGREEN 35871
to now run at full speed (10 Gbps/4K 60 fps mode.)
--- drivers/usb/core/quirks.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/usb/core/quirks.c +9 -0
@@ -377,6 +377,9 @@ static const struct usb_device_id usb_qu/* SanDisk Extreme 55AE */ { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM }, + /* Avermedia Live Gamer Ultra 2.1 (GC553G2) - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x07ca, 0x2553), .driver_info = USB_QUIRK_NO_BOS }, + /* Realforce 87U Keyboard */ { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
@@ -437,6 +440,9 @@ static const struct usb_device_id usb_qu { USB_DEVICE(0x0b05, 0x17e0), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* ASUS TUF 4K PRO - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x0b05, 0x1ab9), .driver_info = USB_QUIRK_NO_BOS }, + /* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/ { USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -565,6 +571,9 @@ static const struct usb_device_id usb_qu { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM }, + /* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS }, + /* APTIV AUTOMOTIVE HUB */ { USB_DEVICE(0x2c48, 0x0132), .driver_info = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT },
Greg Kroah-Hartman
maintainerPATCH 143/378 usb/core/quirks: Add Huawei ME906S-device to wakeup quirk
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoffer Sandberg <[email protected]>
commit 0326ff28d56b4fa202de36ffc8462a354f383a64 upstream.
Similar to other Huawei LTE modules using this quirk, this version with another vid/pid suffers from spurious wakeups.
Setting the quirk fixes the issue for this device as well.
--- drivers/usb/core/quirks.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/core/quirks.c +4 -0
@@ -208,6 +208,10 @@ static const struct usb_device_id usb_qu/* HP v222w 16GB Mini USB Drive */ { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Huawei 4G LTE module ME906S */ + { USB_DEVICE(0x03f0, 0xa31d), .driver_info = + USB_QUIRK_DISCONNECT_SUSPEND }, + /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
Greg Kroah-Hartman
maintainerPATCH 144/378 USB: ezcap401 needs USB_QUIRK_NO_BOS to function on 10gbs usb speed
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vyacheslav Vahnenko <[email protected]>
commit d0d9b1f4f5391e6a00cee81d73ed2e8f98446d5f upstream.
Add USB_QUIRK_NO_BOS for ezcap401 capture card, without it dmesg will show "unable to get BOS descriptor or descriptor too short" and "unable to read config index 0 descriptor/start: -71" errors and device will not able to work at full speed at 10gbs
--- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/core/quirks.c +3 -0
@@ -588,6 +588,9 @@ static const struct usb_device_id usb_qu/* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */ { USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM }, + /* ezcap401 - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x32ed, 0x0401), .driver_info = USB_QUIRK_NO_BOS }, + /* DELL USB GEN2 */ { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
Greg Kroah-Hartman
maintainerPATCH 145/378 usb: xhci: Fix memory leak in xhci_disable_slot()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
commit c1c8550e70401159184130a1afc6261db01fc0ce upstream.
xhci_alloc_command() allocates a command structure and, when the second argument is true, also allocates a completion structure. Currently, the error handling path in xhci_disable_slot() only frees the command structure using kfree(), causing the completion structure to leak.
Use xhci_free_command() instead of kfree(). xhci_free_command() correctly frees both the command structure and the associated completion structure. Since the command structure is allocated with zero-initialization, command->in_ctx is NULL and will not be erroneously freed by xhci_free_command().
This bug was found using an experimental static analysis tool we are developing. The tool is based on the LLVM framework and is specifically designed to detect memory management issues. It is currently under active development and not yet publicly available, but we plan to open-source it after our research is published.
The bug was originally detected on v6.13-rc1 using our static analysis tool, and we have verified that the issue persists in the latest mainline kernel.
We performed build testing on x86_64 with allyesconfig using GCC=11.4.0. Since triggering these error paths in xhci_disable_slot() requires specific hardware conditions or abnormal state, we were unable to construct a test case to reliably trigger these specific error paths at runtime.
--- drivers/usb/host/xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/host/xhci.c +2 -2
@@ -4146,7 +4146,7 @@ int xhci_disable_slot(struct xhci_hcd *xif (state ==0xffffffff || (xhci->xhc_state &XHCI_STATE_DYING ) || (xhci->xhc_state &XHCI_STATE_HALTED )) {spin_unlock_irqrestore (&xhci->lock, flags); -kfree (command); +xhci_free_command (xhci, command);return -ENODEV ; }
@@ -4154,7 +4154,7 @@ int xhci_disable_slot(struct xhci_hcd *x slot_id);if (ret) {spin_unlock_irqrestore (&xhci->lock, flags); -kfree (command); +xhci_free_command (xhci, command);return ret; }xhci_ring_cmd_db (xhci);
Greg Kroah-Hartman
maintainerPATCH 146/378 usb: xhci: Prevent interrupt storm on host controller error (HCE)
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dayu Jiang <[email protected]>
commit d6d5febd12452b7fd951fdd15c3ec262f01901a4 upstream.
The xHCI controller reports a Host Controller Error (HCE) in UAS Storage Device plug/unplug scenarios on Android devices. HCE is checked in xhci_irq() function and causes an interrupt storm (since the interrupt isn’t cleared), leading to severe system-level faults.
When the xHC controller reports HCE in the interrupt handler, the driver only logs a warning and assumes xHC activity will stop as stated in xHCI specification. An interrupt storm does however continue on some hosts even after HCE, and only ceases after manually disabling xHC interrupt and stopping the controller by calling xhci_halt().
Add xhci_halt() to xhci_irq() function where STS_HCE status is checked, mirroring the existing error handling pattern used for STS_FATAL errors.
This only fixes the interrupt storm. Proper HCE recovery requires resetting and re-initializing the xHC.
--- drivers/usb/host/xhci-ring.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/xhci-ring.c +1 -0
@@ -3195,6 +3195,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcdif (status &STS_HCE ) {xhci_warn (xhci,"WARNING: Host Controller Error\n" ); +xhci_halt (xhci); goto out; }
Greg Kroah-Hartman
maintainerPATCH 147/378 xhci: Fix NULL pointer dereference when reading portli debugfs files
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Nyman <[email protected]>
commit ae4ff9dead5efa2025eddfcdb29411432bf40a7c upstream.
Michal reported and debgged a NULL pointer dereference bug in the recently added portli debugfs files
Oops is caused when there are more port registers counted in xhci->max_ports than ports reported by Supported Protocol capabilities. This is possible if max_ports is more than maximum port number, or if there are gaps between ports of different speeds the 'Supported Protocol' capabilities.
In such cases port->rhub will be NULL so we can't reach xhci behind it. Add an explicit NULL check for this case, and print portli in hex without dereferencing port->rhub.
--- drivers/usb/host/xhci-debugfs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/host/xhci-debugfs.c +9 -1
@@ -386,11 +386,19 @@ static const struct file_operations port_fops = {static int xhci_portli_show (struct seq_file *s,void *unused) {struct xhci_port *port = s->private; -struct xhci_hcd *xhci =hcd_to_xhci (port->rhub->hcd); +struct xhci_hcd *xhci;u32 portli; portli =readl (&port->port_reg->portli); +/* port without protocol capability isn't added to a roothub */ +if (!port->rhub) { +seq_printf (s,"0x%08x\n" , portli); +return 0 ; + } + + xhci =hcd_to_xhci (port->rhub->hcd); +/* PORTLI fields are valid if port is a USB3 or eUSB2V2 port */ if (port->rhub == &xhci->usb3_rhub) seq_printf(s, "0x%08x LEC=%u RLC=%u TLC=%u\n", portli,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 148/378 usb: yurex: fix race in probe
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
commit 7a875c09899ba0404844abfd8f0d54cdc481c151 upstream.
The bbu member of the descriptor must be set to the value standing for uninitialized values before the URB whose completion handler sets bbu is submitted. Otherwise there is a window during which probing can overwrite already retrieved data.
--- drivers/usb/misc/yurex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/misc/yurex.c +1 -1
@@ -272,6 +272,7 @@ static int yurex_probe(struct usb_interf dev->int_buffer,YUREX_BUF_SIZE , yurex_interrupt, dev, 1); dev->urb->transfer_flags |=URB_NO_TRANSFER_DMA_MAP ; + dev->bbu =-1 ;if (usb_submit_urb (dev->urb,GFP_KERNEL )) { retval = -EIO ;dev_err (&interface->dev,"Could not submitting URB\n" );
@@ -280,7 +281,6 @@ static int yurex_probe(struct usb_interf/* save our data pointer in this interface device */ usb_set_intfdata (interface, dev); - dev->bbu =-1 ;/* we can register the device now, as it is ready */ retval =usb_register_dev (interface, &yurex_class);
Greg Kroah-Hartman
maintainerPATCH 149/378 usb: dwc3: pci: add support for the Intel Nova Lake -H
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus <[email protected]>
commit 17ab4d4078e22be7fd8fd6fc710c15c085a4cb1b upstream.
This patch adds the necessary PCI ID for Intel Nova Lake -H devices.
--- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/dwc3/dwc3-pci.c +2 -0
@@ -56,6 +56,7 @@#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e#define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0#define PCI_DEVICE_ID_INTEL_RPL 0xa70e +#define PCI_DEVICE_ID_INTEL_NVLH 0xd37f#define PCI_DEVICE_ID_INTEL_PTLH 0xe332#define PCI_DEVICE_ID_INTEL_PTLH_PCH 0xe37e#define PCI_DEVICE_ID_INTEL_PTLU 0xe432
@@ -447,6 +448,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, NVLH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, PTLH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, PTLH_PCH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, PTLU, &dwc3_pci_intel_swnode) },
Greg Kroah-Hartman
maintainerPATCH 150/378 usb: misc: uss720: properly clean up reference in uss720_probe()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 45dba8011efac11a2f360383221b541f5ea53ce5 upstream.
If get_1284_register() fails, the usb device reference count is incorrect and needs to be properly dropped before returning. That will happen when the kref is dropped in the call to destroy_priv(), so jump to that error path instead of returning directly.
--- drivers/usb/misc/uss720.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/misc/uss720.c +1 -1
@@ -736,7 +736,7 @@ static int uss720_probe(struct usb_inter ret =get_1284_register (pp,0 , ®,GFP_KERNEL );dev_dbg (&intf->dev,"reg: %7ph\n" , priv->reg);if (ret <0 ) -return ret; + goto probe_abort; ret =usb_find_last_int_in_endpoint (interface, &epd);if (!ret) {
Greg Kroah-Hartman
maintainerPATCH 151/378 usb: core: dont power off roothub PHYs if phy_set_mode() fails
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabor Juhos <[email protected]>
commit e293015ba76eb96ce4ebed7e3b2cb1a7d319f3e9 upstream.
Remove the error path from the usb_phy_roothub_set_mode() function. The code is clearly wrong, because phy_set_mode() calls can't be balanced with phy_power_off() calls.
Additionally, the usb_phy_roothub_set_mode() function is called only from usb_add_hcd() before it powers on the PHYs, so powering off those makes no sense anyway.
Presumably, the code is copy-pasted from the phy_power_on() function without adjusting the error handling.
--- drivers/usb/core/phy.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/usb/core/phy.c +1 -7
@@ -200,16 +200,10 @@ int usb_phy_roothub_set_mode(struct usb_list_for_each_entry (roothub_entry, head, list) { err =phy_set_mode (roothub_entry->phy, mode);if (err) - goto err_out; +return err; }return 0 ; - -err_out: -list_for_each_entry_continue_reverse (roothub_entry, head, list) -phy_power_off (roothub_entry->phy); - -return err; }EXPORT_SYMBOL_GPL (usb_phy_roothub_set_mode);
Greg Kroah-Hartman
maintainerPATCH 152/378 usb: cdc-acm: Restore CAP_BRK functionnality to CH343
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit 14ae24cba291bddfdc296bbcbfd00cd09d0498ef upstream.
The CH343 USB/serial adapter is as buggy as it is popular (very). One of its quirks is that despite being capable of signalling a BREAK condition, it doesn't advertise it.
This used to work nonetheless until 66aad7d8d3ec5 ("usb: cdc-acm:
return correct error code on unsupported break") applied some reasonable restrictions, preventing breaks from being emitted on devices that do not advertise CAP_BRK.
Add a quirk for this particular device, so that breaks can still be produced on some of my machines attached to my console server.
--- drivers/usb/class/cdc-acm.c | 5 +++++ drivers/usb/class/cdc-acm.h | 1 + 2 files changed, 6 insertions(+)
drivers/usb/class/cdc-acm.c +5 -0
@@ -1379,6 +1379,8 @@ made_compressed_probe: acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;if (quirks &NO_CAP_LINE ) acm->ctrl_caps &= ~USB_CDC_CAP_LINE ; +if (quirks &MISSING_CAP_BRK ) + acm->ctrl_caps |=USB_CDC_CAP_BRK ; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf;
@@ -2002,6 +2004,9 @@ static const struct usb_device_id acm_id .driver_info = IGNORE_DEVICE, }, +/* CH343 supports CAP_BRK, but doesn't advertise it */ + { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) },
drivers/usb/class/cdc-acm.h +1 -0
@@ -113,3 +113,4 @@ struct acm {#define CLEAR_HALT_CONDITIONS BIT(5)#define SEND_ZERO_PACKET BIT(6)#define DISABLE_ECHO BIT(7) +#define MISSING_CAP_BRK BIT(8)
Greg Kroah-Hartman
maintainerPATCH 153/378 usb: roles: get usb role switch from parent only for usb-b-connector
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
commit 8345b1539faa49fcf9c9439c3cbd97dac6eca171 upstream.
usb_role_switch_is_parent() was walking up to the parent node and checking for the "usb-role-switch" property regardless of the type of the passed fwnode. This could cause unrelated device nodes to be probed as potential role switch parent, leading to spurious matches and "-EPROBE_DEFER" being returned infinitely.
Till now only Type-B connector node will have a parent node which may present "usb-role-switch" property and register the role switch device. For Type-C connector node, its parent node will always be a Type-C chip device which will never register the role switch device. However, it may still present a non-boolean "usb-role-switch = <&usb_controller>" property for historical compatibility.
So restrict the helper to only operate on Type-B connector when attempting to get the role switch from parent node.
--- drivers/usb/roles/class.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/usb/roles/class.c +6 -1
@@ -139,9 +139,14 @@ static void *usb_role_switch_match(conststatic struct usb_role_switch *usb_role_switch_is_parent (struct fwnode_handle *fwnode) { -struct fwnode_handle *parent =fwnode_get_parent (fwnode); +struct fwnode_handle *parent;struct device *dev; +if (!fwnode_device_is_compatible (fwnode,"usb-b-connector" )) +return NULL ; + + parent =fwnode_get_parent (fwnode); +if (!fwnode_property_present (parent,"usb-role-switch" )) {fwnode_handle_put (parent);return NULL ;
Greg Kroah-Hartman
maintainerPATCH 154/378 usb: typec: altmode/displayport: set displayport signaling rate in configure message
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: RD Babiera <[email protected]>
commit e8557acfa079a54b59a21f447c82a31aec7717df upstream.
dp_altmode_configure sets the signaling rate to the current configuration's rate and then shifts the value to the Select Configuration bitfield. On the initial configuration, dp->data.conf is 0 to begin with, so the signaling rate field is never set, which leads to some DisplayPort Alt Mode partners sending NAK to the Configure message.
Set the signaling rate to the capabilities supported by both the port and the port partner. If the cable supports DisplayPort Alt Mode, then include its capabilities as well.
--- drivers/usb/typec/altmodes/displayport.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/usb/typec/altmodes/displayport.c +6 -1
@@ -100,9 +100,14 @@ static int dp_altmode_configure(struct d {u8 pin_assign =0 ;u32 conf; +u32 signal;/* DP Signalling */ - conf = (dp->data.conf &DP_CONF_SIGNALLING_MASK ) >>DP_CONF_SIGNALLING_SHIFT ; + signal =DP_CAP_DP_SIGNALLING (dp->port->vdo) &DP_CAP_DP_SIGNALLING (dp->alt->vdo); +if (dp->plug_prime) + signal &=DP_CAP_DP_SIGNALLING (dp->plug_prime->vdo); + + conf = signal <<DP_CONF_SIGNALLING_SHIFT ;switch (con) {case DP_STATUS_CON_DISABLED :
Greg Kroah-Hartman
maintainerPATCH 155/378 USB: usbcore: Introduce usb_bulk_msg_killable()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern <[email protected]>
commit 416909962e7cdf29fd01ac523c953f37708df93d upstream.
The synchronous message API in usbcore (usb_control_msg(), usb_bulk_msg(), and so on) uses uninterruptible waits. However, drivers may call these routines in the context of a user thread, which means it ought to be possible to at least kill them.
For this reason, introduce a new usb_bulk_msg_killable() function which behaves the same as usb_bulk_msg() except for using wait_for_completion_killable_timeout() instead of wait_for_completion_timeout(). The same can be done later for usb_control_msg() later on, if it turns out to be needed.
--- drivers/usb/core/message.c | 79 +++++++++++++++++++++++++++++++++++++++------ include/linux/usb.h | 5 +- 2 files changed, 72 insertions(+), 12 deletions(-)
drivers/usb/core/message.c +69 -10
@@ -42,16 +42,17 @@ static void usb_api_blocking_completion(/* -* Starts urb and waits for completion or timeout. Note that this call -* is NOT interruptible. Many device driver i/o requests should be -* interruptible and therefore these drivers should implement their -* own interruptible routines. +* Starts urb and waits for completion or timeout. +* Whether or not the wait is killable depends on the flag passed in. +* For example, compare usb_bulk_msg() and usb_bulk_msg_killable(). */ -static int usb_start_wait_urb (struct urb *urb,int timeout,int *actual_length) +static int usb_start_wait_urb (struct urb *urb,int timeout,int *actual_length, +bool killable) {struct api_context ctx;unsigned long expire;int retval; +long rc;init_completion (&ctx.done); urb->context = &ctx;
@@ -61,12 +62,21 @@ static int usb_start_wait_urb(struct urb goto out; expire = timeout ?msecs_to_jiffies (timeout) :MAX_SCHEDULE_TIMEOUT ; -if (!wait_for_completion_timeout (&ctx.done, expire)) { +if (killable) + rc =wait_for_completion_killable_timeout (&ctx.done, expire); +else + rc =wait_for_completion_timeout (&ctx.done, expire); +if (rc <=0 ) {usb_kill_urb (urb); - retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status); +if (ctx.status != -ENOENT ) + retval = ctx.status; +else if (rc ==0 ) + retval = -ETIMEDOUT ; +else + retval = rc; dev_dbg(&urb->dev->dev, - "%s timed out on ep%d%s len=%u/%u\n", + "%s timed out or killed on ep%d%s len=%u/%u\n", current->comm, usb_endpoint_num(&urb->ep->desc), usb_urb_dir_in(urb) ? "in" : "out",
@@ -100,7 +110,7 @@ static int usb_internal_control_msg(struusb_fill_control_urb (urb, usb_dev, pipe, (unsigned char *)cmd, data, len, usb_api_blocking_completion,NULL ); - retv =usb_start_wait_urb (urb, timeout, &length); + retv =usb_start_wait_urb (urb, timeout, &length, false);if (retv <0 )return retv;else
@@ -385,10 +395,59 @@ int usb_bulk_msg(struct usb_device *usb_usb_fill_bulk_urb (urb, usb_dev, pipe, data, len, usb_api_blocking_completion,NULL ); -return usb_start_wait_urb (urb, timeout, actual_length); +return usb_start_wait_urb (urb, timeout, actual_length, false); }EXPORT_SYMBOL_GPL (usb_bulk_msg); +/** +* usb_bulk_msg_killable - Builds a bulk urb, sends it off and waits for completion in a killable state +* @usb_dev: pointer to the usb device to send the message to +* @pipe: endpoint "pipe" to send the message to +* @data: pointer to the data to send +* @len: length in bytes of the data to send +* @actual_length: pointer to a location to put the actual length transferred +* in bytes +* @timeout: time in msecs to wait for the message to complete before +* timing out (if 0 the wait is forever) +* +* Context: task context, might sleep. +* +* This function is just like usb_blk_msg() except that it waits in a +* killable state. +* +* Return: +* If successful, 0. Otherwise a negative error number. The number of actual +* bytes transferred will be stored in the @actual_length parameter. +* +*/ +int usb_bulk_msg_killable (struct usb_device *usb_dev,unsigned int pipe, +void *data,int len,int *actual_length,int timeout) +{ +struct urb *urb; +struct usb_host_endpoint *ep; + + ep =usb_pipe_endpoint (usb_dev, pipe); +if (!ep || len <0 ) +return -EINVAL ; + + urb =usb_alloc_urb (0 ,GFP_KERNEL ); +if (!urb) +return -ENOMEM ; + +if ((ep->desc.bmAttributes &USB_ENDPOINT_XFERTYPE_MASK ) == +USB_ENDPOINT_XFER_INT ) { + pipe = (pipe & ~(3 <<30 )) | (PIPE_INTERRUPT <<30 ); +usb_fill_int_urb (urb, usb_dev, pipe, data, len, + usb_api_blocking_completion,NULL , + ep->desc.bInterval); + }else +usb_fill_bulk_urb (urb, usb_dev, pipe, data, len, + usb_api_blocking_completion,NULL ); + +return usb_start_wait_urb (urb, timeout, actual_length, true); +} +EXPORT_SYMBOL_GPL (usb_bulk_msg_killable); +/*-------------------------------------------------------------------*/ static void sg_clean (struct usb_sg_request *io)
include/linux/usb.h +3 -2
@@ -1869,8 +1869,9 @@ extern int usb_control_msg(struct usb_deextern int usb_interrupt_msg (struct usb_device *usb_dev,unsigned int pipe,void *data,int len,int *actual_length,int timeout);extern int usb_bulk_msg (struct usb_device *usb_dev,unsigned int pipe, -void *data,int len,int *actual_length, -int timeout); +void *data,int len,int *actual_length,int timeout); +extern int usb_bulk_msg_killable (struct usb_device *usb_dev,unsigned int pipe, +void *data,int len,int *actual_length,int timeout);/* wrappers around usb_control_msg() for the most common standard requests */ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
Greg Kroah-Hartman
maintainerPATCH 156/378 USB: usbtmc: Use usb_bulk_msg_killable() with user-specified timeouts
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern <[email protected]>
commit 7784caa413a89487dd14dd5c41db8753483b2acb upstream.
The usbtmc driver accepts timeout values specified by the user in an ioctl command, and uses these timeouts for some usb_bulk_msg() calls. Since the user can specify arbitrarily long timeouts and usb_bulk_msg() uses unkillable waits, call usb_bulk_msg_killable() instead to avoid the possibility of the user hanging a kernel thread indefinitely.
--- drivers/usb/class/usbtmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/usb/class/usbtmc.c +3 -3
@@ -727,7 +727,7 @@ static int usbtmc488_ioctl_trigger(struc buffer[1 ] = data->bTag; buffer[2 ] = ~data->bTag; - retval = usb_bulk_msg(data->usb_dev, + retval = usb_bulk_msg_killable(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out), buffer, USBTMC_HEADER_SIZE,
@@ -1347,7 +1347,7 @@ static int send_request_dev_dep_msg_in(s buffer[11 ] =0 ;/* Reserved */ /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, + retval = usb_bulk_msg_killable(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out), buffer, USBTMC_HEADER_SIZE,
@@ -1419,7 +1419,7 @@ static ssize_t usbtmc_read(struct file * actual =0 ;/* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, + retval = usb_bulk_msg_killable(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in), buffer, bufsize, &actual,
Greg Kroah-Hartman
maintainerPATCH 157/378 USB: core: Limit the length of unkillable synchronous timeouts
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern <[email protected]>
commit 1015c27a5e1a63efae2b18a9901494474b4d1dc3 upstream.
The usb_control_msg(), usb_bulk_msg(), and usb_interrupt_msg() APIs in usbcore allow unlimited timeout durations. And since they use uninterruptible waits, this leaves open the possibility of hanging a task for an indefinitely long time, with no way to kill it short of unplugging the target device.
To prevent this sort of problem, enforce a maximum limit on the length of these unkillable timeouts. The limit chosen here, somewhat arbitrarily, is 60 seconds. On many systems (although not all) this is short enough to avoid triggering the kernel's hung-task detector.
In addition, clear up the ambiguity of negative timeout values by treating them the same as 0, i.e., using the maximum allowed timeout.
--- drivers/usb/core/message.c | 27 +++++++++++++-------------- include/linux/usb.h | 3 +++ 2 files changed, 16 insertions(+), 14 deletions(-)
drivers/usb/core/message.c +13 -14
@@ -45,6 +45,8 @@ static void usb_api_blocking_completion(* Starts urb and waits for completion or timeout. * Whether or not the wait is killable depends on the flag passed in. * For example, compare usb_bulk_msg() and usb_bulk_msg_killable(). +* +* For non-killable waits, we enforce a maximum limit on the timeout value. */ static int usb_start_wait_urb (struct urb *urb,int timeout,int *actual_length,bool killable)
@@ -61,7 +63,9 @@ static int usb_start_wait_urb(struct urbif (unlikely (retval)) goto out; - expire = timeout ?msecs_to_jiffies (timeout) :MAX_SCHEDULE_TIMEOUT ; +if (!killable && (timeout <=0 || timeout >USB_MAX_SYNCHRONOUS_TIMEOUT )) + timeout =USB_MAX_SYNCHRONOUS_TIMEOUT ; + expire = (timeout >0 ) ?msecs_to_jiffies (timeout) :MAX_SCHEDULE_TIMEOUT ;if (killable) rc =wait_for_completion_killable_timeout (&ctx.done, expire);else
@@ -127,8 +131,7 @@ static int usb_internal_control_msg(stru* @index: USB message index value * @data: pointer to the data to send * @size: length in bytes of the data to send -* @timeout: time in msecs to wait for the message to complete before timing -* out (if 0 the wait is forever) +* @timeout: time in msecs to wait for the message to complete before timing out * * Context: task context, might sleep. *
@@ -183,8 +186,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg);* @index: USB message index value * @driver_data: pointer to the data to send * @size: length in bytes of the data to send -* @timeout: time in msecs to wait for the message to complete before timing -* out (if 0 the wait is forever) +* @timeout: time in msecs to wait for the message to complete before timing out * @memflags: the flags for memory allocation for buffers * * Context: !in_interrupt ()
@@ -242,8 +244,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_send);* @index: USB message index value * @driver_data: pointer to the data to be filled in by the message * @size: length in bytes of the data to be received -* @timeout: time in msecs to wait for the message to complete before timing -* out (if 0 the wait is forever) +* @timeout: time in msecs to wait for the message to complete before timing out * @memflags: the flags for memory allocation for buffers * * Context: !in_interrupt ()
@@ -314,8 +315,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);* @len: length in bytes of the data to send * @actual_length: pointer to a location to put the actual length transferred * in bytes -* @timeout: time in msecs to wait for the message to complete before -* timing out (if 0 the wait is forever) +* @timeout: time in msecs to wait for the message to complete before timing out * * Context: task context, might sleep. *
@@ -347,8 +347,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);* @len: length in bytes of the data to send * @actual_length: pointer to a location to put the actual length transferred * in bytes -* @timeout: time in msecs to wait for the message to complete before -* timing out (if 0 the wait is forever) +* @timeout: time in msecs to wait for the message to complete before timing out * * Context: task context, might sleep. *
@@ -408,12 +407,12 @@ EXPORT_SYMBOL_GPL(usb_bulk_msg);* @actual_length: pointer to a location to put the actual length transferred * in bytes * @timeout: time in msecs to wait for the message to complete before -* timing out (if 0 the wait is forever) +* timing out (if <= 0, the wait is as long as possible) * * Context: task context, might sleep. * -* This function is just like usb_blk_msg() except that it waits in a -* killable state. +* This function is just like usb_blk_msg(), except that it waits in a +* killable state and there is no limit on the timeout length. * * Return: * If successful, 0. Otherwise a negative error number. The number of actual
include/linux/usb.h +3 -0
@@ -1863,6 +1863,9 @@ void usb_free_noncoherent(struct usb_dev* SYNCHRONOUS CALL SUPPORT * *-------------------------------------------------------------------*/ +/* Maximum value allowed for timeout in synchronous routines below */ +#define USB_MAX_SYNCHRONOUS_TIMEOUT 60000/* ms */ +extern int usb_control_msg (struct usb_device *dev,unsigned int pipe,__u8 request,__u8 requesttype,__u16 value,__u16 index,void *data,__u16 size,int timeout);
Greg Kroah-Hartman
maintainerPATCH 158/378 usb: class: cdc-wdm: fix reordering issue in read code path
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
commit 8df672bfe3ec2268c2636584202755898e547173 upstream.
Quoting the bug report:
Due to compiler optimization or CPU out-of-order execution, the desc->length update can be reordered before the memmove. If this happens, wdm_read() can see the new length and call copy_to_user() on uninitialized memory. This also violates LKMM data race rules [1].
Fix it by using WRITE_ONCE and memory barriers.
--- drivers/usb/class/cdc-wdm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/class/cdc-wdm.c +3 -1
@@ -225,7 +225,8 @@ static void wdm_in_callback(struct urb */* we may already be in overflow */ if (!test_bit (WDM_OVERFLOW , &desc->flags)) {memmove (desc->ubuf + desc->length, desc->inbuf, length); - desc->length += length; +smp_wmb ();/* against wdm_read() */ +WRITE_ONCE (desc->length, desc->length + length); } } skip_error:
@@ -533,6 +534,7 @@ static ssize_t wdm_readreturn -ERESTARTSYS ; cntr =READ_ONCE (desc->length); +smp_rmb ();/* against wdm_in_callback() */ if (cntr ==0 ) { desc->read =0 ; retry:
Greg Kroah-Hartman
maintainerPATCH 159/378 usb: renesas_usbhs: fix use-after-free in ISR during device removal
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 3cbc242b88c607f55da3d0d0d336b49bf1e20412 upstream.
In usbhs_remove(), the driver frees resources (including the pipe array) while the interrupt handler (usbhs_interrupt) is still registered. If an interrupt fires after usbhs_pipe_remove() but before the driver is fully unbound, the ISR may access freed memory, causing a use-after-free.
Fix this by calling devm_free_irq() before freeing resources. This ensures the interrupt handler is both disabled and synchronized (waits for any running ISR to complete) before usbhs_pipe_remove() is called.
--- drivers/usb/renesas_usbhs/common.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/usb/renesas_usbhs/common.c +9 -0
@@ -815,6 +815,15 @@ static void usbhs_remove(struct platformusbhs_platform_call (priv, hardware_exit, pdev);reset_control_assert (priv->rsts); + +/* +* Explicitly free the IRQ to ensure the interrupt handler is +* disabled and synchronized before freeing resources. +* devm_free_irq() calls free_irq() which waits for any running +* ISR to complete, preventing UAF. +*/ +devm_free_irq (&pdev->dev, priv->irq, priv); +usbhs_mod_remove (priv);usbhs_fifo_remove (priv);usbhs_pipe_remove (priv);
Greg Kroah-Hartman
maintainerPATCH 160/378 usb: gadget: f_hid: fix SuperSpeed descriptors
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Keeping <[email protected]>
commit 7f58b4148ef5d8ee0fb7d8113dcc38ff5374babc upstream.
When adding dynamic configuration for bInterval, the value was removed from the static SuperSpeed endpoint descriptors but was not set from the configured value in hidg_bind(). Thus at SuperSpeed the interrupt endpoints have bInterval as zero which is not valid per the USB specification.
Add the missing setting for SuperSpeed endpoints.
--- drivers/usb/gadget/function/f_hid.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/gadget/function/f_hid.c +4 -0
@@ -1207,9 +1207,11 @@ static int hidg_bind(struct usb_configurif (!hidg->interval_user_set) { hidg_fs_in_ep_desc.bInterval =10 ; hidg_hs_in_ep_desc.bInterval =4 ; + hidg_ss_in_ep_desc.bInterval =4 ; }else { hidg_fs_in_ep_desc.bInterval = hidg->interval; hidg_hs_in_ep_desc.bInterval = hidg->interval; + hidg_ss_in_ep_desc.bInterval = hidg->interval; } hidg_ss_out_comp_desc.wBytesPerInterval =
@@ -1239,9 +1241,11 @@ static int hidg_bind(struct usb_configurif (!hidg->interval_user_set) { hidg_fs_out_ep_desc.bInterval =10 ; hidg_hs_out_ep_desc.bInterval =4 ; + hidg_ss_out_ep_desc.bInterval =4 ; }else { hidg_fs_out_ep_desc.bInterval = hidg->interval; hidg_hs_out_ep_desc.bInterval = hidg->interval; + hidg_ss_out_ep_desc.bInterval = hidg->interval; } status = usb_assign_descriptors(f, hidg_fs_descriptors_intout,
Greg Kroah-Hartman
maintainerPATCH 161/378 usb: mdc800: handle signal and read racing
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
commit 2d6d260e9a3576256fe9ef6d1f7930c9ec348723 upstream.
If a signal arrives after a read has partially completed, we need to return the number of bytes read. -EINTR is correct only if that number is zero.
--- drivers/usb/image/mdc800.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/image/mdc800.c +1 -1
@@ -707,7 +707,7 @@ static ssize_t mdc800_device_read (strucif (signal_pending (current)) {mutex_unlock (&mdc800->io_lock); -return -EINTR ; +return len == left ? -EINTR : len-left; } sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
Greg Kroah-Hartman
maintainerPATCH 162/378 usb: gadget: uvc: fix interval_duration calculation
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junzhong Pan <[email protected]>
commit 56135c0c60b07729401af9d329fa9c0eded845a6 upstream.
To correctly convert bInterval as interval_duration:
interval_duration = 2^(bInterval-1) * frame_interval
Current code uses a wrong left shift operand, computing 2^bInterval instead of 2^(bInterval-1).
--- drivers/usb/gadget/function/uvc_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/uvc_video.c +1 -1
@@ -513,7 +513,7 @@ uvc_video_prep_requests(struct uvc_videoreturn ; } - interval_duration =2 << (video->ep->desc->bInterval -1 ); + interval_duration =1 << (video->ep->desc->bInterval -1 );if (cdev->gadget->speed <USB_SPEED_HIGH ) interval_duration *=10000 ;else
Greg Kroah-Hartman
maintainerPATCH 163/378 usb: image: mdc800: kill download URB on timeout
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ziyi Guo <[email protected]>
commit 1be3b77de4eb89af8ae2fd6610546be778e25589 upstream.
mdc800_device_read() submits download_urb and waits for completion. If the timeout fires and the device has not responded, the function returns without killing the URB, leaving it active.
A subsequent read() resubmits the same URB while it is still in-flight, triggering the WARN in usb_submit_urb():
"URB submitted while active"
Check the return value of wait_event_timeout() and kill the URB if it indicates timeout, ensuring the URB is complete before its status is inspected or the URB is resubmitted.
Similar to
- commit 372c93131998 ("USB: yurex: fix control-URB timeout handling")
- commit b98d5000c505 ("media: rc: iguanair: handle timeouts")
--- drivers/usb/image/mdc800.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/image/mdc800.c +3 -1
@@ -730,9 +730,11 @@ static ssize_t mdc800_device_read (strucmutex_unlock (&mdc800->io_lock);return len-left; } -wait_event_timeout (mdc800->download_wait, + retval =wait_event_timeout (mdc800->download_wait, mdc800->downloaded,msecs_to_jiffies (TO_DOWNLOAD_GET_READY )); +if (!retval) +usb_kill_urb (mdc800->download_urb); mdc800->downloaded =0 ;if (mdc800->download_urb->status !=0 ) {
Greg Kroah-Hartman
maintainerPATCH 164/378 usb: gadget: f_tcm: Fix NULL pointer dereferences in nexus handling
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiasheng Jiang <[email protected]>
commit b9fde507355342a2d64225d582dc8b98ff5ecb19 upstream.
The tpg->tpg_nexus pointer in the USB Target driver is dynamically managed and tied to userspace configuration via ConfigFS. It can be NULL if the USB host sends requests before the nexus is fully established or immediately after it is dropped.
Currently, functions like bot_submit_command() and the data transfer paths retrieve tv_nexus = tpg->tpg_nexus and immediately dereference tv_nexus->tvn_se_sess without any validation. If a malicious or misconfigured USB host sends a BOT (Bulk-Only Transport) command during this race window, it triggers a NULL pointer dereference, leading to a kernel panic (local DoS).
This exposes an inconsistent API usage within the module, as peer functions like usbg_submit_command() and bot_send_bad_response() correctly implement a NULL check for tv_nexus before proceeding.
Fix this by bringing consistency to the nexus handling. Add the missing if (!tv_nexus) checks to the vulnerable BOT command and request processing paths, aborting the command gracefully with an error instead of crashing the system.
--- drivers/usb/gadget/function/f_tcm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/usb/gadget/function/f_tcm.c +14 -0
@@ -1222,6 +1222,13 @@ static void usbg_submit_cmd(struct usbg_ se_cmd = &cmd->se_cmd; tpg = cmd->fu->tpg; tv_nexus = tpg->tpg_nexus; +if (!tv_nexus) { +struct usb_gadget *gadget =fuas_to_gadget (cmd->fu); + +dev_err (&gadget->dev,"Missing nexus, ignoring command\n" ); +return ; + } + dir =get_cmd_dir (cmd->cmd_buf);if (dir <0 ) goto out;
@@ -1482,6 +1489,13 @@ static void bot_cmd_work(struct work_str se_cmd = &cmd->se_cmd; tpg = cmd->fu->tpg; tv_nexus = tpg->tpg_nexus; +if (!tv_nexus) { +struct usb_gadget *gadget =fuas_to_gadget (cmd->fu); + +dev_err (&gadget->dev,"Missing nexus, ignoring command\n" ); +return ; + } + dir =get_cmd_dir (cmd->cmd_buf);if (dir <0 ) goto out;
Greg Kroah-Hartman
maintainerPATCH 165/378 usb: gadget: f_ncm: Fix atomic context locking issue
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit 0d6c8144ca4d93253de952a5ea0028c19ed7ab68 upstream.
The ncm_set_alt function was holding a mutex to protect against races with configfs, which invokes the might-sleep function inside an atomic context.
Remove the struct net_device pointer from the f_ncm_opts structure to eliminate the contention. The connection state is now managed by a new boolean flag to preserve the use-after-free fix from
commit 6334b8e4553c ("usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport error").
BUG: sleeping function called from invalid context Call Trace: dump_stack_lvl+0x83/0xc0 dump_stack+0x14/0x16 __might_resched+0x389/0x4c0 __might_sleep+0x8e/0x100 ... __mutex_lock+0x6f/0x1740 ... ncm_set_alt+0x209/0xa40 set_config+0x6b6/0xb40 composite_setup+0x734/0x2b40 ...
--- drivers/usb/gadget/function/f_ncm.c | 29 ++++++++++--------------- drivers/usb/gadget/function/u_ether_configfs.h | 11 --------- drivers/usb/gadget/function/u_ncm.h | 1 3 files changed, 13 insertions(+), 28 deletions(-)
drivers/usb/gadget/function/f_ncm.c +12 -17
@@ -58,6 +58,7 @@ struct f_ncm {u8 notify_state;atomic_t notify_count;bool is_open; +bool is_connected;const struct ndp_parser_opts *parser_opts;bool is_crc;
@@ -864,7 +865,6 @@ invalid:static int ncm_set_alt (struct usb_function *f,unsigned intf,unsigned alt) {struct f_ncm *ncm =func_to_ncm (f); -struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;/* Control interface has only altsetting 0 */
@@ -887,13 +887,12 @@ static int ncm_set_alt(struct usb_functiif (alt >1 ) goto fail; - scoped_guard(mutex, &opts->lock) -if (opts->net) { -DBG (cdev,"reset ncm\n" ); - opts->net =NULL ; -gether_disconnect (&ncm->port); -ncm_reset_values (ncm); - } +if (ncm->is_connected) { +DBG (cdev,"reset ncm\n" ); + ncm->is_connected = false; +gether_disconnect (&ncm->port); +ncm_reset_values (ncm); + }/* * CDC Network only sends data in non-default altsettings.
@@ -926,8 +925,7 @@ static int ncm_set_alt(struct usb_functi net =gether_connect (&ncm->port);if (IS_ERR (net))return PTR_ERR (net); -scoped_guard (mutex, &opts->lock) - opts->net = net; + ncm->is_connected = true; }spin_lock (&ncm->lock);
@@ -1374,16 +1372,14 @@ err:static void ncm_disable (struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); -struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;DBG (cdev,"ncm deactivated\n" ); - scoped_guard(mutex, &opts->lock) -if (opts->net) { - opts->net =NULL ; -gether_disconnect (&ncm->port); - } +if (ncm->is_connected) { + ncm->is_connected = false; +gether_disconnect (&ncm->port); + }if (ncm->notify->enabled) {usb_ep_disable (ncm->notify);
@@ -1687,7 +1683,6 @@ static struct usb_function_instance *ncmif (!opts)return ERR_PTR (-ENOMEM ); - opts->net =NULL ; opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;gether_setup_opts_default (&opts->net_opts,"usb" );
drivers/usb/gadget/function/u_ether_configfs.h +1 -10
@@ -326,18 +326,9 @@ out: \ char *page) \ { \ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ -const char *name; \ \guard (mutex)(&opts->lock); \ -rtnl_lock (); \ -if (opts->net_opts.ifname_set) \ - name = opts->net_opts.name; \ -else if (opts->net) \ - name =netdev_name (opts->net); \ -else \ - name ="(inactive net_device)" ; \ -rtnl_unlock (); \ -return sysfs_emit (page,"%s\n" , name); \ +return sysfs_emit (page,"%s\n" , opts->net_opts.name); \ } \ \ static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
drivers/usb/gadget/function/u_ncm.h +0 -1
@@ -19,7 +19,6 @@struct f_ncm_opts {struct usb_function_instance func_inst; -struct net_device *net;struct gether_opts net_opts;struct config_group *ncm_interf_group;
Greg Kroah-Hartman
maintainerPATCH 166/378 usb: legacy: ncm: Fix NPE in gncm_bind
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit fde0634ad9856b3943a2d1a8cc8de174a63ac840 upstream.
Commit 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") deferred the allocation of the net_device. This change leads to a NULL pointer dereference in the legacy NCM driver as it attempts to access the net_device before it's fully instantiated.
Store the provided qmult, host_addr, and dev_addr into the struct ncm_opts->net_opts during gncm_bind(). These values will be properly applied to the net_device when it is allocated and configured later in the binding process by the NCM function driver.
--- drivers/usb/gadget/legacy/ncm.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/usb/gadget/legacy/ncm.c +10 -3
@@ -15,8 +15,10 @@/* #define DEBUG */ /* #define VERBOSE_DEBUG */ +#include <linux/hex.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/string.h> #include <linux/usb/composite.h> #include "u_ether.h"
@@ -129,6 +131,7 @@ static int gncm_bind(struct usb_compositstruct usb_gadget *gadget = cdev->gadget;struct f_ncm_opts *ncm_opts;int status; +u8 mac[ETH_ALEN ]; f_ncm_inst =usb_get_function_instance ("ncm" );if (IS_ERR (f_ncm_inst))
@@ -136,11 +139,15 @@ static int gncm_bind(struct usb_composit ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); -gether_set_qmult (ncm_opts->net, qmult); -if (!gether_set_host_addr (ncm_opts->net, host_addr)) + ncm_opts->net_opts.qmult = qmult; +if (host_addr &&mac_pton (host_addr, mac)) { +memcpy (&ncm_opts->net_opts.host_mac, mac,ETH_ALEN );pr_info ("using host ethernet address: %s" , host_addr); -if (!gether_set_dev_addr (ncm_opts->net, dev_addr)) + } +if (dev_addr &&mac_pton (dev_addr, mac)) { +memcpy (&ncm_opts->net_opts.dev_mac, mac,ETH_ALEN );pr_info ("using self ethernet address: %s" , dev_addr); + }/* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue.
Greg Kroah-Hartman
maintainerPATCH 167/378 Revert "usb: gadget: f_ncm: Fix atomic context locking issue"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit 11199720fac2debbe718aec11e026ab3330dc80d upstream.
This reverts commit 0d6c8144ca4d93253de952a5ea0028c19ed7ab68.
This commit is being reverted as part of a series-wide revert.
By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations.
This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail.
Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance.
All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst).
--- drivers/usb/gadget/function/f_ncm.c | 29 ++++++++++++++----------- drivers/usb/gadget/function/u_ether_configfs.h | 11 ++++++++- drivers/usb/gadget/function/u_ncm.h | 1 3 files changed, 28 insertions(+), 13 deletions(-)
drivers/usb/gadget/function/f_ncm.c +17 -12
@@ -58,7 +58,6 @@ struct f_ncm {u8 notify_state;atomic_t notify_count;bool is_open; -bool is_connected;const struct ndp_parser_opts *parser_opts;bool is_crc;
@@ -865,6 +864,7 @@ invalid:static int ncm_set_alt (struct usb_function *f,unsigned intf,unsigned alt) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;/* Control interface has only altsetting 0 */
@@ -887,12 +887,13 @@ static int ncm_set_alt(struct usb_functiif (alt >1 ) goto fail; -if (ncm->is_connected) { -DBG (cdev,"reset ncm\n" ); - ncm->is_connected = false; -gether_disconnect (&ncm->port); -ncm_reset_values (ncm); - } + scoped_guard(mutex, &opts->lock) +if (opts->net) { +DBG (cdev,"reset ncm\n" ); + opts->net =NULL ; +gether_disconnect (&ncm->port); +ncm_reset_values (ncm); + }/* * CDC Network only sends data in non-default altsettings.
@@ -925,7 +926,8 @@ static int ncm_set_alt(struct usb_functi net =gether_connect (&ncm->port);if (IS_ERR (net))return PTR_ERR (net); - ncm->is_connected = true; +scoped_guard (mutex, &opts->lock) + opts->net = net; }spin_lock (&ncm->lock);
@@ -1372,14 +1374,16 @@ err:static void ncm_disable (struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;DBG (cdev,"ncm deactivated\n" ); -if (ncm->is_connected) { - ncm->is_connected = false; -gether_disconnect (&ncm->port); - } + scoped_guard(mutex, &opts->lock) +if (opts->net) { + opts->net =NULL ; +gether_disconnect (&ncm->port); + }if (ncm->notify->enabled) {usb_ep_disable (ncm->notify);
@@ -1683,6 +1687,7 @@ static struct usb_function_instance *ncmif (!opts)return ERR_PTR (-ENOMEM ); + opts->net =NULL ; opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;gether_setup_opts_default (&opts->net_opts,"usb" );
drivers/usb/gadget/function/u_ether_configfs.h +10 -1
@@ -326,9 +326,18 @@ out: \ char *page) \ { \ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +const char *name; \ \guard (mutex)(&opts->lock); \ -return sysfs_emit (page,"%s\n" , opts->net_opts.name); \ +rtnl_lock (); \ +if (opts->net_opts.ifname_set) \ + name = opts->net_opts.name; \ +else if (opts->net) \ + name =netdev_name (opts->net); \ +else \ + name ="(inactive net_device)" ; \ +rtnl_unlock (); \ +return sysfs_emit (page,"%s\n" , name); \ } \ \ static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
drivers/usb/gadget/function/u_ncm.h +1 -0
@@ -19,6 +19,7 @@struct f_ncm_opts {struct usb_function_instance func_inst; +struct net_device *net;struct gether_opts net_opts;struct config_group *ncm_interf_group;
Greg Kroah-Hartman
maintainerPATCH 168/378 Revert "usb: legacy: ncm: Fix NPE in gncm_bind"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit f2524c0e6ff0a5f72f1e1a32441c69d3b56430c4 upstream.
This reverts commit fde0634ad9856b3943a2d1a8cc8de174a63ac840.
This commit is being reverted as part of a series-wide revert.
By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations.
This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail.
Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance.
All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst).
--- drivers/usb/gadget/legacy/ncm.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-)
drivers/usb/gadget/legacy/ncm.c +3 -10
@@ -15,10 +15,8 @@/* #define DEBUG */ /* #define VERBOSE_DEBUG */ -#include <linux/hex.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/string.h> #include <linux/usb/composite.h> #include "u_ether.h"
@@ -131,7 +129,6 @@ static int gncm_bind(struct usb_compositstruct usb_gadget *gadget = cdev->gadget;struct f_ncm_opts *ncm_opts;int status; -u8 mac[ETH_ALEN ]; f_ncm_inst =usb_get_function_instance ("ncm" );if (IS_ERR (f_ncm_inst))
@@ -139,15 +136,11 @@ static int gncm_bind(struct usb_composit ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); - ncm_opts->net_opts.qmult = qmult; -if (host_addr &&mac_pton (host_addr, mac)) { -memcpy (&ncm_opts->net_opts.host_mac, mac,ETH_ALEN ); +gether_set_qmult (ncm_opts->net, qmult); +if (!gether_set_host_addr (ncm_opts->net, host_addr))pr_info ("using host ethernet address: %s" , host_addr); - } -if (dev_addr &&mac_pton (dev_addr, mac)) { -memcpy (&ncm_opts->net_opts.dev_mac, mac,ETH_ALEN ); +if (!gether_set_dev_addr (ncm_opts->net, dev_addr))pr_info ("using self ethernet address: %s" , dev_addr); - }/* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue.
Greg Kroah-Hartman
maintainerPATCH 169/378 Revert "usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit 46662d3a1ad40282ba9f753cccc6f909ec4468cc upstream.
This reverts commit 0c0981126b99288ed354d3d414c8a5fd42ac9e25.
This commit is being reverted as part of a series-wide revert.
By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations.
This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail.
Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance.
All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst).
--- drivers/usb/gadget/function/u_ether.c | 15 --------------- drivers/usb/gadget/function/u_ether.h | 2 -- 2 files changed, 17 deletions(-)
drivers/usb/gadget/function/u_ether.c +0 -15
@@ -1125,21 +1125,6 @@ void gether_cleanup(struct eth_dev *dev) }EXPORT_SYMBOL_GPL (gether_cleanup); -void gether_unregister_free_netdev (struct net_device *net) -{ -if (!net) -return ; - -struct eth_dev *dev =netdev_priv (net); - -if (net->reg_state ==NETREG_REGISTERED ) { -unregister_netdev (net); -flush_work (&dev->work); - } -free_netdev (net); -} -EXPORT_SYMBOL_GPL (gether_unregister_free_netdev); -/** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching
drivers/usb/gadget/function/u_ether.h +0 -2
@@ -283,8 +283,6 @@ int gether_get_ifname(struct net_deviceint gether_set_ifname (struct net_device *net,const char *name,int len);void gether_cleanup (struct eth_dev *dev); -void gether_unregister_free_netdev (struct net_device *net); -DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_free_netdev(_T));void gether_setup_opts_default (struct gether_opts *opts,const char *name);void gether_apply_opts (struct net_device *net,struct gether_opts *opts);
Greg Kroah-Hartman
maintainerPATCH 170/378 Revert "usb: gadget: f_ncm: align net_device lifecycle with bind/unbind"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit 37893bc5de2460c543ec1aa8250c37a305234054 upstream.
This reverts commit 56a512a9b4107079f68701e7d55da8507eb963d9.
This commit is being reverted as part of a series-wide revert.
By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations.
This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail.
Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance.
All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst).
--- drivers/usb/gadget/function/f_ncm.c | 128 ++++++++++++++++++------------------ drivers/usb/gadget/function/u_ncm.h | 4 - 2 files changed, 66 insertions(+), 66 deletions(-)
drivers/usb/gadget/function/f_ncm.c +65 -63
@@ -83,11 +83,6 @@ static inline struct f_ncm *func_to_ncm( return container_of(f, struct f_ncm, port.func); } -static inline struct f_ncm_opts *func_to_ncm_opts (struct usb_function *f) -{ - return container_of(f->fi, struct f_ncm_opts, func_inst); -} -/*-------------------------------------------------------------------------*/ /*
@@ -864,7 +859,6 @@ invalid:static int ncm_set_alt (struct usb_function *f,unsigned intf,unsigned alt) {struct f_ncm *ncm =func_to_ncm (f); -struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;/* Control interface has only altsetting 0 */
@@ -887,13 +881,12 @@ static int ncm_set_alt(struct usb_functiif (alt >1 ) goto fail; - scoped_guard(mutex, &opts->lock) -if (opts->net) { -DBG (cdev,"reset ncm\n" ); - opts->net =NULL ; -gether_disconnect (&ncm->port); -ncm_reset_values (ncm); - } +if (ncm->netdev) { +DBG (cdev,"reset ncm\n" ); + ncm->netdev =NULL ; +gether_disconnect (&ncm->port); +ncm_reset_values (ncm); + }/* * CDC Network only sends data in non-default altsettings.
@@ -926,8 +919,7 @@ static int ncm_set_alt(struct usb_functi net =gether_connect (&ncm->port);if (IS_ERR (net))return PTR_ERR (net); -scoped_guard (mutex, &opts->lock) - opts->net = net; + ncm->netdev = net; }spin_lock (&ncm->lock);
@@ -1374,16 +1366,14 @@ err:static void ncm_disable (struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); -struct f_ncm_opts *opts =func_to_ncm_opts (f);struct usb_composite_dev *cdev = f->config->cdev;DBG (cdev,"ncm deactivated\n" ); - scoped_guard(mutex, &opts->lock) -if (opts->net) { - opts->net =NULL ; -gether_disconnect (&ncm->port); - } +if (ncm->netdev) { + ncm->netdev =NULL ; +gether_disconnect (&ncm->port); + }if (ncm->notify->enabled) {usb_ep_disable (ncm->notify);
@@ -1443,44 +1433,39 @@ static int ncm_bind(struct usb_configura {struct usb_composite_dev *cdev = c->cdev;struct f_ncm *ncm =func_to_ncm (f); -struct f_ncm_opts *ncm_opts =func_to_ncm_opts (f);struct usb_string *us;int status =0 ;struct usb_ep *ep; +struct f_ncm_opts *ncm_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; - struct net_device *netdev __free(free_gether_netdev) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_ecm (cdev->gadget))return -EINVAL ; + ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); +if (cdev->use_os_string) { os_desc_table =kzalloc (sizeof (*os_desc_table),GFP_KERNEL );if (!os_desc_table)return -ENOMEM ; } - netdev =gether_setup_default (); -if (IS_ERR (netdev)) -return -ENOMEM ; - - scoped_guard(mutex, &ncm_opts->lock) { -gether_apply_opts (netdev, &ncm_opts->net_opts); - netdev->mtu = ncm_opts->max_segment_size -ETH_HLEN ; +mutex_lock (&ncm_opts->lock); +gether_set_gadget (ncm_opts->net, cdev->gadget); +if (!ncm_opts->bound) { + ncm_opts->net->mtu = (ncm_opts->max_segment_size -ETH_HLEN ); + status =gether_register_netdev (ncm_opts->net); } +mutex_unlock (&ncm_opts->lock); -gether_set_gadget (netdev, cdev->gadget); - status =gether_register_netdev (netdev);if (status)return status; -/* export host's Ethernet address in CDC format */ - status =gether_get_host_addr_cdc (netdev, ncm->ethaddr, -sizeof (ncm->ethaddr)); -if (status <12 ) -return -EINVAL ; - ncm_string_defs[STRING_MAC_IDX ].s = ncm->ethaddr; + ncm_opts->bound = true; + + ncm_string_defs[1 ].s = ncm->ethaddr; us =usb_gstrings_attach (cdev, ncm_strings,ARRAY_SIZE (ncm_string_defs));
@@ -1578,8 +1563,6 @@ static int ncm_bind(struct usb_configura f->os_desc_n =1 ; } ncm->notify_req =no_free_ptr (request); - ncm->netdev =no_free_ptr (netdev); - ncm->port.ioport =netdev_priv (ncm->netdev); DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1594,19 +1577,19 @@ static inline struct f_ncm_opts *to_f_nc }/* f_ncm_item_ops */ -USB_ETHER_OPTS_ITEM (ncm); +USB_ETHERNET_CONFIGFS_ITEM (ncm);/* f_ncm_opts_dev_addr */ -USB_ETHER_OPTS_ATTR_DEV_ADDR (ncm); +USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR (ncm);/* f_ncm_opts_host_addr */ -USB_ETHER_OPTS_ATTR_HOST_ADDR (ncm); +USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR (ncm);/* f_ncm_opts_qmult */ -USB_ETHER_OPTS_ATTR_QMULT (ncm); +USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT (ncm);/* f_ncm_opts_ifname */ -USB_ETHER_OPTS_ATTR_IFNAME (ncm); +USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME (ncm);static ssize_t ncm_opts_max_segment_size_show (struct config_item *item,char *page)
@@ -1672,27 +1655,34 @@ static void ncm_free_inst(struct usb_funstruct f_ncm_opts *opts; opts = container_of(f, struct f_ncm_opts, func_inst); +if (opts->bound) +gether_cleanup (netdev_priv (opts->net)); +else +free_netdev (opts->net);kfree (opts->ncm_interf_group);kfree (opts); }static struct usb_function_instance *ncm_alloc_inst (void ) { -struct usb_function_instance *ret; +struct f_ncm_opts *opts;struct usb_os_desc *descs[1 ];char *names[1 ];struct config_group *ncm_interf_group; - struct f_ncm_opts *opts __free(kfree) = kzalloc(sizeof(*opts), GFP_KERNEL); + opts =kzalloc (sizeof (*opts),GFP_KERNEL );if (!opts)return ERR_PTR (-ENOMEM ); - - opts->net =NULL ; opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; -gether_setup_opts_default (&opts->net_opts,"usb" );mutex_init (&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; + opts->net =gether_setup_default (); +if (IS_ERR (opts->net)) { +struct net_device *net = opts->net; +kfree (opts); +return ERR_CAST (net); + } opts->max_segment_size =ETH_FRAME_LEN ;INIT_LIST_HEAD (&opts->ncm_os_desc.ext_prop);
@@ -1703,22 +1693,26 @@ static struct usb_function_instance *ncm ncm_interf_group =usb_os_desc_prepare_interf_dir (&opts->func_inst.group,1 , descs, names,THIS_MODULE ); -if (IS_ERR (ncm_interf_group)) +if (IS_ERR (ncm_interf_group)) { +ncm_free_inst (&opts->func_inst);return ERR_CAST (ncm_interf_group); + } opts->ncm_interf_group = ncm_interf_group; - ret = &opts->func_inst; -retain_and_null_ptr (opts); -return ret; +return &opts->func_inst; }static void ncm_free (struct usb_function *f) { -struct f_ncm_opts *opts =func_to_ncm_opts (f); +struct f_ncm *ncm; +struct f_ncm_opts *opts; -scoped_guard (mutex, &opts->lock) - opts->refcnt--; -kfree (func_to_ncm (f)); + ncm =func_to_ncm (f); + opts = container_of(f->fi, struct f_ncm_opts, func_inst); +kfree (ncm); +mutex_lock (&opts->lock); + opts->refcnt--; +mutex_unlock (&opts->lock); }static void ncm_unbind (struct usb_configuration *c,struct usb_function *f)
@@ -1742,15 +1736,13 @@ static void ncm_unbind(struct usb_configkfree (ncm->notify_req->buf);usb_ep_free_request (ncm->notify, ncm->notify_req); - - ncm->port.ioport =NULL ; -gether_cleanup (netdev_priv (ncm->netdev)); }static struct usb_function *ncm_alloc (struct usb_function_instance *fi) {struct f_ncm *ncm;struct f_ncm_opts *opts; +int status;/* allocate and initialize one new instance */ ncm =kzalloc (sizeof (*ncm),GFP_KERNEL );
@@ -1758,12 +1750,22 @@ static struct usb_function *ncm_alloc(streturn ERR_PTR (-ENOMEM ); opts = container_of(fi, struct f_ncm_opts, func_inst); +mutex_lock (&opts->lock); + opts->refcnt++; -scoped_guard (mutex, &opts->lock) - opts->refcnt++; +/* export host's Ethernet address in CDC format */ + status =gether_get_host_addr_cdc (opts->net, ncm->ethaddr, +sizeof (ncm->ethaddr)); +if (status <12 ) {/* strlen("01234567890a") */ +kfree (ncm); +mutex_unlock (&opts->lock); +return ERR_PTR (-EINVAL ); + }spin_lock_init (&ncm->lock);ncm_reset_values (ncm); + ncm->port.ioport =netdev_priv (opts->net); +mutex_unlock (&opts->lock); ncm->port.is_fixed = true; ncm->port.supports_multi_frame = true;
drivers/usb/gadget/function/u_ncm.h +1 -3
@@ -15,13 +15,11 @@#include <linux/usb/composite.h> -#include "u_ether.h" -struct f_ncm_opts {struct usb_function_instance func_inst;struct net_device *net; +bool bound; -struct gether_opts net_opts;struct config_group *ncm_interf_group;struct usb_os_desc ncm_os_desc;char ncm_ext_compat_id[16 ];
Greg Kroah-Hartman
maintainerPATCH 171/378 Revert "usb: gadget: u_ether: add gether_opts for config caching"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit 3131c1aff7cdffb96239f06f98e16188cbc2083f upstream.
This reverts commit e065c6a7e46c2ee9c677fdbf50035323d2de1215.
This commit is being reverted as part of a series-wide revert.
By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations.
This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail.
Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance.
All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst).
--- drivers/usb/gadget/function/u_ether.c | 30 ---- drivers/usb/gadget/function/u_ether.h | 28 --- drivers/usb/gadget/function/u_ether_configfs.h | 176 ------------------------- 3 files changed, 234 deletions(-)
drivers/usb/gadget/function/u_ether.c +0 -30
@@ -1039,36 +1039,6 @@ int gether_set_ifname(struct net_device }EXPORT_SYMBOL_GPL (gether_set_ifname); -void gether_setup_opts_default (struct gether_opts *opts,const char *name) -{ - opts->qmult =QMULT_DEFAULT ; -snprintf (opts->name,sizeof (opts->name),"%s%%d" , name); -eth_random_addr (opts->dev_mac); - opts->addr_assign_type =NET_ADDR_RANDOM ; -eth_random_addr (opts->host_mac); -} -EXPORT_SYMBOL_GPL (gether_setup_opts_default); - -void gether_apply_opts (struct net_device *net,struct gether_opts *opts) -{ -struct eth_dev *dev =netdev_priv (net); - - dev->qmult = opts->qmult; - -if (opts->ifname_set) { -strscpy (net->name, opts->name,sizeof (net->name)); - dev->ifname_set = true; - } - -memcpy (dev->host_mac, opts->host_mac,sizeof (dev->host_mac)); - -if (opts->addr_assign_type ==NET_ADDR_SET ) { -memcpy (dev->dev_mac, opts->dev_mac,sizeof (dev->dev_mac)); - net->addr_assign_type = opts->addr_assign_type; - } -} -EXPORT_SYMBOL_GPL (gether_apply_opts); -void gether_suspend (struct gether *link) {struct eth_dev *dev = link->ioport;
drivers/usb/gadget/function/u_ether.h +0 -28
@@ -38,31 +38,6 @@struct eth_dev ; -/** -* struct gether_opts - Options for Ethernet gadget function instances -* @name: Pattern for the network interface name (e.g., "usb%d"). -* Used to generate the net device name. -* @qmult: Queue length multiplier for high/super speed. -* @host_mac: The MAC address to be used by the host side. -* @dev_mac: The MAC address to be used by the device side. -* @ifname_set: True if the interface name pattern has been set by userspace. -* @addr_assign_type: The method used for assigning the device MAC address -* (e.g., NET_ADDR_RANDOM, NET_ADDR_SET). -* -* This structure caches network-related settings provided through configfs -* before the net_device is fully instantiated. This allows for early -* configuration while deferring net_device allocation until the function -* is bound. -*/ -struct gether_opts { -char name[IFNAMSIZ ]; -unsigned int qmult; -u8 host_mac[ETH_ALEN ]; -u8 dev_mac[ETH_ALEN ]; -bool ifname_set; -unsigned char addr_assign_type; -}; -/* * This represents the USB side of an "ethernet" link, managed by a USB * function which provides control and (maybe) framing. Two functions
@@ -284,9 +259,6 @@ int gether_set_ifname(struct net_devicevoid gether_cleanup (struct eth_dev *dev); -void gether_setup_opts_default (struct gether_opts *opts,const char *name); -void gether_apply_opts (struct net_device *net,struct gether_opts *opts); -void gether_suspend (struct gether *link);void gether_resume (struct gether *link);
drivers/usb/gadget/function/u_ether_configfs.h +0 -176
186 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 172/378 usb: gadget: f_ncm: Fix net_device lifecycle with device_move
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuen-Han Tsai <[email protected]>
commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 upstream.
The network device outlived its parent gadget device during disconnection, resulting in dangling sysfs links and null pointer dereference problems.
A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1] was reverted due to power management ordering concerns and a NO-CARRIER regression.
A subsequent attempt to defer net_device allocation to bind [2] broke 1:1 mapping between function instance and network device, making it impossible for configfs to report the resolved interface name. This results in a regression where the DHCP server fails on pmOS.
Use device_move to reparent the net_device between the gadget device and /sys/devices/virtual/ across bind/unbind cycles. This preserves the network interface across USB reconnection, allowing the DHCP server to retain their binding.
Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use __free(detach_gadget) macro to undo attachment on bind failure. The bind_count ensures device_move executes only on the first bind.
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/linux-usb/[email protected]/
--- drivers/usb/gadget/function/f_ncm.c | 38 ++++++++++++++++++++++------------ drivers/usb/gadget/function/u_ether.c | 22 +++++++++++++++++++ drivers/usb/gadget/function/u_ether.h | 26 +++++++++++++++++++++++ drivers/usb/gadget/function/u_ncm.h | 2 - 4 files changed, 74 insertions(+), 14 deletions(-)
drivers/usb/gadget/function/f_ncm.c +25 -13
@@ -1439,6 +1439,7 @@ static int ncm_bind(struct usb_configurastruct f_ncm_opts *ncm_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_ecm (cdev->gadget))
@@ -1452,18 +1453,19 @@ static int ncm_bind(struct usb_configurareturn -ENOMEM ; } -mutex_lock (&ncm_opts->lock); -gether_set_gadget (ncm_opts->net, cdev->gadget); -if (!ncm_opts->bound) { - ncm_opts->net->mtu = (ncm_opts->max_segment_size -ETH_HLEN ); - status =gether_register_netdev (ncm_opts->net); - } -mutex_unlock (&ncm_opts->lock); - -if (status) -return status; - - ncm_opts->bound = true; + scoped_guard(mutex, &ncm_opts->lock) +if (ncm_opts->bind_count ==0 ) { +if (!device_is_registered (&ncm_opts->net->dev)) { + ncm_opts->net->mtu = (ncm_opts->max_segment_size -ETH_HLEN ); +gether_set_gadget (ncm_opts->net, cdev->gadget); + status =gether_register_netdev (ncm_opts->net); + }else + status =gether_attach_gadget (ncm_opts->net, cdev->gadget); + +if (status) +return status; + net = ncm_opts->net; + } ncm_string_defs[1 ].s = ncm->ethaddr;
@@ -1564,6 +1566,9 @@ static int ncm_bind(struct usb_configura } ncm->notify_req =no_free_ptr (request); + ncm_opts->bind_count++; +retain_and_null_ptr (net); +DBG (cdev,"CDC Network: IN/%s OUT/%s NOTIFY/%s\n" , ncm->port.in_ep->name, ncm->port.out_ep->name, ncm->notify->name);
@@ -1655,7 +1660,7 @@ static void ncm_free_inst(struct usb_funstruct f_ncm_opts *opts; opts = container_of(f, struct f_ncm_opts, func_inst); -if (opts->bound) +if (device_is_registered (&opts->net->dev))gether_cleanup (netdev_priv (opts->net));else free_netdev (opts->net);
@@ -1718,9 +1723,12 @@ static void ncm_free(struct usb_functionstatic void ncm_unbind (struct usb_configuration *c,struct usb_function *f) {struct f_ncm *ncm =func_to_ncm (f); +struct f_ncm_opts *ncm_opts;DBG (c->cdev,"ncm unbind\n" ); + ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); +hrtimer_cancel (&ncm->task_timer);kfree (f->os_desc_table);
@@ -1736,6 +1744,10 @@ static void ncm_unbind(struct usb_configkfree (ncm->notify_req->buf);usb_ep_free_request (ncm->notify, ncm->notify_req); + + ncm_opts->bind_count--; +if (ncm_opts->bind_count ==0 ) +gether_detach_gadget (ncm_opts->net); }static struct usb_function *ncm_alloc (struct usb_function_instance *fi)
drivers/usb/gadget/function/u_ether.c +22 -0
@@ -896,6 +896,28 @@ void gether_set_gadget(struct net_device }EXPORT_SYMBOL_GPL (gether_set_gadget); +int gether_attach_gadget (struct net_device *net,struct usb_gadget *g) +{ +int ret; + + ret =device_move (&net->dev, &g->dev,DPM_ORDER_DEV_AFTER_PARENT ); +if (ret) +return ret; + +gether_set_gadget (net, g); +return 0 ; +} +EXPORT_SYMBOL_GPL (gether_attach_gadget); + +void gether_detach_gadget (struct net_device *net) +{ +struct eth_dev *dev =netdev_priv (net); + +device_move (&net->dev,NULL ,DPM_ORDER_NONE ); + dev->gadget =NULL ; +} +EXPORT_SYMBOL_GPL (gether_detach_gadget); +int gether_set_dev_addr (struct net_device *net,const char *dev_addr) {struct eth_dev *dev;
drivers/usb/gadget/function/u_ether.h +26 -0
@@ -151,6 +151,32 @@ static inline struct net_device *gether_void gether_set_gadget (struct net_device *net,struct usb_gadget *g);/** +* gether_attach_gadget - Reparent net_device to the gadget device. +* @net: The network device to reparent. +* @g: The target USB gadget device to parent to. +* +* This function moves the network device to be a child of the USB gadget +* device in the device hierarchy. This is typically done when the function +* is bound to a configuration. +* +* Returns 0 on success, or a negative error code on failure. +*/ +int gether_attach_gadget (struct net_device *net,struct usb_gadget *g); + +/** +* gether_detach_gadget - Detach net_device from its gadget parent. +* @net: The network device to detach. +* +* This function moves the network device to be a child of the virtual +* devices parent, effectively detaching it from the USB gadget device +* hierarchy. This is typically done when the function is unbound +* from a configuration but the instance is not yet freed. +*/ +void gether_detach_gadget (struct net_device *net); + +DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T)) + +/** * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address * @net: device representing this link * @dev_addr: eth address of this device
drivers/usb/gadget/function/u_ncm.h +1 -1
@@ -18,7 +18,7 @@struct f_ncm_opts {struct usb_function_instance func_inst;struct net_device *net; -bool bound; +int bind_count;struct config_group *ncm_interf_group;struct usb_os_desc ncm_os_desc;
Greg Kroah-Hartman
maintainerPATCH 173/378 mm/tracing: rss_stat: ensure curr is false from kthread context
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalesh Singh <[email protected]>
commit 079c24d5690262e83ee476e2a548e416f3237511 upstream.
The rss_stat trace event allows userspace tools, like Perfetto [1], to inspect per-process RSS metric changes over time.
The curr field was introduced to rss_stat in commit e4dcad204d3a ("rss_stat: add support to detect RSS updates of external mm"). Its intent is to indicate whether the RSS update is for the mm_struct of the current execution context; and is set to false when operating on a remote mm_struct (e.g., via kswapd or a direct reclaimer).
However, an issue arises when a kernel thread temporarily adopts a user process's mm_struct. Kernel threads do not have their own mm_struct and normally have current->mm set to NULL. To operate on user memory, they can "borrow" a memory context using kthread_use_mm(), which sets current->mm to the user process's mm.
This can be observed, for example, in the USB Function Filesystem (FFS) driver. The ffs_user_copy_worker() handles AIO completions and uses kthread_use_mm() to copy data to a user-space buffer. If a page fault occurs during this copy, the fault handler executes in the kthread's context.
At this point, current is the kthread, but current->mm points to the user process's mm. Since the rss_stat event (from the page fault) is for that same mm, the condition current->mm == mm becomes true, causing curr to be incorrectly set to true when the trace event is emitted.
This is misleading because it suggests the mm belongs to the kthread, confusing userspace tools that track per-process RSS changes and corrupting their mm_id-to-process association.
Fix this by ensuring curr is always false when the trace event is emitted from a kthread context by checking for the PF_KTHREAD flag.
--- include/trace/events/kmem.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
include/trace/events/kmem.h +7 -1
@@ -440,7 +440,13 @@ TRACE_EVENT(rss_stat,TP_fast_assign ( __entry->mm_id = mm_ptr_to_hash(mm); - __entry->curr = !!(current->mm == mm); +/* +* curr is true if the mm matches the current task's mm_struct. +* Since kthreads (PF_KTHREAD) have no mm_struct of their own +* but can borrow one via kthread_use_mm(), we must filter them +* out to avoid incorrectly attributing the RSS update to them. +*/ + __entry->curr = current->mm == mm && !(current->flags &PF_KTHREAD ); __entry->member = member; __entry->size = (percpu_counter_sum_positive (&mm->rss_stat[member]) <<PAGE_SHIFT );
Greg Kroah-Hartman
maintainerPATCH 174/378 ceph: fix i_nlink underrun during async unlink
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit ce0123cbb4a40a2f1bbb815f292b26e96088639f upstream.
During async unlink, we drop the i_nlink counter before we receive the completion (that will eventually update the i_nlink) because "we assume that the unlink will succeed". That is not a bad idea, but it races against deletions by other clients (or against the completion of our own unlink) and can lead to an underrun which emits a WARNING like this one:
WARNING: CPU: 85 PID: 25093 at fs/inode.c:407 drop_nlink+0x50/0x68 Modules linked in: CPU: 85 UID: 3221252029 PID: 25093 Comm: php-cgi8.1 Not tainted 6.14.11-cm4all1-ampere #655 Hardware name: Supermicro ARS-110M-NR/R12SPD-A, BIOS 1.1b 10/17/2023 pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : drop_nlink+0x50/0x68 lr : ceph_unlink+0x6c4/0x720 sp : ffff80012173bc90 x29: ffff80012173bc90 x28: ffff086d0a45aaf8 x27: ffff0871d0eb5680 x26: ffff087f2a64a718 x25: 0000020000000180 x24: 0000000061c88647 x23: 0000000000000002 x22: ffff07ff9236d800 x21: 0000000000001203 x20: ffff07ff9237b000 x19: ffff088b8296afc0 x18: 00000000f3c93365 x17: 0000000000070000 x16: ffff08faffcbdfe8 x15: ffff08faffcbdfec x14: 0000000000000000 x13: 45445f65645f3037 x12: 34385f6369706f74 x11: 0000a2653104bb20 x10: ffffd85f26d73290 x9 : ffffd85f25664f94 x8 : 00000000000000c0 x7 : 0000000000000000 x6 : 0000000000000002 x5 : 0000000000000081 x4 : 0000000000000481 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff08727d3f91e8 Call trace: drop_nlink+0x50/0x68 (P) vfs_unlink+0xb0/0x2e8 do_unlinkat+0x204/0x288 __arm64_sys_unlinkat+0x3c/0x80 invoke_syscall.constprop.0+0x54/0xe8 do_el0_svc+0xa4/0xc8 el0_svc+0x18/0x58 el0t_64_sync_handler+0x104/0x130 el0t_64_sync+0x154/0x158
In ceph_unlink(), a call to ceph_mdsc_submit_request() submits the CEPH_MDS_OP_UNLINK to the MDS, but does not wait for completion.
Meanwhile, between this call and the following drop_nlink() call, a worker thread may process a CEPH_CAP_OP_IMPORT, CEPH_CAP_OP_GRANT or just a CEPH_MSG_CLIENT_REPLY (the latter of which could be our own completion). These will lead to a set_nlink() call, updating the i_nlink counter to the value received from the MDS. If that new i_nlink value happens to be zero, it is illegal to decrement it further. But that is exactly what ceph_unlink() will do then.
The WARNING can be reproduced this way:
1. Force async unlink; only the async code path is affected. Having no real clue about Ceph internals, I was unable to find out why the MDS wouldn't give me the "Fxr" capabilities, so I patched get_caps_for_async_unlink() to always succeed.
(Note that the WARNING dump above was found on an unpatched kernel, without this kludge - this is not a theoretical bug.)
2. Add a sleep call after ceph_mdsc_submit_request() so the unlink completion gets handled by a worker thread before drop_nlink() is called. This guarantees that the i_nlink is already zero before drop_nlink() runs.
The solution is to skip the counter decrement when it is already zero, but doing so without a lock is still racy (TOCTOU). Since ceph_fill_inode() and handle_cap_grant() both hold the ceph_inode_info.i_ceph_lock spinlock while set_nlink() runs, this seems like the proper lock to protect the i_nlink updates.
I found prior art in NFS and SMB (using inode.i_lock) and AFS (using afs_vnode.cb_lock). All three have the zero check as well.
--- fs/ceph/dir.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
fs/ceph/dir.c +14 -1
@@ -1339,6 +1339,7 @@ static int ceph_unlink(struct inode *dirstruct ceph_client *cl = fsc->client;struct ceph_mds_client *mdsc = fsc->mdsc;struct inode *inode =d_inode (dentry); +struct ceph_inode_info *ci =ceph_inode (inode);struct ceph_mds_request *req;bool try_async =ceph_test_mount_opt (fsc,ASYNC_DIROPS );struct dentry *dn;
@@ -1424,7 +1425,19 @@ retry:* We have enough caps, so we assume that the unlink * will succeed. Fix up the target inode and dcache. */ -drop_nlink (inode); + +/* +* Protect the i_nlink update with i_ceph_lock +* to precent racing against ceph_fill_inode() +* handling our completion on a worker thread +* and don't decrement if i_nlink has already +* been updated to zero by this completion. +*/ +spin_lock (&ci->i_ceph_lock); +if (inode->i_nlink >0 ) +drop_nlink (inode); +spin_unlock (&ci->i_ceph_lock); +d_delete (dentry); }else {spin_lock (&fsc->async_unlink_conflict_lock);
Greg Kroah-Hartman
maintainerPATCH 175/378 ceph: do not skip the first folio of the next object in writeback
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hristo Venev <[email protected]>
commit 081a0b78ef30f5746cda3e92e28b4d4ae92901d1 upstream.
When ceph_process_folio_batch encounters a folio past the end of the current object, it should leave it in the batch so that it is picked up in the next iteration.
Removing the folio from the batch means that it does not get written back and remains dirty instead. This makes fsync() silently skip some of the data, delays capability release, and breaks coherence with O_DIRECT.
The link below contains instructions for reproducing the bug.
--- fs/ceph/addr.c | 1 - 1 file changed, 1 deletion(-)
fs/ceph/addr.c +0 -1
@@ -1330,7 +1330,6 @@ int ceph_process_folio_batch(struct addr }else if (rc == -E2BIG ) { rc =0 ;folio_unlock (folio); - ceph_wbc->fbatch.folios[i] =NULL ;break ; }
Greg Kroah-Hartman
maintainerPATCH 176/378 ceph: fix memory leaks in ceph_mdsc_build_path()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit 040d159a45ded7f33201421a81df0aa2a86e5a0b upstream.
Add __putname() calls to error code paths that did not free the "path" pointer obtained by __getname(). If ownership of this pointer is not passed to the caller via path_info.path, the function must free it before returning.
--- fs/ceph/mds_client.c | 3 +++ 1 file changed, 3 insertions(+)
fs/ceph/mds_client.c +3 -0
@@ -2768,6 +2768,7 @@ retry:if (ret <0 ) {dput (parent);dput (cur); +__putname (path);return ERR_PTR (ret); }
@@ -2777,6 +2778,7 @@ retry:if (len <0 ) {dput (parent);dput (cur); +__putname (path);return ERR_PTR (len); } }
@@ -2813,6 +2815,7 @@ retry:* cannot ever succeed. Creating paths that long is * possible with Ceph, but Linux cannot use them. */ +__putname (path);return ERR_PTR (-ENAMETOOLONG ); }
Greg Kroah-Hartman
maintainerPATCH 177/378 ALSA: usb-audio: Improve Focusrite sample rate filtering
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geoffrey D. Bennett <[email protected]>
[ Upstream commit 24d2d3c5f94007a5a0554065ab7349bb69e28bcb ]
Replace the bLength == 10 max_rate check in focusrite_valid_sample_rate() with filtering that also examines the bmControls VAL_ALT_SETTINGS bit.
When VAL_ALT_SETTINGS is readable, the device uses strict per-altsetting rate filtering (only the highest rate pair for that altsetting is valid). When it is not readable, all rates up to max_rate are valid.
For devices without the bLength == 10 Format Type descriptor extension but with VAL_ALT_SETTINGS readable and multiple altsettings (only seen in Scarlett 18i8 3rd Gen playback), fall back to the Focusrite
convention: alt 1 = 48kHz, alt 2 = 96kHz, alt 3 = 192kHz.
This produces correct rate tables for all tested Focusrite devices (all Scarlett 2nd, 3rd, and 4th Gen, Clarett+, and Vocaster) using only USB descriptors, allowing QUIRK_FLAG_VALIDATE_RATES to be removed for Focusrite in the next commit.
--- sound/usb/format.c | 70 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-)
sound/usb/format.c +65 -5
@@ -305,17 +305,48 @@ static bool s1810c_valid_sample_rate(struct audioformat *fp, }/* -* Many Focusrite devices supports a limited set of sampling rates per -* altsetting. Maximum rate is exposed in the last 4 bytes of Format Type -* descriptor which has a non-standard bLength = 10. +* Focusrite devices use rate pairs: 44100/48000, 88200/96000, and +* 176400/192000. Return true if rate is in the pair for max_rate. +*/ +static bool focusrite_rate_pair (unsigned int rate, +unsigned int max_rate) +{ +switch (max_rate) { +case 48000 :return rate ==44100 || rate ==48000 ; +case 96000 :return rate ==88200 || rate ==96000 ; +case 192000 :return rate ==176400 || rate ==192000 ; +default :return true; + } +} + +/* +* Focusrite devices report all supported rates in a single clock +* source but only a subset is valid per altsetting. +* +* Detection uses two descriptor features: +* +* 1. Format Type descriptor bLength == 10: non-standard extension +* with max sample rate in bytes 6..9. +* +* 2. bmControls VAL_ALT_SETTINGS readable bit: when set, the device +* only supports the highest rate pair for that altsetting, and when +* clear, all rates up to max_rate are valid. +* +* For devices without the bLength == 10 extension but with +* VAL_ALT_SETTINGS readable and multiple altsettings (only seen in +* Scarlett 18i8 3rd Gen playback), fall back to the Focusrite +* convention: alt 1 = 48kHz, alt 2 = 96kHz, alt 3 = 192kHz. */ static bool focusrite_valid_sample_rate (struct snd_usb_audio *chip,struct audioformat *fp,unsigned int rate) { +struct usb_interface *iface;struct usb_host_interface *alts; +struct uac2_as_header_descriptor *as;unsigned char *fmt;unsigned int max_rate; +bool val_alt; alts =snd_usb_get_host_interface (chip, fp->iface, fp->altsetting);if (!alts)
@@ -326,9 +357,21 @@ static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip,if (!fmt)return true; + as =snd_usb_find_csint_desc (alts->extra, alts->extralen, +NULL ,UAC_AS_GENERAL ); +if (!as) +return true; + + val_alt =uac_v2v3_control_is_readable (as->bmControls, +UAC2_AS_VAL_ALT_SETTINGS ); +if (fmt[0 ] ==10 ) {/* bLength */ max_rate =combine_quad (&fmt[6 ]); +if (val_alt) +return focusrite_rate_pair (rate, max_rate); + +/* No val_alt: rates fall through from higher */ switch (max_rate) {case 192000 :if (rate ==176400 || rate ==192000 )
@@ -344,12 +387,29 @@ static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip,usb_audio_info (chip,"%u:%d : unexpected max rate: %u\n" , fp->iface, fp->altsetting, max_rate); -return true; } } -return true; +if (!val_alt) +return true; + +/* Multi-altsetting device with val_alt but no max_rate +* in the format descriptor. Use Focusrite convention: +* alt 1 = 48kHz, alt 2 = 96kHz, alt 3 = 192kHz. +*/ + iface =usb_ifnum_to_if (chip->dev, fp->iface); +if (!iface || iface->num_altsetting <=2 ) +return true; + +switch (fp->altsetting) { +case 1 : max_rate =48000 ;break ; +case 2 : max_rate =96000 ;break ; +case 3 : max_rate =192000 ;break ; +default :return true; + } + +return focusrite_rate_pair (rate, max_rate); }/*
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 178/378 objtool/klp: Fix detection of corrupt static branch/call entries
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Poimboeuf <[email protected]>
[ Upstream commit f9fb44b0ecefc1f218db56661ed66d4e8d67317d ]
Patching a function which references a static key living in a kernel module is unsupported due to ordering issues inherent to late module patching:
1) Load a livepatch module which has a __jump_table entry which needs a klp reloc to reference static key K which lives in module M.
2) The __jump_table klp reloc does *not* get resolved because module M is not yet loaded.
3) jump_label_add_module() corrupts memory (or causes a panic) when dereferencing the uninitialized pointer to key K.
validate_special_section_klp_reloc() intends to prevent that from ever happening by catching it at build time. However, it incorrectly assumes the special section entry's reloc symbol references have already been converted from section symbols to object symbols, causing the validation to miss corruption in extracted static branch/call table entries.
Make sure the references have been properly converted before doing the validation.
--- tools/objtool/klp-diff.c | 3 +++ 1 file changed, 3 insertions(+)
tools/objtool/klp-diff.c +3 -0
@@ -1364,6 +1364,9 @@ static int validate_special_section_klp_reloc(struct elfs *e, struct symbol *symconst char *sym_modname;struct export *export; +if (convert_reloc_sym (e->patched, reloc)) +continue ; +/* Static branch/call keys are always STT_OBJECT */ if (reloc->sym->type !=STT_OBJECT ) {
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 179/378 objtool: Fix data alignment in elf_add_data()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Poimboeuf <[email protected]>
[ Upstream commit 356e4b2f5b80f757965f3f4d0219c81fca91b6f2 ]
Any data added to a section needs to be aligned in accordance with the section's sh_addralign value. Particularly strings added to a .str1.8 section. Otherwise you may get some funky strings.
--- tools/objtool/elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/elf.c +1 -1
@@ -1375,7 +1375,7 @@ void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_memcpy (sec->data->d_buf, data, size); sec->data->d_size = size; - sec->data->d_align =1 ; + sec->data->d_align = sec->sh.sh_addralign; offset =ALIGN (sec->sh.sh_size, sec->sh.sh_addralign); sec->sh.sh_size = offset + size;
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 180/378 objtool: Fix another stack overflow in validate_branch()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Poimboeuf <[email protected]>
[ Upstream commit 9a73f085dc91980ab7fcc5e9716f4449424b3b59 ]
The insn state is getting saved on the stack twice for each recursive iteration. No need for that, once is enough.
Fixes the following reported stack overflow:
drivers/scsi/qla2xxx/qla_dbg.o: error: SIGSEGV: objtool stack overflow! Segmentation fault
--- tools/objtool/check.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
tools/objtool/check.c +5 -5
@@ -3694,7 +3694,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func,static int validate_branch (struct objtool_file *file,struct symbol *func,struct instruction *insn,struct insn_state state);static int do_validate_branch (struct objtool_file *file,struct symbol *func, -struct instruction *insn,struct insn_state state); +struct instruction *insn,struct insn_state *state); static int validate_insn(struct objtool_file *file, struct symbol *func, struct instruction *insn, struct insn_state *statep,
@@ -3959,7 +3959,7 @@ static int validate_insn(struct objtool_file *file, struct symbol *func,* tools/objtool/Documentation/objtool.txt. */ static int do_validate_branch (struct objtool_file *file,struct symbol *func, -struct instruction *insn,struct insn_state state) +struct instruction *insn,struct insn_state *state) {struct instruction *next_insn, *prev_insn =NULL ;bool dead_end;
@@ -3990,7 +3990,7 @@ static int do_validate_branch(struct objtool_file *file, struct symbol *func,return 1 ; } - ret =validate_insn (file, func, insn, &state, prev_insn, next_insn, + ret =validate_insn (file, func, insn, state, prev_insn, next_insn, &dead_end);if (!insn->trace) {
@@ -4001,7 +4001,7 @@ static int do_validate_branch(struct objtool_file *file, struct symbol *func, }if (!dead_end && !next_insn) { -if (state.cfi.cfa.base ==CFI_UNDEFINED ) +if (state->cfi.cfa.base ==CFI_UNDEFINED )return 0 ;if (file->ignore_unreachables)return 0 ;
@@ -4026,7 +4026,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,int ret;trace_depth_inc (); - ret =do_validate_branch (file, func, insn, state); + ret =do_validate_branch (file, func, insn, &state);trace_depth_dec ();return ret;
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 181/378 irqchip/riscv-aplic: Preserve APLIC states across suspend/resume
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nick Hu <[email protected]>
[ Upstream commit 95a8ddde36601d0a645475fb080ed118db59c8c3 ]
The APLIC states might be reset when the platform enters a low power state, but the register states are not being preserved and restored, which prevents interrupt delivery after the platform resumes. Solve this by adding a syscore ops and a power management notifier to preserve and restore the APLIC states on suspend and resume.
[ tglx: Folded the build fix provided by Geert ]
Stable-dep-of: 620b6ded72a7 ("irqchip/riscv-aplic: Do not clear ACPI dependencies on probe failure")
--- drivers/irqchip/irq-riscv-aplic-direct.c | 10 ++ drivers/irqchip/irq-riscv-aplic-main.c | 170 ++++++++++++++++++++++- drivers/irqchip/irq-riscv-aplic-main.h | 19 +++ 3 files changed, 198 insertions(+), 1 deletion(-)
drivers/irqchip/irq-riscv-aplic-direct.c +10 -0
@@ -8,6 +8,7 @@#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/cpu.h> +#include <linux/cpumask.h> #include <linux/interrupt.h> #include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h>
@@ -171,6 +172,15 @@ static void aplic_idc_set_delivery(struct aplic_idc *idc, bool en)writel (de, idc->regs +APLIC_IDC_IDELIVERY ); } +void aplic_direct_restore_states (struct aplic_priv *priv) +{ + struct aplic_direct *direct = container_of(priv, struct aplic_direct, priv); +int cpu; + +for_each_cpu (cpu, &direct->lmask) +aplic_idc_set_delivery (per_cpu_ptr (&aplic_idcs, cpu), true); +} +static int aplic_direct_dying_cpu (unsigned int cpu) {if (aplic_direct_parent_irq)
drivers/irqchip/irq-riscv-aplic-main.c +169 -1
216 lines not on this page · raw message
drivers/irqchip/irq-riscv-aplic-main.h +19 -0
@@ -23,7 +23,25 @@ struct aplic_msicfg {u32 lhxw; }; +struct aplic_src_ctrl { +u32 sourcecfg; +u32 target; +u32 ie; +}; + +struct aplic_saved_regs { +u32 domaincfg; +#ifdef CONFIG_RISCV_M_MODE +u32 msiaddr; +u32 msiaddrh; +#endif +struct aplic_src_ctrl *srcs; +}; +struct aplic_priv { +struct list_head head; +struct notifier_block genpd_nb; +struct aplic_saved_regs saved_hw_regs;struct device *dev;u32 gsi_base;u32 nr_irqs;
@@ -40,6 +58,7 @@ int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base, unsigned long *hwirq, unsigned int *type);void aplic_init_hw_global (struct aplic_priv *priv,bool msi_mode);int aplic_setup_priv (struct aplic_priv *priv,struct device *dev,void __iomem *regs); +void aplic_direct_restore_states (struct aplic_priv *priv);int aplic_direct_setup (struct device *dev,void __iomem *regs);#ifdef CONFIG_RISCV_APLIC_MSI int aplic_msi_setup (struct device *dev,void __iomem *regs);
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 182/378 irqchip/riscv-aplic: Do not clear ACPI dependencies on probe failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jessica Liu <[email protected]>
[ Upstream commit 620b6ded72a7f0f77be6ec44d0462bb85729ab7a ]
aplic_probe() calls acpi_dev_clear_dependencies() unconditionally at the end, even when the preceding setup (MSI or direct mode) has failed. This is incorrect because if the device failed to probe, it should not be considered as active and should not clear dependencies for other devices waiting on it.
Fix this by returning immediately when the setup fails, skipping the ACPI dependency cleanup. Also, explicitly return 0 on success instead of relying on the value of 'rc' to make the success path clear.
--- drivers/irqchip/irq-riscv-aplic-main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/irqchip/irq-riscv-aplic-main.c +7 -4
@@ -372,18 +372,21 @@ static int aplic_probe(struct platform_device *pdev) rc =aplic_msi_setup (dev, regs); else rc =aplic_direct_setup (dev, regs); -if (rc) + +if (rc) {dev_err_probe (dev, rc,"failed to setup APLIC in %s mode\n" , msi_mode ?"MSI" :"direct" ); -else -register_syscore (&aplic_syscore); +return rc; + } + +register_syscore (&aplic_syscore);#ifdef CONFIG_ACPI if (!acpi_disabled)acpi_dev_clear_dependencies (ACPI_COMPANION (dev));#endif -return rc; +return 0 ; }static const struct of_device_id aplic_match[] = {
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 183/378 irqchip/riscv-aplic: Register syscore operations only once
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jessica Liu <[email protected]>
[ Upstream commit b330fbfd34d7624bec62b99ad88dba2614326a19 ]
Since commit 95a8ddde3660 ("irqchip/riscv-aplic: Preserve APLIC states across suspend/resume"), when multiple NUMA nodes exist and AIA is not configured as "none", aplic_probe() is called multiple times. This leads to register_syscore(&aplic_syscore) being invoked repeatedly, causing the following Oops:
list_add double add: new=ffffffffb91461f0, prev=ffffffffb91461f0, next=ffffffffb915c408.
[<ffffffffb7b5c8ca>] __list_add_valid_or_report+0x60/0xc0 [<ffffffffb7cc3236>] register_syscore+0x3e/0x70 [<ffffffffb7b8d61c>] aplic_probe+0xc6/0x112
Fix this by registering syscore operations only once, using a static variable aplic_syscore_registered to track registration.
[ tglx: Trim backtrace properly ]
--- drivers/irqchip/irq-riscv-aplic-main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/irqchip/irq-riscv-aplic-main.c +11 -1
@@ -116,6 +116,16 @@ static struct syscore aplic_syscore = { .ops = &aplic_syscore_ops, }; +static bool aplic_syscore_registered__ro_after_init ; + +static void aplic_syscore_init (void ) +{ +if (!aplic_syscore_registered) { +register_syscore (&aplic_syscore); + aplic_syscore_registered = true; + } +} +static int aplic_pm_notifier (struct notifier_block *nb,unsigned long action,void *data) { struct aplic_priv *priv = container_of(nb, struct aplic_priv, genpd_nb);
@@ -379,7 +389,7 @@ static int aplic_probe(struct platform_device *pdev)return rc; } -register_syscore (&aplic_syscore); +aplic_syscore_init ();#ifdef CONFIG_ACPI if (!acpi_disabled)
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 184/378 time/jiffies: Mark jiffies_64_to_clock_t() notrace
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 755a648e78f12574482d4698d877375793867fa1 ]
The trace_clock_jiffies() function that handles the "uptime" clock for tracing calls jiffies_64_to_clock_t(). This causes the function tracer to constantly recurse when the tracing clock is set to "uptime". Mark it notrace to prevent unnecessary recursion when using the "uptime" clock.
--- kernel/time/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/time.c +1 -1
@@ -702,7 +702,7 @@ EXPORT_SYMBOL(clock_t_to_jiffies);* * Return: jiffies_64 value converted to 64-bit "clock_t" (CLOCKS_PER_SEC) */ -u64 jiffies_64_to_clock_t (u64 x) +notrace u64 jiffies_64_to_clock_t(u64 x) {#if (TICK_NSEC % (NSEC_PER_SEC /USER_HZ )) ==0 # if HZ <USER_HZ
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 185/378 sched/mmcid: Prevent CID stalls due to concurrent forks
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
[ Upstream commit b2e48c429ec54715d16fefa719dd2fbded2e65be ]
A newly forked task is accounted as MMCID user before the task is visible in the process' thread list and the global task list. This creates the following problem:
CPU1 CPU2
fork()
sched_mm_cid_fork(tnew1)
tnew1->mm.mm_cid_users++;
tnew1->mm_cid.cid = getcid()
-> preemption
fork()
sched_mm_cid_fork(tnew2)
tnew2->mm.mm_cid_users++;
// Reaches the per CPU threshold
mm_cid_fixup_tasks_to_cpus()
for_each_other(current, p)
....As tnew1 is not visible yet, this fails to fix up the already allocated CID of tnew1. As a consequence a subsequent schedule in might fail to acquire a (transitional) CID and the machine stalls.
Move the invocation of sched_mm_cid_fork() after the new task becomes visible in the thread and the task list to prevent this.
This also makes it symmetrical vs. exit() where the task is removed as CID user before the task is removed from the thread and task lists.
--- include/linux/sched.h | 2 -- kernel/fork.c | 2 -- kernel/sched/core.c | 22 +++++++++++++++------- 3 files changed, 15 insertions(+), 11 deletions(-)
include/linux/sched.h +0 -2
@@ -2313,7 +2313,6 @@ static __always_inline void alloc_tag_restore(struct alloc_tag *tag, struct allo#ifdef CONFIG_SCHED_MM_CID void sched_mm_cid_before_execve (struct task_struct *t);void sched_mm_cid_after_execve (struct task_struct *t); -void sched_mm_cid_fork (struct task_struct *t);void sched_mm_cid_exit (struct task_struct *t); static __always_inline int task_mm_cid(struct task_struct *t) {
@@ -2322,7 +2321,6 @@ static __always_inline int task_mm_cid(struct task_struct *t)#else static inline void sched_mm_cid_before_execve (struct task_struct *t) { }static inline void sched_mm_cid_after_execve (struct task_struct *t) { } -static inline void sched_mm_cid_fork (struct task_struct *t) { }static inline void sched_mm_cid_exit (struct task_struct *t) { } static __always_inline int task_mm_cid(struct task_struct *t) {
kernel/fork.c +0 -2
@@ -1585,7 +1585,6 @@ static int copy_mm(u64 clone_flags, struct task_struct *tsk) tsk->mm = mm; tsk->active_mm = mm; -sched_mm_cid_fork (tsk);return 0 ; }
@@ -2496,7 +2495,6 @@ __latent_entropy struct task_struct *copy_process(exit_nsproxy_namespaces (p); bad_fork_cleanup_mm:if (p->mm) { -sched_mm_cid_exit (p);mm_clear_owner (p->mm, p);mmput (p->mm); }
kernel/sched/core.c +15 -7
@@ -4708,8 +4708,11 @@ void sched_cancel_fork(struct task_struct *p)scx_cancel_fork (p); } +static void sched_mm_cid_fork (struct task_struct *t); +void sched_post_fork (struct task_struct *p) { +sched_mm_cid_fork (p);uclamp_post_fork (p);scx_post_fork (p); }
@@ -10594,12 +10597,13 @@ static void mm_cid_do_fixup_tasks_to_cpus(struct mm_struct *mm)* possible switch back to per task mode happens either in the * deferred handler function or in the next fork()/exit(). * -* The caller has already transferred. The newly incoming task is -* already accounted for, but not yet visible. +* The caller has already transferred so remove it from the users +* count. The incoming task is already visible and has mm_cid.active, +* but has task::mm_cid::cid == UNSET. Still it needs to be accounted +* for. Concurrent fork()s might add more threads, but all of them have +* task::mm_cid::active = 0, so they don't affect the accounting here. */ - users = mm->mm_cid.users -2 ; -if (!users) -return ; + users = mm->mm_cid.users -1 ;guard (rcu)(); for_other_threads(current, t) {
@@ -10636,12 +10640,15 @@ static bool sched_mm_cid_add_user(struct task_struct *t, struct mm_struct *mm)return mm_update_max_cids (mm); } -void sched_mm_cid_fork (struct task_struct *t) +static void sched_mm_cid_fork (struct task_struct *t) {struct mm_struct *mm = t->mm;bool percpu; -WARN_ON_ONCE (!mm || t->mm_cid.cid !=MM_CID_UNSET ); +if (!mm) +return ; + +WARN_ON_ONCE (t->mm_cid.cid !=MM_CID_UNSET );guard (mutex)(&mm->mm_cid.mutex); scoped_guard(raw_spinlock_irq, &mm->mm_cid.lock) {
@@ -10833,6 +10840,7 @@ void mm_init_cid(struct mm_struct *mm, struct task_struct *p) }#else /* CONFIG_SCHED_MM_CID */ static inline void mm_update_cpus_allowed (struct mm_struct *mm,const struct cpumask *affmsk) { } +static inline void sched_mm_cid_fork (struct task_struct *t) { }#endif /* !CONFIG_SCHED_MM_CID */ static DEFINE_PER_CPU(struct sched_change_ctx, sched_change_ctx);
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 186/378 sched/mmcid: Handle vfork()/CLONE_VM correctly
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
[ Upstream commit 28b5a1395036d6c7a6c8034d85ad3d7d365f192c ]
Matthieu and Jiri reported stalls where a task endlessly loops in mm_get_cid() when scheduling in.
It turned out that the logic which handles vfork()'ed tasks is broken. It is invoked when the number of tasks associated to a process is smaller than the number of MMCID users. It then walks the task list to find the vfork()'ed task, but accounts all the already processed tasks as well.
If that double processing brings the number of to be handled tasks to 0, the walk stops and the vfork()'ed task's CID is not fixed up. As a consequence a subsequent schedule in fails to acquire a (transitional) CID and the machine stalls.
Cure this by removing the accounting condition and make the fixup always walk the full task list if it could not find the exact number of users in the process' thread list.
--- kernel/sched/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
kernel/sched/core.c +1 -4
@@ -10618,10 +10618,7 @@ static void mm_cid_do_fixup_tasks_to_cpus(struct mm_struct *mm)for_each_process_thread (p, t) {if (t == current || t->mm != mm)continue ; -if (mm_cid_fixup_task_to_cpu (t, mm)) { -if (--users ==0 ) -return ; - } +mm_cid_fixup_task_to_cpu (t, mm); } }
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 187/378 sched/mmcid: Remove pointless preempt guard
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
[ Upstream commit 7574ac6e49789ddee1b1be9b2afb42b4a1b4b1f4 ]
This is a leftover from the early versions of this function where it could be invoked without mm::mm_cid::lock held.
Remove it and add lockdep asserts instead.
--- kernel/sched/core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
kernel/sched/core.c +7 -5
@@ -10632,6 +10632,8 @@ static void mm_cid_fixup_tasks_to_cpus(void)static bool sched_mm_cid_add_user (struct task_struct *t,struct mm_struct *mm) { +lockdep_assert_held (&mm->mm_cid.lock); + t->mm_cid.active =1 ; mm->mm_cid.users++;return mm_update_max_cids (mm);
@@ -10684,12 +10686,12 @@ static void sched_mm_cid_fork(struct task_struct *t)static bool sched_mm_cid_remove_user (struct task_struct *t) { +lockdep_assert_held (&t->mm->mm_cid.lock); + t->mm_cid.active =0 ; -scoped_guard (preempt) { -/* Clear the transition bit */ - t->mm_cid.cid =cid_from_transit_cid (t->mm_cid.cid); -mm_unset_cid_on_task (t); - } +/* Clear the transition bit */ + t->mm_cid.cid =cid_from_transit_cid (t->mm_cid.cid); +mm_unset_cid_on_task (t); t->mm->mm_cid.users--;return mm_update_max_cids (t->mm); }
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 188/378 sched/mmcid: Avoid full tasklist walks
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
[ Upstream commit 192d852129b1b7c4f0ddbab95d0de1efd5ee1405 ]
Chasing vfork()'ed tasks on a CID ownership mode switch requires a full task list walk, which is obviously expensive on large systems.
Avoid that by keeping a list of tasks using a mm MMCID entity in mm::mm_cid and walk this list instead. This removes the proven to be flaky counting logic and avoids a full task list walk in the case of vfork()'ed tasks.
--- include/linux/rseq_types.h | 6 ++++- kernel/fork.c | 1 + kernel/sched/core.c | 54 +++++++++----------------------------- 3 files changed, 18 insertions(+), 43 deletions(-)
include/linux/rseq_types.h +5 -1
@@ -103,10 +103,12 @@ struct rseq_data { };* @active: MM CID is active for the task * @cid: The CID associated to the task either permanently or * borrowed from the CPU +* @node: Queued in the per MM MMCID list */ struct sched_mm_cid {unsigned int active;unsigned int cid; +struct hlist_node node; };/**
@@ -127,6 +129,7 @@ struct mm_cid_pcpu {* @work: Regular work to handle the affinity mode change case * @lock: Spinlock to protect against affinity setting which can't take @mutex * @mutex: Mutex to serialize forks and exits related to this mm +* @user_list: List of the MM CID users of a MM * @nr_cpus_allowed: The number of CPUs in the per MM allowed CPUs map. The map * is growth only. * @users: The number of tasks sharing this MM. Separate from mm::mm_users
@@ -147,13 +150,14 @@ struct mm_mm_cid {raw_spinlock_t lock;struct mutex mutex; +struct hlist_head user_list;/* Low frequency modified */ unsigned int nr_cpus_allowed;unsigned int users;unsigned int pcpu_thrs; unsigned int update_deferred; -}____cacheline_aligned_in_smp ; +}____cacheline_aligned ;#else /* CONFIG_SCHED_MM_CID */ struct mm_mm_cid { };struct sched_mm_cid { };
kernel/fork.c +1 -0
@@ -999,6 +999,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)#ifdef CONFIG_SCHED_MM_CID tsk->mm_cid.cid =MM_CID_UNSET ; tsk->mm_cid.active =0 ; +INIT_HLIST_NODE (&tsk->mm_cid.node);#endif return tsk;
kernel/sched/core.c +12 -42
94 lines not on this page · raw message
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 189/378 i3c: dw-i3c-master: Set SIR_REJECT in DAT on device attach and reattach
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Ng Ho Yin <[email protected]>
[ Upstream commit f311a05784634febd299f03476b80f3f18489767 ]
The DesignWare I3C master controller ACKs IBIs as soon as a valid Device Address Table (DAT) entry is present. This can create a race between device attachment (after DAA) and the point where the client driver enables IBIs via i3c_device_enable_ibi().
Set DEV_ADDR_TABLE_SIR_REJECT in the DAT entry during attach_i3c_dev() and reattach_i3c_dev() so that IBIs are rejected by default. The bit is managed thereafter by the existing dw_i3c_master_set_sir_enabled() function, which clears it in enable_ibi() after ENEC is issued, and restores it in disable_ibi() after DISEC.
--- drivers/i3c/master/dw-i3c-master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/i3c/master/dw-i3c-master.c +2 -2
@@ -1010,7 +1010,7 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, master->free_pos &= ~BIT (pos); } -writel (DEV_ADDR_TABLE_DYNAMIC_ADDR (dev->info.dyn_addr), +writel (DEV_ADDR_TABLE_DYNAMIC_ADDR (dev->info.dyn_addr) |DEV_ADDR_TABLE_SIR_REJECT , master->regs +DEV_ADDR_TABLE_LOC (master->datstartaddr, data->index));
@@ -1039,7 +1039,7 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) master->free_pos &= ~BIT (pos);i3c_dev_set_master_data (dev, data); -writel (DEV_ADDR_TABLE_DYNAMIC_ADDR (master->devs[pos].addr), +writel (DEV_ADDR_TABLE_DYNAMIC_ADDR (master->devs[pos].addr) |DEV_ADDR_TABLE_SIR_REJECT , master->regs +DEV_ADDR_TABLE_LOC (master->datstartaddr, data->index));
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 190/378 powerpc, perf: Check that current->mm is alive before getting user callchain
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viktor Malik <[email protected]>
[ Upstream commit e9bbfb4bfa86c6b5515b868d6982ac60505d7e39 ]
It may happen that mm is already released, which leads to kernel panic.
This adds the NULL check for current->mm, similarly to
commit 20afc60f892d ("x86, perf: Check that current->mm is alive before getting user callchain").
I was getting this panic when running a profiling BPF program (profile.py from bcc-tools):
[26215.051935] Kernel attempted to read user page (588) - exploit attempt? (uid: 0)
[26215.051950] BUG: Kernel NULL pointer dereference on read at 0x00000588
[26215.051952] Faulting instruction address: 0xc00000000020fac0
[26215.051957] Oops: Kernel access of bad area, sig: 11 [#1]
[...]
[26215.052049] Call Trace:
[26215.052050] [c000000061da6d30] [c00000000020fc10] perf_callchain_user_64+0x2d0/0x490 (unreliable)
[26215.052054] [c000000061da6dc0] [c00000000020f92c] perf_callchain_user+0x1c/0x30
[26215.052057] [c000000061da6de0] [c0000000005ab2a0] get_perf_callchain+0x100/0x360
[26215.052063] [c000000061da6e70] [c000000000573bc8] bpf_get_stackid+0x88/0xf0
[26215.052067] [c000000061da6ea0] [c008000000042258] bpf_prog_16d4ab9ab662f669_do_perf_event+0xf8/0x274
[...]In addition, move storing the top-level stack entry to generic perf_callchain_user to make sure the top-evel entry is always captured, even if current->mm is NULL.
--- arch/powerpc/perf/callchain.c | 5 +++++ arch/powerpc/perf/callchain_32.c | 1 - arch/powerpc/perf/callchain_64.c | 1 - 3 files changed, 5 insertions(+), 2 deletions(-)
arch/powerpc/perf/callchain.c +5 -0
@@ -103,6 +103,11 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *revoid perf_callchain_user (struct perf_callchain_entry_ctx *entry,struct pt_regs *regs) { +perf_callchain_store (entry,perf_arch_instruction_pointer (regs)); + +if (!current->mm) +return ; +if (!is_32bit_task ())perf_callchain_user_64 (entry, regs);else
arch/powerpc/perf/callchain_32.c +0 -1
@@ -142,7 +142,6 @@ void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry, next_ip =perf_arch_instruction_pointer (regs); lr = regs->link; sp = regs->gpr[1 ]; -perf_callchain_store (entry, next_ip);while (entry->nr < entry->max_stack) { fp = (unsigned int __user *) (unsigned long ) sp;
arch/powerpc/perf/callchain_64.c +0 -1
@@ -77,7 +77,6 @@ void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry, next_ip =perf_arch_instruction_pointer (regs); lr = regs->link; sp = regs->gpr[1 ]; -perf_callchain_store (entry, next_ip);while (entry->nr < entry->max_stack) { fp = (unsigned long __user *) sp;
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 191/378 scsi: ufs: core: Fix SError in ufshcd_rtc_work() during UFS suspend
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wang Shuaiwei <[email protected]>
[ Upstream commit b0bd84c39289ef6a6c3827dd52c875659291970a ]
In __ufshcd_wl_suspend(), cancel_delayed_work_sync() is called to cancel the UFS RTC work, but it is placed after ufshcd_vops_suspend(hba, pm_op, POST_CHANGE). This creates a race condition where ufshcd_rtc_work() can still be running while ufshcd_vops_suspend() is executing. When UFSHCD_CAP_CLK_GATING is not supported, the condition !hba->clk_gating.active_reqs is always true, causing ufshcd_update_rtc() to be executed. Since ufshcd_vops_suspend() typically performs clock gating operations, executing ufshcd_update_rtc() at that moment triggers an SError. The kernel panic trace is as follows:
Kernel panic - not syncing: Asynchronous SError Interrupt Call trace: dump_backtrace+0xec/0x128 show_stack+0x18/0x28 dump_stack_lvl+0x40/0xa0 dump_stack+0x18/0x24 panic+0x148/0x374 nmi_panic+0x3c/0x8c arm64_serror_panic+0x64/0x8c do_serror+0xc4/0xc8 el1h_64_error_handler+0x34/0x4c el1h_64_error+0x68/0x6c el1_interrupt+0x20/0x58 el1h_64_irq_handler+0x18/0x24 el1h_64_irq+0x68/0x6c ktime_get+0xc4/0x12c ufshcd_mcq_sq_stop+0x4c/0xec ufshcd_mcq_sq_cleanup+0x64/0x1dc ufshcd_clear_cmd+0x38/0x134 ufshcd_issue_dev_cmd+0x298/0x4d0 ufshcd_exec_dev_cmd+0x1a4/0x1c4 ufshcd_query_attr+0xbc/0x19c ufshcd_rtc_work+0x10c/0x1c8 process_scheduled_works+0x1c4/0x45c worker_thread+0x32c/0x3e8 kthread+0x120/0x1d8 ret_from_fork+0x10/0x20
Fix this by moving cancel_delayed_work_sync() before the call to ufshcd_vops_suspend(hba, pm_op, PRE_CHANGE), ensuring the UFS RTC work is fully completed or cancelled at that point.
--- drivers/ufs/core/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ufs/core/ufshcd.c +1 -1
@@ -10061,6 +10061,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) }flush_work (&hba->eeh_work); +cancel_delayed_work_sync (&hba->ufs_rtc_update_work); ret =ufshcd_vops_suspend (hba, pm_op,PRE_CHANGE );if (ret)
@@ -10115,7 +10116,6 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto set_link_active; -cancel_delayed_work_sync (&hba->ufs_rtc_update_work); goto out; set_link_active:
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 192/378 scsi: qla2xxx: Completely fix fcport double free
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Riabchun <[email protected]>
[ Upstream commit c0b7da13a04bd70ef6070bfb9ea85f582294560a ]
In qla24xx_els_dcmd_iocb() sp->free is set to qla2x00_els_dcmd_sp_free(). When an error happens, this function is called by qla2x00_sp_release(), when kref_put() releases the first and the last reference.
qla2x00_els_dcmd_sp_free() frees fcport by calling qla2x00_free_fcport(). Doing it one more time after kref_put() is a bad idea.
--- drivers/scsi/qla2xxx/qla_iocb.c | 2 -- 1 file changed, 2 deletions(-)
drivers/scsi/qla2xxx/qla_iocb.c +0 -2
@@ -2751,7 +2751,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,if (!elsio->u.els_logo.els_logo_pyld) {/* ref: INIT */ kref_put (&sp->cmd_kref, qla2x00_sp_release); -qla2x00_free_fcport (fcport);return QLA_FUNCTION_FAILED ; }
@@ -2776,7 +2775,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,if (rval !=QLA_SUCCESS ) {/* ref: INIT */ kref_put (&sp->cmd_kref, qla2x00_sp_release); -qla2x00_free_fcport (fcport);return QLA_FUNCTION_FAILED ; }
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 193/378 scsi: hisi_sas: Fix NULL pointer exception during user_scan()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xingui Yang <[email protected]>
[ Upstream commit 8ddc0c26916574395447ebf4cff684314f6873a9 ]
user_scan() invokes updated sas_user_scan() for channel 0, and if successful, iteratively scans remaining channels (1 to shost->max_channel) via scsi_scan_host_selected() in commit 37c4e72b0651 ("scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans"). However, hisi_sas supports only one channel, and the current value of max_channel is
1. sas_user_scan() for channel 1 will trigger the following NULL pointer exception:
[ 441.554662] Unable to handle kernel NULL pointer dereference at virtual address 00000000000008b0 [ 441.554699] Mem abort info: [ 441.554710] ESR = 0x0000000096000004 [ 441.554718] EC = 0x25: DABT (current EL), IL = 32 bits [ 441.554723] SET = 0, FnV = 0 [ 441.554726] EA = 0, S1PTW = 0 [ 441.554730] FSC = 0x04: level 0 translation fault [ 441.554735] Data abort info: [ 441.554737] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 441.554742] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 441.554747] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 441.554752] user pgtable: 4k pages, 48-bit VAs, pgdp=00000828377a6000 [ 441.554757] [00000000000008b0] pgd=0000000000000000, p4d=0000000000000000 [ 441.554769] Internal error: Oops: 0000000096000004 [#1] SMP [ 441.629589] Modules linked in: arm_spe_pmu arm_smmuv3_pmu tpm_tis_spi hisi_uncore_sllc_pmu hisi_uncore_pa_pmu hisi_uncore_l3c_pmu hisi_uncore_hha_pmu hisi_uncore_ddrc_pmu hisi_uncore_cpa_pmu hns3_pmu hisi_ptt hisi_pcie_pmu tpm_tis_core spidev spi_hisi_sfc_v3xx hisi_uncore_pmu spi_dw_mmio fuse hclge hclge_common hisi_sec2 hisi_hpre hisi_zip hisi_qm hns3 hisi_sas_v3_hw sm3_ce sbsa_gwdt hnae3 hisi_sas_main uacce hisi_dma i2c_hisi dm_mirror dm_region_hash dm_log dm_mod [ 441.670819] CPU: 46 UID: 0 PID: 6994 Comm: bash Kdump: loaded Not tainted 7.0.0-rc2+ #84 PREEMPT [ 441.691327] pstate: 81400009 (Nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [ 441.698277] pc : sas_find_dev_by_rphy+0x44/0x118 [ 441.702896] lr : sas_find_dev_by_rphy+0x3c/0x118 [ 441.707502] sp : ffff80009abbba40 [ 441.710805] x29: ffff80009abbba40 x28: ffff082819a40008 x27: ffff082810c37c08 [ 441.717930] x26: ffff082810c37c28 x25: ffff082819a40290 x24: ffff082810c37c00 [ 441.725054] x23: 0000000000000000 x22: 0000000000000001 x21: ffff082819a40000 [ 441.732179] x20: ffff082819a40290 x19: 0000000000000000 x18: 0000000000000020 [ 441.739304] x17: 0000000000000000 x16: ffffb5dad6bda690 x15: 00000000ffffffff [ 441.746428] x14: ffff082814c3b26c x13: 00000000ffffffff x12: ffff082814c3b26a [ 441.753553] x11: 00000000000000c0 x10: 000000000000003a x9 : ffffb5dad5ea94f4 [ 441.760678] x8 : 000000000000003a x7 : ffff80009abbbab0 x6 : 0000000000000030 [ 441.767802] x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 [ 441.774926] x2 : ffff08280f35a300 x1 : ffffb5dad7127180 x0 : 0000000000000000 [ 441.782053] Call trace: [ 441.784488] sas_find_dev_by_rphy+0x44/0x118 (P) [ 441.789095] sas_target_alloc+0x24/0xb0 [ 441.792920] scsi_alloc_target+0x290/0x330 [ 441.797010] __scsi_scan_target+0x88/0x258 [ 441.801096] scsi_scan_channel+0x74/0xb8 [ 441.805008] scsi_scan_host_selected+0x170/0x188 [ 441.809615] sas_user_scan+0xfc/0x148 [ 441.813267] store_scan+0x10c/0x180 [ 441.816743] dev_attr_store+0x20/0x40 [ 441.820398] sysfs_kf_write+0x84/0xa8 [ 441.824054] kernfs_fop_write_iter+0x130/0x1c8 [ 441.828487] vfs_write+0x2c0/0x370 [ 441.831880] ksys_write+0x74/0x118 [ 441.835271] __arm64_sys_write+0x24/0x38 [ 441.839182] invoke_syscall+0x50/0x120 [ 441.842919] el0_svc_common.constprop.0+0xc8/0xf0 [ 441.847611] do_el0_svc+0x24/0x38 [ 441.850913] el0_svc+0x38/0x158 [ 441.854043] el0t_64_sync_handler+0xa0/0xe8 [ 441.858214] el0t_64_sync+0x1ac/0x1b0 [ 441.861865] Code: aa1303e0 97ff70a8 34ffff80 d10a4273 (f9445a75) [ 441.867946] ---[ end trace 0000000000000000 ]---
Therefore, set max_channel to 0.
--- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/hisi_sas/hisi_sas_main.c +1 -1
@@ -2578,7 +2578,7 @@ int hisi_sas_probe(struct platform_device *pdev, shost->transportt = hisi_sas_stt; shost->max_id =HISI_SAS_MAX_DEVICES ; shost->max_lun = ~0 ; - shost->max_channel =1 ; + shost->max_channel =0 ; shost->max_cmd_len =HISI_SAS_MAX_CDB_LEN ;if (hisi_hba->hw->slot_index_alloc) { shost->can_queue =HISI_SAS_MAX_COMMANDS ;
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +1 -1
@@ -4993,7 +4993,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->transportt = hisi_sas_stt; shost->max_id =HISI_SAS_MAX_DEVICES ; shost->max_lun = ~0 ; - shost->max_channel =1 ; + shost->max_channel =0 ; shost->max_cmd_len =HISI_SAS_MAX_CDB_LEN ; shost->can_queue =HISI_SAS_UNRESERVED_IPTT ; shost->cmd_per_lun =HISI_SAS_UNRESERVED_IPTT ;
Signature · 1 line
2.51.0
Greg Kroah-Hartman
maintainerPATCH 194/378 mm/kfence: fix KASAN hardware tag faults during late enablement
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Potapenko <[email protected]>
commit d155aab90fffa00f93cea1f107aef0a3d548b2ff upstream.
When KASAN hardware tags are enabled, re-enabling KFENCE late (via /sys/module/kfence/parameters/sample_interval) causes KASAN faults.
This happens because the KFENCE pool and metadata are allocated via the page allocator, which tags the memory, while KFENCE continues to access it using untagged pointers during initialization.
Use __GFP_SKIP_KASAN for late KFENCE pool and metadata allocations to ensure the memory remains untagged, consistent with early allocations from memblock. To support this, add __GFP_SKIP_KASAN to the allowlist in __alloc_contig_verify_gfp_mask().
--- mm/kfence/core.c | 14 ++++++++------ mm/page_alloc.c | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-)
mm/kfence/core.c +8 -6
@@ -984,14 +984,14 @@ static int kfence_init_late(void)#ifdef CONFIG_CONTIG_ALLOC struct page *pages; - pages =alloc_contig_pages (nr_pages_pool,GFP_KERNEL , first_online_node, -NULL ); + pages =alloc_contig_pages (nr_pages_pool,GFP_KERNEL | __GFP_SKIP_KASAN, + first_online_node,NULL );if (!pages)return -ENOMEM ; __kfence_pool =page_to_virt (pages); - pages =alloc_contig_pages (nr_pages_meta,GFP_KERNEL , first_online_node, -NULL ); + pages =alloc_contig_pages (nr_pages_meta,GFP_KERNEL | __GFP_SKIP_KASAN, + first_online_node,NULL );if (pages) kfence_metadata_init =page_to_virt (pages);#else
@@ -1001,11 +1001,13 @@ static int kfence_init_late(void) return -EINVAL; } - __kfence_pool =alloc_pages_exact (KFENCE_POOL_SIZE ,GFP_KERNEL ); + __kfence_pool =alloc_pages_exact (KFENCE_POOL_SIZE , +GFP_KERNEL | __GFP_SKIP_KASAN);if (!__kfence_pool)return -ENOMEM ; - kfence_metadata_init =alloc_pages_exact (KFENCE_METADATA_SIZE ,GFP_KERNEL ); + kfence_metadata_init =alloc_pages_exact (KFENCE_METADATA_SIZE , +GFP_KERNEL | __GFP_SKIP_KASAN);#endif if (!kfence_metadata_init)
mm/page_alloc.c +2 -1
@@ -6941,7 +6941,8 @@ static int __alloc_contig_verify_gfp_mas {const gfp_t reclaim_mask = __GFP_IO | __GFP_FS | __GFP_RECLAIM;const gfp_t action_mask = __GFP_COMP | __GFP_RETRY_MAYFAIL | __GFP_NOWARN | - __GFP_ZERO | __GFP_ZEROTAGS | __GFP_SKIP_ZERO; + __GFP_ZERO | __GFP_ZEROTAGS | __GFP_SKIP_ZERO | + __GFP_SKIP_KASAN;const gfp_t cc_action_mask = __GFP_RETRY_MAYFAIL | __GFP_NOWARN;/*
Greg Kroah-Hartman
maintainerPATCH 195/378 mmc: mmci: Fix device_node reference leak in of_get_dml_pipe_index()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
commit af12e64ae0661546e8b4f5d30d55c5f53a11efe7 upstream.
When calling of_parse_phandle_with_args(), the caller is responsible to call of_node_put() to release the reference of device node. In of_get_dml_pipe_index(), it does not release the reference.
--- drivers/mmc/host/mmci_qcom_dml.c | 1 + 1 file changed, 1 insertion(+)
drivers/mmc/host/mmci_qcom_dml.c +1 -0
@@ -109,6 +109,7 @@ static int of_get_dml_pipe_index(struct &dma_spec))return -ENODEV ; +of_node_put (dma_spec.np);if (dma_spec.args_count)return dma_spec.args[0 ];
Greg Kroah-Hartman
maintainerPATCH 196/378 mm/kfence: disable KFENCE upon KASAN HW tags enablement
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Potapenko <[email protected]>
commit 09833d99db36d74456a4d13eb29c32d56ff8f2b6 upstream.
KFENCE does not currently support KASAN hardware tags. As a result, the two features are incompatible when enabled simultaneously.
Given that MTE provides deterministic protection and KFENCE is a sampling-based debugging tool, prioritize the stronger hardware protections. Disable KFENCE initialization and free the pre-allocated pool if KASAN hardware tags are detected to ensure the system maintains the security guarantees provided by MTE.
--- mm/kfence/core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
mm/kfence/core.c +15 -0
@@ -13,6 +13,7 @@#include <linux/hash.h> #include <linux/irq_work.h> #include <linux/jhash.h> +#include <linux/kasan-enabled.h> #include <linux/kcsan-checks.h> #include <linux/kfence.h> #include <linux/kmemleak.h>
@@ -912,6 +913,20 @@ void __init kfence_alloc_pool_and_metadareturn ;/* +* If KASAN hardware tags are enabled, disable KFENCE, because it +* does not support MTE yet. +*/ +if (kasan_hw_tags_enabled ()) { +pr_info ("disabled as KASAN HW tags are enabled\n" ); +if (__kfence_pool) { +memblock_free (__kfence_pool,KFENCE_POOL_SIZE ); + __kfence_pool =NULL ; + } + kfence_sample_interval =0 ; +return ; + } + +/* * If the pool has already been initialized by arch, there is no need to * re-allocate the memory pool. */
Greg Kroah-Hartman
maintainerPATCH 197/378 mmc: sdhci-brcmstb: use correct register offset for V1 pin_sel restore
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kamal Dasu <[email protected]>
commit 79ad471530e0baef0dce991816013df55e401d9c upstream.
The restore path for SDIO_CFG_CORE_V1 was incorrectly using SDIO_CFG_SD_PIN_SEL (offset 0x44) instead of SDIO_CFG_V1_SD_PIN_SEL (offset 0x54), causing the wrong register to be written on resume. The save path already uses the correct V1-specific offset. This affects BCM7445 and BCM72116 platforms which use the V1 config core.
--- drivers/mmc/host/sdhci-brcmstb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/host/sdhci-brcmstb.c +1 -1
@@ -116,7 +116,7 @@ static void sdhci_brcmstb_restore_regs(struct mmc_host *mmc, enum cfg_core_ver vwritel (sr->boot_main_ctl, priv->boot_regs +SDIO_BOOT_MAIN_CTL );if (ver ==SDIO_CFG_CORE_V1 ) { -writel (sr->sd_pin_sel, cr +SDIO_CFG_SD_PIN_SEL ); +writel (sr->sd_pin_sel, cr +SDIO_CFG_V1_SD_PIN_SEL );return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 198/378 mmc: dw_mmc-rockchip: Fix runtime PM support for internal phase support
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shawn Lin <[email protected]>
commit 6465a8bbb0f6ad98aeb66dc9ea19c32c193a610b upstream.
RK3576 is the first platform to introduce internal phase support, and subsequent platforms are expected to adopt a similar design. In this architecture, runtime suspend powers off the attached power domain, which resets registers, including vendor-specific ones such as SDMMC_TIMING_CON0, SDMMC_TIMING_CON1, and SDMMC_MISC_CON. These registers must be saved and restored, a requirement that falls outside the scope of the dw_mmc core.
--- drivers/mmc/host/dw_mmc-rockchip.c | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-)
drivers/mmc/host/dw_mmc-rockchip.c +37 -1
@@ -36,6 +36,8 @@ struct dw_mci_rockchip_priv_data {int default_sample_phase;int num_phases;bool internal_phase; +int sample_phase; +int drv_phase; };/*
@@ -574,9 +576,43 @@ static void dw_mci_rockchip_remove(strucdw_mci_pltfm_remove (pdev); } +static int dw_mci_rockchip_runtime_suspend (struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_mci *host =platform_get_drvdata (pdev); +struct dw_mci_rockchip_priv_data *priv = host->priv; + +if (priv->internal_phase) { + priv->sample_phase =rockchip_mmc_get_phase (host, true); + priv->drv_phase =rockchip_mmc_get_phase (host, false); + } + +return dw_mci_runtime_suspend (dev); +} + +static int dw_mci_rockchip_runtime_resume (struct device *dev) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_mci *host =platform_get_drvdata (pdev); +struct dw_mci_rockchip_priv_data *priv = host->priv; +int ret; + + ret =dw_mci_runtime_resume (dev); +if (ret) +return ret; + +if (priv->internal_phase) { +rockchip_mmc_set_phase (host, true, priv->sample_phase); +rockchip_mmc_set_phase (host, false, priv->drv_phase); +mci_writel (host,MISC_CON ,MEM_CLK_AUTOGATE_ENABLE ); + } + +return ret; +} +static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = { SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -RUNTIME_PM_OPS (dw_mci_runtime_suspend, dw_mci_runtime_resume,NULL ) +RUNTIME_PM_OPS (dw_mci_rockchip_runtime_suspend, dw_mci_rockchip_runtime_resume,NULL ) };static struct platform_driver dw_mci_rockchip_pltfm_driver = {
Greg Kroah-Hartman
maintainerPATCH 199/378 mmc: core: Avoid bitfield RMW for claim/retune flags
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Penghe Geng <[email protected]>
commit 901084c51a0a8fb42a3f37d2e9c62083c495f824 upstream.
Move claimed and retune control flags out of the bitfield word to avoid unrelated RMW side effects in asynchronous contexts.
The host->claimed bit shared a word with retune flags. Writes to claimed in __mmc_claim_host() or retune_now in mmc_mq_queue_rq() can overwrite other bits when concurrent updates happen in other contexts, triggering spurious WARN_ON(!host->claimed). Convert claimed, can_retune, retune_now and retune_paused to bool to remove shared-word coupling.
--- include/linux/mmc/host.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/mmc/host.h +5 -4
@@ -486,14 +486,12 @@ struct mmc_host {struct mmc_ios ios;/* current io bus settings */ +bool claimed;/* host exclusively claimed */ +/* group bitfields together to minimize padding */ unsigned int use_spi_crc:1; - unsigned int claimed:1; /* host exclusively claimed */ unsigned int doing_init_tune:1; /* initial tuning in progress */ - unsigned int can_retune:1; /* re-tuning can be used */ unsigned int doing_retune:1; /* re-tuning in progress */ - unsigned int retune_now:1; /* do re-tuning at next req */ - unsigned int retune_paused:1; /* re-tuning is temporarily disabled */ unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */ unsigned int can_dma_map_merge:1; /* merging can be used */ unsigned int vqmmc_enabled:1; /* vqmmc regulator is enabled */
@@ -508,6 +506,9 @@ struct mmc_host {int rescan_disable;/* disable card detection */ int rescan_entered;/* used with nonremovable devices */ +bool can_retune;/* re-tuning can be used */ +bool retune_now;/* do re-tuning at next req */ +bool retune_paused;/* re-tuning is temporarily disabled */ int need_retune;/* re-tuning is needed */ int hold_retune;/* hold off re-tuning */ unsigned int retune_period;/* re-tuning period in secs */
Greg Kroah-Hartman
maintainerPATCH 200/378 ASoC: qcom: qdsp6: Fix q6apm remove ordering during ADSP stop and start
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ravi Hothi <[email protected]>
commit d6db827b430bdcca3976cebca7bd69cca03cde2c upstream.
During ADSP stop and start, the kernel crashes due to the order in which ASoC components are removed.
On ADSP stop, the q6apm-audio .remove callback unloads topology and removes PCM runtimes during ASoC teardown. This deletes the RTDs that contain the q6apm DAI components before their removal pass runs, leaving those components still linked to the card and causing crashes on the next rebind.
Fix this by ensuring that all dependent (child) components are removed first, and the q6apm component is removed last.
[ 48.105720] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000d0 [ 48.114763] Mem abort info: [ 48.117650] ESR = 0x0000000096000004 [ 48.121526] EC = 0x25: DABT (current EL), IL = 32 bits [ 48.127010] SET = 0, FnV = 0 [ 48.130172] EA = 0, S1PTW = 0 [ 48.133415] FSC = 0x04: level 0 translation fault [ 48.138446] Data abort info: [ 48.141422] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 [ 48.147079] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 48.152354] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 48.157859] user pgtable: 4k pages, 48-bit VAs, pgdp=00000001173cf000 [ 48.164517] [00000000000000d0] pgd=0000000000000000, p4d=0000000000000000 [ 48.171530] Internal error: Oops: 0000000096000004 [#1] SMP [ 48.177348] Modules linked in: q6prm_clocks q6apm_lpass_dais q6apm_dai snd_q6dsp_common q6prm snd_q6apm 8021q garp mrp stp llc snd_soc_hdmi_codec apr pdr_interface phy_qcom_edp fastrpc qcom_pd_mapper rpmsg_ctrl qrtr_smd rpmsg_char qcom_pdr_msg qcom_iris v4l2_mem2mem videobuf2_dma_contig ath11k_pci msm ubwc_config at24 ath11k videobuf2_memops mac80211 ocmem videobuf2_v4l2 libarc4 drm_gpuvm mhi qrtr videodev drm_exec snd_soc_sc8280xp gpu_sched videobuf2_common nvmem_qcom_spmi_sdam snd_soc_qcom_sdw drm_dp_aux_bus qcom_q6v5_pas qcom_spmi_temp_alarm snd_soc_qcom_common rtc_pm8xxx qcom_pon drm_display_helper cec qcom_pil_info qcom_stats soundwire_bus drm_client_lib mc dispcc0_sa8775p videocc_sa8775p qcom_q6v5 camcc_sa8775p snd_soc_dmic phy_qcom_sgmii_eth snd_soc_max98357a i2c_qcom_geni snd_soc_core dwmac_qcom_ethqos llcc_qcom icc_bwmon qcom_sysmon snd_compress qcom_refgen_regulator coresight_stm stmmac_platform snd_pcm_dmaengine qcom_common coresight_tmc stmmac coresight_replicator qcom_glink_smem coresight_cti stm_core [ 48.177444] coresight_funnel snd_pcm ufs_qcom phy_qcom_qmp_usb gpi phy_qcom_snps_femto_v2 coresight phy_qcom_qmp_ufs qcom_wdt gpucc_sa8775p pcs_xpcs mdt_loader qcom_ice icc_osm_l3 qmi_helpers snd_timer snd soundcore display_connector qcom_rng nvmem_reboot_mode drm_kms_helper phy_qcom_qmp_pcie sha256 cfg80211 rfkill socinfo fuse drm backlight ipv6 [ 48.301059] CPU: 2 UID: 0 PID: 293 Comm: kworker/u32:2 Not tainted 6.19.0-rc6-dirty #10 PREEMPT [ 48.310081] Hardware name: Qualcomm Technologies, Inc. Lemans EVK (DT) [ 48.316782] Workqueue: pdr_notifier_wq pdr_notifier_work [pdr_interface] [ 48.323672] pstate: 20400005 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 48.330825] pc : mutex_lock+0xc/0x54 [ 48.334514] lr : soc_dapm_shutdown_dapm+0x44/0x174 [snd_soc_core] [ 48.340794] sp : ffff800084ddb7b0 [ 48.344207] x29: ffff800084ddb7b0 x28: ffff00009cd9cf30 x27: ffff00009cd9cc00 [ 48.351544] x26: ffff000099610190 x25: ffffa31d2f19c810 x24: ffffa31d2f185098 [ 48.358869] x23: ffff800084ddb7f8 x22: 0000000000000000 x21: 00000000000000d0 [ 48.366198] x20: ffff00009ba6c338 x19: ffff00009ba6c338 x18: 00000000ffffffff [ 48.373528] x17: 000000040044ffff x16: ffffa31d4ae6dca8 x15: 072007740775076f [ 48.380853] x14: 0765076d07690774 x13: 00313a323a656369 x12: 767265733a637673 [ 48.388182] x11: 00000000000003f9 x10: ffffa31d4c7dea98 x9 : 0000000000000001 [ 48.395519] x8 : ffff00009a2aadc0 x7 : 0000000000000003 x6 : 0000000000000000 [ 48.402854] x5 : 0000000000000000 x4 : 0000000000000028 x3 : ffff000ef397a698 [ 48.410180] x2 : ffff00009a2aadc0 x1 : 0000000000000000 x0 : 00000000000000d0 [ 48.417506] Call trace: [ 48.420025] mutex_lock+0xc/0x54 (P) [ 48.423712] snd_soc_dapm_shutdown+0x44/0xbc [snd_soc_core] [ 48.429447] soc_cleanup_card_resources+0x30/0x2c0 [snd_soc_core] [ 48.435719] snd_soc_bind_card+0x4dc/0xcc0 [snd_soc_core] [ 48.441278] snd_soc_add_component+0x27c/0x2c8 [snd_soc_core] [ 48.447192] snd_soc_register_component+0x9c/0xf4 [snd_soc_core] [ 48.453371] devm_snd_soc_register_component+0x64/0xc4 [snd_soc_core] [ 48.459994] apm_probe+0xb4/0x110 [snd_q6apm] [ 48.464479] apr_device_probe+0x24/0x40 [apr] [ 48.468964] really_probe+0xbc/0x298 [ 48.472651] __driver_probe_device+0x78/0x12c [ 48.477132] driver_probe_device+0x40/0x160 [ 48.481435] __device_attach_driver+0xb8/0x134 [ 48.486011] bus_for_each_drv+0x80/0xdc [ 48.489964] __device_attach+0xa8/0x1b0 [ 48.493916] device_initial_probe+0x50/0x54 [ 48.498219] bus_probe_device+0x38/0xa0 [ 48.502170] device_add+0x590/0x760 [ 48.505761] device_register+0x20/0x30 [ 48.509623] of_register_apr_devices+0x1d8/0x318 [apr] [ 48.514905] apr_pd_status+0x2c/0x54 [apr] [ 48.519114] pdr_notifier_work+0x8c/0xe0 [pdr_interface] [ 48.524570] process_one_work+0x150/0x294 [ 48.528692] worker_thread+0x2d8/0x3d8 [ 48.532551] kthread+0x130/0x204 [ 48.535874] ret_from_fork+0x10/0x20 [ 48.539559] Code: d65f03c0 d5384102 d503201f d2800001 (c8e17c02) [ 48.545823] ---[ end trace 0000000000000000 ]---
--- sound/soc/qcom/qdsp6/q6apm-dai.c | 1 + sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 1 + sound/soc/qcom/qdsp6/q6apm.c | 1 + 3 files changed, 3 insertions(+)
sound/soc/qcom/qdsp6/q6apm-dai.c +1 -0
@@ -838,6 +838,7 @@ static const struct snd_soc_component_dr .ack = q6apm_dai_ack, .compress_ops = &q6apm_dai_compress_ops, .use_dai_pcm_id = true, + .remove_order = SND_SOC_COMP_ORDER_EARLY, };static int q6apm_dai_probe (struct platform_device *pdev)
sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +1 -0
@@ -278,6 +278,7 @@ static const struct snd_soc_component_dr .of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name, .be_pcm_base = AUDIOREACH_BE_PCM_BASE, .use_dai_pcm_id = true, + .remove_order = SND_SOC_COMP_ORDER_FIRST, };static int q6apm_lpass_dai_dev_probe (struct platform_device *pdev)
sound/soc/qcom/qdsp6/q6apm.c +1 -0
@@ -712,6 +712,7 @@ static const struct snd_soc_component_dr .name = APM_AUDIO_DRV_NAME, .probe = q6apm_audio_probe, .remove = q6apm_audio_remove, + .remove_order = SND_SOC_COMP_ORDER_LAST, };static int apm_probe (gpr_device_t *gdev)
Greg Kroah-Hartman
maintainerPATCH 201/378 tipc: fix divide-by-zero in tipc_sk_filter_connect()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mehul Rao <[email protected]>
commit 6c5a9baa15de240e747263aba435a0951da8d8d2 upstream.
A user can set conn_timeout to any value via setsockopt(TIPC_CONN_TIMEOUT), including values less than 4. When a SYN is rejected with TIPC_ERR_OVERLOAD and the retry path in tipc_sk_filter_connect() executes:
delay %= (tsk->conn_timeout / 4);
If conn_timeout is in the range [0, 3], the integer division yields 0, and the modulo operation triggers a divide-by-zero exception, causing a kernel oops/panic.
Fix this by clamping conn_timeout to a minimum of 4 at the point of use in tipc_sk_filter_connect().
Oops: divide error: 0000 [#1] SMP KASAN NOPTI CPU: 0 UID: 0 PID: 119 Comm: poc-F144 Not tainted 7.0.0-rc2+ RIP: 0010:tipc_sk_filter_rcv (net/tipc/socket.c:2236 net/tipc/socket.c:2362) Call Trace: tipc_sk_backlog_rcv (include/linux/instrumented.h:82 include/linux/atomic/atomic-instrumented.h:32 include/net/sock.h:2357 net/tipc/socket.c:2406) __release_sock (include/net/sock.h:1185 net/core/sock.c:3213) release_sock (net/core/sock.c:3797) tipc_connect (net/tipc/socket.c:2570) __sys_connect (include/linux/file.h:62 include/linux/file.h:83 net/socket.c:2098)
--- net/tipc/socket.c | 2 ++ 1 file changed, 2 insertions(+)
net/tipc/socket.c +2 -0
@@ -2233,6 +2233,8 @@ static bool tipc_sk_filter_connect(strucif (skb_queue_empty (&sk->sk_write_queue))break ;get_random_bytes (&delay,2 ); +if (tsk->conn_timeout <4 ) + tsk->conn_timeout =4 ; delay %= (tsk->conn_timeout /4 ); delay =msecs_to_jiffies (delay +100 );sk_reset_timer (sk, &sk->sk_timer, jiffies + delay);
Greg Kroah-Hartman
maintainerPATCH 202/378 firmware: stratix10-rsu: Fix NULL pointer dereference when RSU is disabled
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liwei Song <[email protected]>
commit c45f7263100cece247dd3fa5fe277bd97fdb5687 upstream.
When the Remote System Update (RSU) isn't enabled in the First Stage Boot Loader (FSBL), the driver encounters a NULL pointer dereference when excute svc_normal_to_secure_thread() thread, resulting in a kernel panic:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008
Mem abort info:
...
Data abort info:
...
[0000000000000008] user address but active_mm is swapper
Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 79 Comm: svc_smc_hvc_thr Not tainted 6.19.0-rc8-yocto-standard+ #59 PREEMPT Hardware name: SoCFPGA Stratix 10 SoCDK (DT) pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : svc_normal_to_secure_thread+0x38c/0x990 lr : svc_normal_to_secure_thread+0x144/0x990 ... Call trace: svc_normal_to_secure_thread+0x38c/0x990 (P) kthread+0x150/0x210 ret_from_fork+0x10/0x20 Code: 97cfc113 f9400260 aa1403e1 f9400400 (f9400402) ---[ end trace 0000000000000000 ]---
The issue occurs because rsu_send_async_msg() fails when RSU is not enabled in firmware, causing the channel to be freed via stratix10_svc_free_channel(). However, the probe function continues execution and registers svc_normal_to_secure_thread(), which subsequently attempts to access the already-freed channel, triggering the NULL pointer dereference.
Fix this by properly cleaning up the async client and returning early on failure, preventing the thread from being used with an invalid channel.
--- drivers/firmware/stratix10-rsu.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/firmware/stratix10-rsu.c +2 -0
@@ -768,7 +768,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev) rsu_async_status_callback);if (ret) {dev_err (dev,"Error, getting RSU status %i\n" , ret); +stratix10_svc_remove_async_client (priv->chan);stratix10_svc_free_channel (priv->chan); +return ret; }/* get DCMF version from firmware */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 203/378 kprobes: avoid crash when rmmod/insmod after ftrace killed
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit e113f0b46d19626ec15388bcb91432c9a4fd6261 upstream.
After we hit ftrace is killed by some errors, the kernel crash if we remove modules in which kprobe probes.
BUG: unable to handle page fault for address: fffffbfff805000d PGD 817fcc067 P4D 817fcc067 PUD 817fc8067 PMD 101555067 PTE 0 Oops: Oops: 0000 [#1] SMP KASAN PTI CPU: 4 UID: 0 PID: 2012 Comm: rmmod Tainted: G W OE Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE RIP: 0010:kprobes_module_callback+0x89/0x790 RSP: 0018:ffff88812e157d30 EFLAGS: 00010a02 RAX: 1ffffffff805000d RBX: dffffc0000000000 RCX: ffffffff86a8de90 RDX: ffffed1025c2af9b RSI: 0000000000000008 RDI: ffffffffc0280068 RBP: 0000000000000000 R08: 0000000000000001 R09: ffffed1025c2af9a R10: ffff88812e157cd7 R11: 205d323130325420 R12: 0000000000000002 R13: ffffffffc0290488 R14: 0000000000000002 R15: ffffffffc0280040 FS: 00007fbc450dd740(0000) GS:ffff888420331000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: fffffbfff805000d CR3: 000000010f624000 CR4: 00000000000006f0 Call Trace: <TASK> notifier_call_chain+0xc6/0x280 blocking_notifier_call_chain+0x60/0x90 __do_sys_delete_module.constprop.0+0x32a/0x4e0 do_syscall_64+0x5d/0xfa0 entry_SYSCALL_64_after_hwframe+0x76/0x7e
This is because the kprobe on ftrace does not correctly handles the kprobe_ftrace_disabled flag set by ftrace_kill().
To prevent this error, check kprobe_ftrace_disabled in __disarm_kprobe_ftrace() and skip all ftrace related operations.
--- kernel/kprobes.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/kprobes.c +4 -0
@@ -1104,6 +1104,10 @@ static int __disarm_kprobe_ftrace(structint ret;lockdep_assert_held (&kprobe_mutex); +if (unlikely (kprobe_ftrace_disabled)) { +/* Now ftrace is disabled forever, disarm is already done. */ +return 0 ; + }if (*cnt ==1 ) { ret =unregister_ftrace_function (ops);
Greg Kroah-Hartman
maintainerPATCH 204/378 ceph: add a bunch of missing ceph_path_info initializers
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <[email protected]>
commit 43323a5934b660afae687e8e4e95ac328615a5c4 upstream.
ceph_mdsc_build_path() must be called with a zero-initialized ceph_path_info parameter, or else the following ceph_mdsc_free_path_info() may crash.
Example crash (on Linux 6.18.12):
virt_to_cache: Object is not a Slab page!
WARNING: CPU: 184 PID: 2871736 at mm/slub.c:6732 kmem_cache_free+0x316/0x400 [...] Call Trace: [...] ceph_open+0x13d/0x3e0 do_dentry_open+0x134/0x480 vfs_open+0x2a/0xe0 path_openat+0x9a3/0x1160 [...] cache_from_obj: Wrong slab cache. names_cache but object is from ceph_inode_info WARNING: CPU: 184 PID: 2871736 at mm/slub.c:6746 kmem_cache_free+0x2dd/0x400 [...] kernel BUG at mm/slub.c:634! Oops: invalid opcode: 0000 [#1] SMP NOPTI RIP: 0010:__slab_free+0x1a4/0x350
Some of the ceph_mdsc_build_path() callers had initializers, but others had not, even though they were all added by commit 15f519e9f883 ("ceph: fix race condition validating r_parent before applying state"). The ones without initializer are suspectible to random crashes. (I can imagine it could even be possible to exploit this bug to elevate privileges.)
Unfortunately, these Ceph functions are undocumented and its semantics can only be derived from the code. I see that ceph_mdsc_build_path() initializes the structure only on success, but not on error.
Calling ceph_mdsc_free_path_info() after a failed ceph_mdsc_build_path() call does not even make sense, but that's what all callers do, and for it to be safe, the structure must be zero-initialized. The least intrusive approach to fix this is therefore to add initializers everywhere.
--- fs/ceph/debugfs.c | 4 ++-- fs/ceph/dir.c | 2 +- fs/ceph/file.c | 4 ++-- fs/ceph/inode.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-)
fs/ceph/debugfs.c +2 -2
@@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s,if (req->r_inode) {seq_printf (s," #%llx" ,ceph_ino (req->r_inode)); }else if (req->r_dentry) { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, req->r_dentry, &path_info,0 );if (IS_ERR (path)) path =NULL ;
@@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, }if (req->r_old_dentry) { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, req->r_old_dentry, &path_info,0 );if (IS_ERR (path)) path =NULL ;
fs/ceph/dir.c +1 -1
@@ -1364,7 +1364,7 @@ static int ceph_unlink(struct inode *dirif (!dn) { try_async = false; }else { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, dn, &path_info,0 );if (IS_ERR (path)) { try_async = false;
fs/ceph/file.c +2 -2
@@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, strucif (!dentry) { do_sync = true; }else { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, dentry, &path_info,0 );if (IS_ERR (path)) { do_sync = true;
@@ -807,7 +807,7 @@ int ceph_atomic_open(struct inode *dir,if (!dn) { try_async = false; }else { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, dn, &path_info,0 );if (IS_ERR (path)) { try_async = false;
fs/ceph/inode.c +1 -1
@@ -2551,7 +2551,7 @@ int __ceph_setattr(struct mnt_idmap *idmif (!dentry) { do_sync = true; }else { -struct ceph_path_info path_info; +struct ceph_path_info path_info = {0 }; path =ceph_mdsc_build_path (mdsc, dentry, &path_info,0 );if (IS_ERR (path)) { do_sync = true;
Greg Kroah-Hartman
maintainerPATCH 205/378 libceph: Fix potential out-of-bounds access in ceph_handle_auth_reply()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit b282c43ed156ae15ea76748fc15cd5c39dc9ab72 upstream.
This patch fixes an out-of-bounds access in ceph_handle_auth_reply() that can be triggered by a message of type CEPH_MSG_AUTH_REPLY. In ceph_handle_auth_reply(), the value of the payload_len field of such a message is stored in a variable of type int. A value greater than INT_MAX leads to an integer overflow and is interpreted as a negative value. This leads to decrementing the pointer address by this value and subsequently accessing it because ceph_decode_need() only checks that the memory access does not exceed the end address of the allocation.
This patch fixes the issue by changing the data type of payload_len to u32. Additionally, the data type of result_msg_len is changed to u32, as it is also a variable holding a non-negative length.
Also, an additional layer of sanity checks is introduced, ensuring that directly after reading it from the message, payload_len and result_msg_len are not greater than the overall segment length.
BUG: KASAN: slab-out-of-bounds in ceph_handle_auth_reply+0x642/0x7a0 [libceph] Read of size 4 at addr ffff88811404df14 by task kworker/20:1/262 CPU: 20 UID: 0 PID: 262 Comm: kworker/20:1 Not tainted 6.19.2 #5 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: ceph-msgr ceph_con_workfn [libceph] Call Trace: <TASK> dump_stack_lvl+0x76/0xa0 print_report+0xd1/0x620 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 ? kasan_complete_mode_report_info+0x72/0x210 kasan_report+0xe7/0x130 ? ceph_handle_auth_reply+0x642/0x7a0 [libceph] ? ceph_handle_auth_reply+0x642/0x7a0 [libceph] __asan_report_load_n_noabort+0xf/0x20 ceph_handle_auth_reply+0x642/0x7a0 [libceph] mon_dispatch+0x973/0x23d0 [libceph] ? apparmor_socket_recvmsg+0x6b/0xa0 ? __pfx_mon_dispatch+0x10/0x10 [libceph] ? __kasan_check_write+0x14/0x30i ? mutex_unlock+0x7f/0xd0 ? __pfx_mutex_unlock+0x10/0x10 ? __pfx_do_recvmsg+0x10/0x10 [libceph] ceph_con_process_message+0x1f1/0x650 [libceph] process_message+0x1e/0x450 [libceph] ceph_con_v2_try_read+0x2e48/0x6c80 [libceph] ? __pfx_ceph_con_v2_try_read+0x10/0x10 [libceph] ? save_fpregs_to_fpstate+0xb0/0x230 ? raw_spin_rq_unlock+0x17/0xa0 ? finish_task_switch.isra.0+0x13b/0x760 ? __switch_to+0x385/0xda0 ? __kasan_check_write+0x14/0x30 ? mutex_lock+0x8d/0xe0 ? __pfx_mutex_lock+0x10/0x10 ceph_con_workfn+0x248/0x10c0 [libceph] process_one_work+0x629/0xf80 ? __kasan_check_write+0x14/0x30 worker_thread+0x87f/0x1570 ? __pfx__raw_spin_lock_irqsave+0x10/0x10 ? __pfx_try_to_wake_up+0x10/0x10 ? kasan_print_address_stack_frame+0x1f7/0x280 ? __pfx_worker_thread+0x10/0x10 kthread+0x396/0x830 ? __pfx__raw_spin_lock_irq+0x10/0x10 ? __pfx_kthread+0x10/0x10 ? __kasan_check_write+0x14/0x30 ? recalc_sigpending+0x180/0x210 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x3f7/0x610 ? __pfx_ret_from_fork+0x10/0x10 ? __switch_to+0x385/0xda0 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
[ idryomov: replace if statements with ceph_decode_need() for
payload_len and result_msg_len ]
--- net/ceph/auth.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/ceph/auth.c +4 -2
@@ -205,9 +205,9 @@ int ceph_handle_auth_reply(struct ceph_as32 result;u64 global_id;void *payload, *payload_end; -int payload_len; +u32 payload_len;char *result_msg; -int result_msg_len; +u32 result_msg_len;int ret = -EINVAL ;mutex_lock (&ac->mutex);
@@ -217,10 +217,12 @@ int ceph_handle_auth_reply(struct ceph_a result =ceph_decode_32 (&p); global_id =ceph_decode_64 (&p); payload_len =ceph_decode_32 (&p); +ceph_decode_need (&p, end, payload_len, bad); payload = p; p += payload_len;ceph_decode_need (&p, end,sizeof (u32), bad); result_msg_len =ceph_decode_32 (&p); +ceph_decode_need (&p, end, result_msg_len, bad); result_msg = p; p += result_msg_len;if (p != end)
Greg Kroah-Hartman
maintainerPATCH 206/378 libceph: reject preamble if control segment is empty
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Dryomov <[email protected]>
commit c4c22b846eceff05b1129b8844a80310e55a7f87 upstream.
While head_onwire_len() has a branch to handle ctrl_len == 0 case, prepare_read_control() always sets up a kvec for the CRC meaning that a non-empty control segment is effectively assumed. All frames that clients deal with meet that assumption, so let's make it official and treat the preamble with an empty control segment as malformed.
--- net/ceph/messenger_v2.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
net/ceph/messenger_v2.c +8 -9
@@ -392,7 +392,7 @@ static int head_onwire_len(int ctrl_len,int head_len;int rem_len; -BUG_ON (ctrl_len <0 || ctrl_len >CEPH_MSG_MAX_CONTROL_LEN ); +BUG_ON (ctrl_len <1 || ctrl_len >CEPH_MSG_MAX_CONTROL_LEN );if (secure) { head_len =CEPH_PREAMBLE_SECURE_LEN ;
@@ -401,9 +401,7 @@ static int head_onwire_len(int ctrl_len, head_len +=padded_len (rem_len) +CEPH_GCM_TAG_LEN ; } }else { - head_len =CEPH_PREAMBLE_PLAIN_LEN ; -if (ctrl_len) - head_len += ctrl_len +CEPH_CRC_LEN ; + head_len =CEPH_PREAMBLE_PLAIN_LEN + ctrl_len +CEPH_CRC_LEN ; }return head_len; }
@@ -528,11 +526,16 @@ static int decode_preamble(void *p, stru desc->fd_aligns[i] =ceph_decode_16 (&p); } -if (desc->fd_lens[0 ] <0 || +/* +* This would fire for FRAME_TAG_WAIT (it has one empty +* segment), but we should never get it as client. +*/ +if (desc->fd_lens[0 ] <1 || desc->fd_lens[0 ] >CEPH_MSG_MAX_CONTROL_LEN ) {pr_err ("bad control segment length %d\n" , desc->fd_lens[0 ]);return -EINVAL ; } +if (desc->fd_lens[1 ] <0 || desc->fd_lens[1 ] >CEPH_MSG_MAX_FRONT_LEN ) {pr_err ("bad front segment length %d\n" , desc->fd_lens[1 ]);
@@ -549,10 +552,6 @@ static int decode_preamble(void *p, strureturn -EINVAL ; } -/* -* This would fire for FRAME_TAG_WAIT (it has one empty -* segment), but we should never get it as client. -*/ if (!desc->fd_lens[desc->fd_seg_cnt -1 ]) {pr_err ("last segment empty, segment count %d\n" , desc->fd_seg_cnt);
Greg Kroah-Hartman
maintainerPATCH 207/378 libceph: prevent potential out-of-bounds reads in process_message_header()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Dryomov <[email protected]>
commit 69fb5d91bba44ecf7eb80530b85fa4fb028921d5 upstream.
If the message frame is (maliciously) corrupted in a way that the length of the control segment ends up being less than the size of the message header or a different frame is made to look like a message frame, out-of-bounds reads may ensue in process_message_header().
Perform an explicit bounds check before decoding the message header.
--- net/ceph/messenger_v2.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/ceph/messenger_v2.c +8 -1
@@ -2832,12 +2832,15 @@ static int process_message_header(struct void *p, void *end) { struct ceph_frame_desc *desc = &con->v2.in_desc; -struct ceph_msg_header2 *hdr2 = p; +struct ceph_msg_header2 *hdr2;struct ceph_msg_header hdr;int skip;int ret;u64 seq; +ceph_decode_need (&p, end,sizeof (*hdr2), bad); + hdr2 = p; +/* verify seq# */ seq =le64_to_cpu (hdr2->seq);if ((s64 )seq - (s64 )con->in_seq <1 ) {
@@ -2868,6 +2871,10 @@ static int process_message_header(structWARN_ON (!con->in_msg);WARN_ON (con->in_msg->con != con);return 1 ; + +bad: +pr_err ("failed to decode message header\n" ); +return -EINVAL ; }static int process_message (struct ceph_connection *con)
Greg Kroah-Hartman
maintainerPATCH 208/378 libceph: Use u32 for non-negative values in ceph_monmap_decode()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit 770444611f047dbfd4517ec0bc1b179d40c2f346 upstream.
This patch fixes unnecessary implicit conversions that change signedness of blob_len and num_mon in ceph_monmap_decode().
Currently blob_len and num_mon are (signed) int variables. They are used to hold values that are always non-negative and get assigned in ceph_decode_32_safe(), which is meant to assign u32 values. Both variables are subsequently used as unsigned values, and the value of num_mon is further assigned to monmap->num_mon, which is of type u32. Therefore, both variables should be of type u32. This is especially relevant for num_mon. If the value read from the incoming message is very large, it is interpreted as a negative value, and the check for num_mon > CEPH_MAX_MON does not catch it. This leads to the attempt to allocate a very large chunk of memory for monmap, which will most likely fail. In this case, an unnecessary attempt to allocate memory is performed, and -ENOMEM is returned instead of -EINVAL.
--- net/ceph/mon_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/ceph/mon_client.c +3 -3
@@ -72,8 +72,8 @@ static struct ceph_monmap *ceph_monmap_dstruct ceph_monmap *monmap =NULL ;struct ceph_fsid fsid;u32 struct_len; -int blob_len; -int num_mon; +u32 blob_len; +u32 num_mon;u8 struct_v;u32 epoch;int ret;
@@ -112,7 +112,7 @@ static struct ceph_monmap *ceph_monmap_d }ceph_decode_32_safe (p, end, num_mon, e_inval); -dout ("%s fsid %pU epoch %u num_mon %d\n" , __func__, &fsid, epoch, +dout ("%s fsid %pU epoch %u num_mon %u\n" , __func__, &fsid, epoch, num_mon);if (num_mon >CEPH_MAX_MON ) goto e_inval;
Greg Kroah-Hartman
maintainerPATCH 209/378 libceph: admit message frames only in CEPH_CON_S_OPEN state
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Dryomov <[email protected]>
commit a5a373705081d7cc6363e16990e2361b0b362314 upstream.
Similar checks are performed for all control frames, but an early check for message frames was missing. process_message() is already set up to terminate the loop in case the state changes while con->ops->dispatch() handler is being executed.
--- net/ceph/messenger_v2.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ceph/messenger_v2.c +5 -0
@@ -2904,6 +2904,11 @@ static int __handle_control(struct ceph_if (con->v2.in_desc.fd_tag !=FRAME_TAG_MESSAGE )return process_control (con, p, end); +if (con->state !=CEPH_CON_S_OPEN ) { + con->error_msg ="protocol error, unexpected message" ; +return -EINVAL ; + } + ret =process_message_header (con, p, end);if (ret <0 )return ret;
Greg Kroah-Hartman
maintainerPATCH 210/378 Revert "tcpm: allow looking for role_sw device in the main node"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Yang <[email protected]>
commit 6b275bfaa16be3fb1689fa6794e445ecd127a1b4 upstream.
This reverts commit 1366cd228b0c67b60a2c0c26ef37fe9f7cfedb7f.
The fwnode_usb_role_switch_get() returns NULL only if no connection is found, returns ERR_PTR(-EPROBE_DEFER) if connection is found but deferred probe is needed, or a valid pointer of usb_role_switch.
When switching from a NULL check to IS_ERR_OR_NULL(), usb_role_switch_get() returns NULL and overwrites the ERR_PTR(-EPROBE_DEFER) returned by fwnode_usb_role_switch_get(). This causes the deferred probe indication to be lost, preventing the USB role switch from ever being retrieved.
--- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/tcpm/tcpm.c +1 -1
@@ -7890,7 +7890,7 @@ struct tcpm_port *tcpm_register_port(str port->partner_desc.identity = &port->partner_ident; port->role_sw =fwnode_usb_role_switch_get (tcpc->fwnode); -if (IS_ERR_OR_NULL (port->role_sw)) +if (!port->role_sw) port->role_sw =usb_role_switch_get (port->dev);if (IS_ERR (port->role_sw)) { err =PTR_ERR (port->role_sw);
Greg Kroah-Hartman
maintainerPATCH 211/378 Revert "ptdesc: remove references to folios from __pagetable_ctor() and pagetable_dtor()"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Axel Rasmussen <[email protected]>
commit 2d28ed588f8d7d0d41b0a4fad7f0d05e4bbf1797 upstream.
This change swapped out mod_node_page_state for lruvec_stat_add_folio. But, these two APIs are not interchangeable: the lruvec version also increments memcg stats, in addition to "global" pgdat stats.
So after this change, the "pagetables" memcg stat in memory.stat always yields "0", which is a userspace visible regression.
I tried to look for a refactor where we add a variant of lruvec_stat_mod_folio which takes a pgdat and a memcg instead of a folio, to try to adhere to the spirit of the original patch. But at the end of the day this just means we have to call folio_memcg(ptdesc_folio(ptdesc)) anyway, which doesn't really accomplish much.
This regression is visible in master as well as 6.18 stable, so CC stable too.
--- include/linux/mm.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
include/linux/mm.h +6 -11
@@ -3304,26 +3304,21 @@ static inline bool ptlock_init(struct ptstatic inline void ptlock_free (struct ptdesc *ptdesc) {}#endif /* defined(CONFIG_SPLIT_PTE_PTLOCKS) */ -static inline unsigned long ptdesc_nr_pages (const struct ptdesc *ptdesc) -{ -return compound_nr (ptdesc_page (ptdesc)); -} -static inline void __pagetable_ctor (struct ptdesc *ptdesc) { -pg_data_t *pgdat =NODE_DATA (memdesc_nid (ptdesc->pt_flags)); +struct folio *folio =ptdesc_folio (ptdesc); -__SetPageTable (ptdesc_page (ptdesc)); -mod_node_page_state (pgdat,NR_PAGETABLE ,ptdesc_nr_pages (ptdesc)); +__folio_set_pgtable (folio); +lruvec_stat_add_folio (folio,NR_PAGETABLE ); }static inline void pagetable_dtor (struct ptdesc *ptdesc) { -pg_data_t *pgdat =NODE_DATA (memdesc_nid (ptdesc->pt_flags)); +struct folio *folio =ptdesc_folio (ptdesc);ptlock_free (ptdesc); -__ClearPageTable (ptdesc_page (ptdesc)); -mod_node_page_state (pgdat,NR_PAGETABLE , -ptdesc_nr_pages (ptdesc)); +__folio_clear_pgtable (folio); +lruvec_stat_sub_folio (folio,NR_PAGETABLE ); }static inline void pagetable_dtor_free (struct ptdesc *ptdesc)
Greg Kroah-Hartman
maintainerPATCH 212/378 mm: Fix a hmm_range_fault() livelock / starvation problem
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Hellström <[email protected]>
commit b570f37a2ce480be26c665345c5514686a8a0274 upstream.
If hmm_range_fault() fails a folio_trylock() in do_swap_page, trying to acquire the lock of a device-private folio for migration, to ram, the function will spin until it succeeds grabbing the lock.
However, if the process holding the lock is depending on a work item to be completed, which is scheduled on the same CPU as the spinning hmm_range_fault(), that work item might be starved and we end up in a livelock / starvation situation which is never resolved.
This can happen, for example if the process holding the device-private folio lock is stuck in
migrate_device_unmap()->lru_add_drain_all()
sinc lru_add_drain_all() requires a short work-item to be run on all online cpus to complete.
A prerequisite for this to happen is:
a) Both zone device and system memory folios are considered in migrate_device_unmap(), so that there is a reason to call lru_add_drain_all() for a system memory folio while a folio lock is held on a zone device folio.
b) The zone device folio has an initial mapcount > 1 which causes at least one migration PTE entry insertion to be deferred to try_to_migrate(), which can happen after the call to lru_add_drain_all().
c) No or voluntary only preemption.
This all seems pretty unlikely to happen, but indeed is hit by the "xe_exec_system_allocator" igt test.
Resolve this by waiting for the folio to be unlocked if the folio_trylock() fails in do_swap_page().
Rename migration_entry_wait_on_locked() to softleaf_entry_wait_unlock() and update its documentation to indicate the new use-case.
Future code improvements might consider moving
the lru_add_drain_all() call in migrate_device_unmap() to be called *after* all pages have migration entries inserted. That would eliminate also b) above.
v2:
- Instead of a cond_resched() in hmm_range_fault(), eliminate the problem by waiting for the folio to be unlocked in do_swap_page() (Alistair Popple, Andrew Morton)
v3:
- Add a stub migration_entry_wait_on_locked() for the !CONFIG_MIGRATION case. (Kernel Test Robot)
v4:
- Rename migrate_entry_wait_on_locked() to softleaf_entry_wait_on_locked() and update docs (Alistair Popple)
v5:
- Add a WARN_ON_ONCE() for the !CONFIG_MIGRATION
version of softleaf_entry_wait_on_locked().
- Modify wording around function names in the commit message (Andrew Morton)
--- include/linux/migrate.h | 10 +++++++++- mm/filemap.c | 15 ++++++++++----- mm/memory.c | 3 ++- mm/migrate.c | 8 ++++---- mm/migrate_device.c | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-)
include/linux/migrate.h +9 -1
@@ -65,7 +65,7 @@ bool isolate_folio_to_list(struct folioint migrate_huge_page_move_mapping (struct address_space *mapping,struct folio *dst,struct folio *src); -void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl) +void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl) __releases(ptl);void folio_migrate_flags (struct folio *newfolio,struct folio *folio); int folio_migrate_mapping(struct address_space *mapping,
@@ -97,6 +97,14 @@ static inline int set_movable_ops(const return -ENOSYS; } +static inline void softleaf_entry_wait_on_locked (softleaf_t entry,spinlock_t *ptl) +__releases (ptl) +{ +WARN_ON_ONCE (1 ); + +spin_unlock (ptl); +} +#endif /* CONFIG_MIGRATION */ #ifdef CONFIG_NUMA_BALANCING
mm/filemap.c +10 -5
@@ -1379,14 +1379,16 @@ repeat:#ifdef CONFIG_MIGRATION /** -* migration_entry_wait_on_locked - Wait for a migration entry to be removed -* @entry: migration swap entry. +* softleaf_entry_wait_on_locked - Wait for a migration entry or +* device_private entry to be removed. +* @entry: migration or device_private swap entry. * @ptl: already locked ptl. This function will drop the lock. * -* Wait for a migration entry referencing the given page to be removed. This is +* Wait for a migration entry referencing the given page, or device_private +* entry referencing a dvice_private page to be unlocked. This is * equivalent to folio_put_wait_locked(folio, TASK_UNINTERRUPTIBLE) except * this can be called without taking a reference on the page. Instead this -* should be called while holding the ptl for the migration entry referencing +* should be called while holding the ptl for @entry referencing * the page. * * Returns after unlocking the ptl.
@@ -1394,7 +1396,7 @@ repeat:* This follows the same logic as folio_wait_bit_common() so see the comments * there. */ -void migration_entry_wait_on_locked (softleaf_t entry,spinlock_t *ptl) +void softleaf_entry_wait_on_locked (softleaf_t entry,spinlock_t *ptl)__releases (ptl) {struct wait_page_queue wait_page;
@@ -1428,6 +1430,9 @@ void migration_entry_wait_on_locked(soft* If a migration entry exists for the page the migration path must hold * a valid reference to the page, and it must take the ptl to remove the * migration entry. So the page is valid until the ptl is dropped. +* Similarly any path attempting to drop the last reference to a +* device-private page needs to grab the ptl to remove the device-private +* entry. */ spin_unlock (ptl);
mm/memory.c +2 -1
@@ -4684,7 +4684,8 @@ vm_fault_t do_swap_page(struct vm_faultunlock_page (vmf->page);put_page (vmf->page); }else { -pte_unmap_unlock (vmf->pte, vmf->ptl); +pte_unmap (vmf->pte); +softleaf_entry_wait_on_locked (entry, vmf->ptl); } }else if (softleaf_is_hwpoison (entry)) { ret =VM_FAULT_HWPOISON ;
mm/migrate.c +4 -4
@@ -499,7 +499,7 @@ void migration_entry_wait(struct mm_struif (!softleaf_is_migration (entry)) goto out; -migration_entry_wait_on_locked (entry, ptl); +softleaf_entry_wait_on_locked (entry, ptl);return ; out:spin_unlock (ptl);
@@ -531,10 +531,10 @@ void migration_entry_wait_huge(struct vm* If migration entry existed, safe to release vma lock * here because the pgtable page won't be freed without the * pgtable lock released. See comment right above pgtable -* lock release in migration_entry_wait_on_locked(). +* lock release in softleaf_entry_wait_on_locked(). */ hugetlb_vma_unlock_read (vma); -migration_entry_wait_on_locked (entry, ptl); +softleaf_entry_wait_on_locked (entry, ptl);return ; }
@@ -552,7 +552,7 @@ void pmd_migration_entry_wait(struct mm_ ptl =pmd_lock (mm, pmd);if (!pmd_is_migration_entry (*pmd)) goto unlock; -migration_entry_wait_on_locked (softleaf_from_pmd (*pmd), ptl); +softleaf_entry_wait_on_locked (softleaf_from_pmd (*pmd), ptl);return ; unlock:spin_unlock (ptl);
mm/migrate_device.c +1 -1
@@ -176,7 +176,7 @@ static int migrate_vma_collect_huge_pmd( }if (softleaf_is_migration (entry)) { -migration_entry_wait_on_locked (entry, ptl); +softleaf_entry_wait_on_locked (entry, ptl);spin_unlock (ptl);return -EAGAIN ; }
Greg Kroah-Hartman
maintainerPATCH 213/378 nsfs: tighten permission checks for ns iteration ioctls
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit e6b899f08066e744f89df16ceb782e06868bd148 upstream.
Even privileged services should not necessarily be able to see other privileged service's namespaces so they can't leak information to each other. Use may_see_all_namespaces() helper that centralizes this policy until the nstree adapts.
--- fs/nsfs.c | 13 +++++++++++++ include/linux/ns_common.h | 2 ++ kernel/nscommon.c | 6 ++++++ 3 files changed, 21 insertions(+)
fs/nsfs.c +13 -0
@@ -186,6 +186,17 @@ static bool nsfs_ioctl_valid(unsigned inreturn false; } +static bool may_use_nsfs_ioctl (unsigned int cmd) +{ +switch (_IOC_NR (cmd)) { +case _IOC_NR (NS_MNT_GET_NEXT ): + fallthrough; +case _IOC_NR (NS_MNT_GET_PREV ): +return may_see_all_namespaces (); + } +return true; +} +static long ns_ioctl (struct file *filp,unsigned int ioctl,unsigned long arg) {
@@ -201,6 +212,8 @@ static long ns_ioctl(struct file *filp,if (!nsfs_ioctl_valid (ioctl))return -ENOIOCTLCMD ; +if (!may_use_nsfs_ioctl (ioctl)) +return -EPERM ; ns =get_proc_ns (file_inode (filp));switch (ioctl) {
include/linux/ns_common.h +2 -0
@@ -55,6 +55,8 @@ static __always_inline bool is_ns_init_i#define ns_common_free (__ns) __ns_common_free(to_ns_common((__ns))) +bool may_see_all_namespaces (void ); + static __always_inline __must_check int __ns_ref_active_read(const struct ns_common *ns) {return atomic_read (&ns->__ns_ref_active);
kernel/nscommon.c +6 -0
@@ -309,3 +309,9 @@ void __ns_ref_active_get(struct ns_commoreturn ; } } + +bool may_see_all_namespaces (void ) +{ +return (task_active_pid_ns (current) == &init_pid_ns) && +ns_capable_noaudit (init_pid_ns.user_ns,CAP_SYS_ADMIN ); +}
Greg Kroah-Hartman
maintainerPATCH 214/378 liveupdate: luo_file: remember retrieve() status
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratyush Yadav (Google) <[email protected]>
commit f85b1c6af5bc3872f994df0a5688c1162de07a62 upstream.
LUO keeps track of successful retrieve attempts on a LUO file. It does so to avoid multiple retrievals of the same file. Multiple retrievals cause problems because once the file is retrieved, the serialized data structures are likely freed and the file is likely in a very different state from what the code expects.
The retrieve boolean in struct luo_file keeps track of this, and is passed to the finish callback so it knows what work was already done and what it has left to do.
All this works well when retrieve succeeds. When it fails, luo_retrieve_file() returns the error immediately, without ever storing anywhere that a retrieve was attempted or what its error code was. This results in an errored LIVEUPDATE_SESSION_RETRIEVE_FD ioctl to userspace, but nothing prevents it from trying this again.
The retry is problematic for much of the same reasons listed above. The file is likely in a very different state than what the retrieve logic normally expects, and it might even have freed some serialization data structures. Attempting to access them or free them again is going to break things.
For example, if memfd managed to restore 8 of its 10 folios, but fails on the 9th, a subsequent retrieve attempt will try to call kho_restore_folio() on the first folio again, and that will fail with a warning since it is an invalid operation.
Apart from the retry, finish() also breaks. Since on failure the retrieved bool in luo_file is never touched, the finish() call on session close will tell the file handler that retrieve was never attempted, and it will try to access or free the data structures that might not exist, much in the same way as the retry attempt.
There is no sane way of attempting the retrieve again. Remember the error retrieve returned and directly return it on a retry. Also pass this status code to finish() so it can make the right decision on the work it needs to do.
This is done by changing the bool to an integer. A value of 0 means retrieve was never attempted, a positive value means it succeeded, and a negative value means it failed and the error code is the value.
--- include/linux/liveupdate.h | 9 ++++++--- kernel/liveupdate/luo_file.c | 41 +++++++++++++++++++++++++---------------- mm/memfd_luo.c | 7 ++++++- 3 files changed, 37 insertions(+), 20 deletions(-)
include/linux/liveupdate.h +6 -3
@@ -20,8 +20,11 @@ struct file;/** * struct liveupdate_file_op_args - Arguments for file operation callbacks. * @handler: The file handler being called. -* @retrieved: The retrieve status for the 'can_finish / finish' -* operation. +* @retrieve_status: The retrieve status for the 'can_finish / finish' +* operation. A value of 0 means the retrieve has not been +* attempted, a positive value means the retrieve was +* successful, and a negative value means the retrieve failed, +* and the value is the error code of the call. * @file: The file object. For retrieve: [OUT] The callback sets * this to the new file. For other ops: [IN] The caller sets * this to the file being operated on.
@@ -37,7 +40,7 @@ struct file;*/ struct liveupdate_file_op_args {struct liveupdate_file_handler *handler; -bool retrieved; +int retrieve_status;struct file *file;u64 serialized_data;void *private_data;
kernel/liveupdate/luo_file.c +25 -16
92 lines not on this page · raw message
mm/memfd_luo.c +6 -1
@@ -326,7 +326,12 @@ static void memfd_luo_finish(struct livestruct memfd_luo_folio_ser *folios_ser;struct memfd_luo_ser *ser; -if (args->retrieved) +/* +* If retrieve was successful, nothing to do. If it failed, retrieve() +* already cleaned up everything it could. So nothing to do there +* either. Only need to clean up when retrieve was not called. +*/ +if (args->retrieve_status)return ; ser =phys_to_virt (args->serialized_data);
Greg Kroah-Hartman
maintainerPATCH 215/378 kthread: consolidate kthread exit paths to prevent use-after-free
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 28aaa9c39945b7925a1cc1d513c8f21ed38f5e4f upstream.
Guillaume reported crashes via corrupted RCU callback function pointers during KUnit testing. The crash was traced back to the pidfs rhashtable conversion which replaced the 24-byte rb_node with an 8-byte rhash_head in struct pid, shrinking it from 160 to 144 bytes.
struct kthread (without CONFIG_BLK_CGROUP) is also 144 bytes. With CONFIG_SLAB_MERGE_DEFAULT and SLAB_HWCACHE_ALIGN both round up to 192 bytes and share the same slab cache. struct pid.rcu.func and struct kthread.affinity_node both sit at offset 0x78.
When a kthread exits via make_task_dead() it bypasses kthread_exit() and misses the affinity_node cleanup. free_kthread_struct() frees the memory while the node is still linked into the global kthread_affinity_list. A subsequent list_del() by another kthread writes through dangling list pointers into the freed and reused memory, corrupting the pid's rcu.func pointer.
Instead of patching free_kthread_struct() to handle the missed cleanup, consolidate all kthread exit paths. Turn kthread_exit() into a macro that calls do_exit() and add kthread_do_exit() which is called from do_exit() for any task with PF_KTHREAD set. This guarantees that kthread-specific cleanup always happens regardless of the exit path - make_task_dead(), direct do_exit(), or kthread_exit().
Replace __to_kthread() with a new tsk_is_kthread() accessor in the public header. Export do_exit() since module code using the kthread_exit() macro now needs it directly.
--- include/linux/kthread.h | 21 ++++++++++++++++++++- kernel/exit.c | 6 ++++++ kernel/kthread.c | 41 +++++------------------------------------ 3 files changed, 31 insertions(+), 37 deletions(-)
include/linux/kthread.h +20 -1
@@ -7,6 +7,24 @@struct mm_struct ; +/* opaque kthread data */ +struct kthread ; + +/* +* When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will +* always remain a kthread. For kthreads p->worker_private always +* points to a struct kthread. For tasks that are not kthreads +* p->worker_private is used to point to other things. +* +* Return NULL for any task that is not a kthread. +*/ +static inline struct kthread *tsk_is_kthread (struct task_struct *p) +{ +if (p->flags &PF_KTHREAD ) +return p->worker_private; +return NULL ; +} + __printf(4, 5) struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data,
@@ -98,8 +116,9 @@ void *kthread_probe_data(struct task_strint kthread_park (struct task_struct *k);void kthread_unpark (struct task_struct *k);void kthread_parkme (void ); -void kthread_exit (long result)__noreturn ; +#define kthread_exit (result) do_exit(result)void kthread_complete_and_exit (struct completion *,long )__noreturn ; +void kthread_do_exit (struct kthread *,long );int kthreadd (void *unused);extern struct task_struct *kthreadd_task;
kernel/exit.c +6 -0
@@ -896,11 +896,16 @@ static void synchronize_group_exit(strucvoid __noreturn do_exit (long code) {struct task_struct *tsk = current; +struct kthread *kthread;int group_dead;WARN_ON (irqs_disabled ());WARN_ON (tsk->plug); + kthread =tsk_is_kthread (tsk); +if (unlikely (kthread)) +kthread_do_exit (kthread, code); +kcov_task_exit (tsk);kmsan_task_exit (tsk);
@@ -1013,6 +1018,7 @@ void __noreturn do_exit(long code)lockdep_free_task (tsk);do_task_dead (); } +EXPORT_SYMBOL (do_exit);void __noreturn make_task_dead (int signr) {
kernel/kthread.c +5 -36
85 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 216/378 cpufreq: intel_pstate: Fix NULL pointer dereference in update_cpu_qos_request()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Arcari <[email protected]>
commit ab39cc4cb8ceecdc2b61747433e7237f1ac2b789 upstream.
The update_cpu_qos_request() function attempts to initialize the 'freq' variable by dereferencing 'cpudata' before verifying if the 'policy' is valid.
This issue occurs on systems booted with the "nosmt" parameter, where all_cpu_data[cpu] is NULL for the SMT sibling threads. As a result, any call to update_qos_requests() will result in a NULL pointer dereference as the code will attempt to access pstate.turbo_freq using the NULL cpudata pointer.
Also, pstate.turbo_freq may be updated by intel_pstate_get_hwp_cap() after initializing the 'freq' variable, so it is better to defer the 'freq' until intel_pstate_get_hwp_cap() has been called.
Fix this by deferring the 'freq' assignment until after the policy and driver_data have been validated.
--- drivers/cpufreq/intel_pstate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/cpufreq/intel_pstate.c +3 -1
@@ -1647,8 +1647,8 @@ static ssize_t store_no_turbo(struct kobstatic void update_cpu_qos_request (int cpu,enum freq_qos_req_type type) {struct cpudata *cpudata = all_cpu_data[cpu]; -unsigned int freq = cpudata->pstate.turbo_freq;struct freq_qos_request *req; +unsigned int freq; struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);if (!policy)
@@ -1661,6 +1661,8 @@ static void update_cpu_qos_request(int cif (hwp_active)intel_pstate_get_hwp_cap (cpudata); + freq = cpudata->pstate.turbo_freq; +if (type ==FREQ_QOS_MIN ) { freq =DIV_ROUND_UP (freq * global.min_perf_pct,100 ); }else {
Greg Kroah-Hartman
maintainerPATCH 217/378 drm/amdgpu: add upper bound check on user inputs in signal ioctl
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sunil Khatri <[email protected]>
commit ea78f8c68f4f6211c557df49174c54d167821962 upstream.
Huge input values in amdgpu_userq_signal_ioctl can lead to a OOM and could be exploited.
So check these input value against AMDGPU_USERQ_MAX_HANDLES which is big enough value for genuine use cases and could potentially avoid OOM.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +7 -0
@@ -35,6 +35,8 @@static const struct dma_fence_ops amdgpu_userq_fence_ops;static struct kmem_cache *amdgpu_userq_fence_slab; +#define AMDGPU_USERQ_MAX_HANDLES (1U << 16) +int amdgpu_userq_fence_slab_init (void ) { amdgpu_userq_fence_slab = kmem_cache_create("amdgpu_userq_fence",
@@ -476,6 +478,11 @@ int amdgpu_userq_signal_ioctl(struct drmif (!amdgpu_userq_enabled (dev))return -ENOTSUPP ; +if (args->num_syncobj_handles >AMDGPU_USERQ_MAX_HANDLES || + args->num_bo_write_handles >AMDGPU_USERQ_MAX_HANDLES || + args->num_bo_read_handles >AMDGPU_USERQ_MAX_HANDLES ) +return -EINVAL ; + num_syncobj_handles = args->num_syncobj_handles; syncobj_handles =memdup_user (u64_to_user_ptr (args->syncobj_handles),size_mul (sizeof (u32), num_syncobj_handles));
Greg Kroah-Hartman
maintainerPATCH 218/378 drm/amdgpu/userq: Fix reference leak in amdgpu_userq_wait_ioctl
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
commit 49abfa812617a7f2d0132c70d23ac98b389c6ec1 upstream.
Drop reference to syncobj and timeline fence when aborting the ioctl due output array being too small.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +2 -0
@@ -880,6 +880,7 @@ int amdgpu_userq_wait_ioctl(struct drm_ddma_fence_unwrap_for_each (f, &iter, fence) {if (num_fences >= wait_info->num_fences) { r = -EINVAL ; +dma_fence_put (fence); goto free_fences; }
@@ -904,6 +905,7 @@ int amdgpu_userq_wait_ioctl(struct drm_dif (num_fences >= wait_info->num_fences) { r = -EINVAL ; +dma_fence_put (fence); goto free_fences; }
Greg Kroah-Hartman
maintainerPATCH 219/378 drm/amdgpu: add upper bound check on user inputs in wait ioctl
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sunil Khatri <[email protected]>
commit 64ac7c09fc44985ec9bb6a9db740899fa40ca613 upstream.
Huge input values in amdgpu_userq_wait_ioctl can lead to a OOM and could be exploited.
So check these input value against AMDGPU_USERQ_MAX_HANDLES which is big enough value for genuine use cases and could potentially avoid OOM.
v2: squash in Srini's fix
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +5 -0
@@ -668,6 +668,11 @@ int amdgpu_userq_wait_ioctl(struct drm_dif (!amdgpu_userq_enabled (dev))return -ENOTSUPP ; +if (wait_info->num_syncobj_handles >AMDGPU_USERQ_MAX_HANDLES || + wait_info->num_bo_write_handles >AMDGPU_USERQ_MAX_HANDLES || + wait_info->num_bo_read_handles >AMDGPU_USERQ_MAX_HANDLES ) +return -EINVAL ; + num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read =memdup_user (u64_to_user_ptr (wait_info->bo_read_handles),size_mul (sizeof (u32), num_read_bo_handles));
Greg Kroah-Hartman
maintainerPATCH 220/378 drm/amd: Disable MES LR compute W/A
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit 6b0d812971370c64b837a2db4275410f478272fe upstream.
A workaround was introduced in commit 1fb710793ce2 ("drm/amdgpu: Enable MES lr_compute_wa by default") to help with some hangs observed in gfx1151.
This WA didn't fully fix the issue. It was actually fixed by adjusting the VGPR size to the correct value that matched the hardware in commit b42f3bf9536c ("drm/amdkfd: bump minimum vgpr size for gfx1151").
There are reports of instability on other products with newer GC microcode versions, and I believe they're caused by this workaround. As we don't need the workaround any more, remove it.
--- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 5 ----- drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 5 ----- 2 files changed, 10 deletions(-)
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +0 -5
@@ -718,11 +718,6 @@ static int mes_v11_0_set_hw_resources(st mes_set_hw_res_pkt.enable_reg_active_poll =1 ; mes_set_hw_res_pkt.enable_level_process_quantum_check =1 ; mes_set_hw_res_pkt.oversubscription_timer =50 ; -if ((mes->adev->mes.sched_version &AMDGPU_MES_VERSION_MASK ) >=0x7f ) - mes_set_hw_res_pkt.enable_lr_compute_wa =1 ; -else -dev_info_once (mes->adev->dev, -"MES FW version must be >= 0x7f to enable LR compute workaround.\n" );if (amdgpu_mes_log_enable) { mes_set_hw_res_pkt.enable_mes_event_int_logging =1 ;
drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +0 -5
@@ -779,11 +779,6 @@ static int mes_v12_0_set_hw_resources(st mes_set_hw_res_pkt.use_different_vmid_compute =1 ; mes_set_hw_res_pkt.enable_reg_active_poll =1 ; mes_set_hw_res_pkt.enable_level_process_quantum_check =1 ; -if ((mes->adev->mes.sched_version &AMDGPU_MES_VERSION_MASK ) >=0x82 ) - mes_set_hw_res_pkt.enable_lr_compute_wa =1 ; -else -dev_info_once (adev->dev, -"MES FW version must be >= 0x82 to enable LR compute workaround.\n" );/* * Keep oversubscribe timer for sdma . When we have unmapped doorbell
Greg Kroah-Hartman
maintainerPATCH 221/378 ipmi:si: Dont block module unload if the BMC is messed up
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit f895e5df80316a308c2f7d64d13a78494630ea05 upstream.
If the BMC is in a bad state, don't bother waiting for queues messages since there can't be any. Otherwise the unload is blocked until the BMC is back in a good state.
--- drivers/char/ipmi/ipmi_si_intf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/char/ipmi/ipmi_si_intf.c +2 -1
@@ -2226,7 +2226,8 @@ static void wait_msg_processed(struct smunsigned long jiffies_now;long time_diff; -while (smi_info->curr_msg || (smi_info->si_state !=SI_NORMAL )) { +while (smi_info->si_state !=SI_HOSED && + (smi_info->curr_msg || (smi_info->si_state !=SI_NORMAL ))) { jiffies_now = jiffies; time_diff = (((long )jiffies_now - (long )smi_info->last_timeout_jiffies) *SI_USEC_PER_JIFFY );
Greg Kroah-Hartman
maintainerPATCH 222/378 ipmi:si: Use a long timeout when the BMC is misbehaving
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit c3bb3295637cc9bf514f690941ca9a385bf30113 upstream.
If the driver goes into HOSED state, don't reset the timeout to the short timeout in the timeout handler.
--- drivers/char/ipmi/ipmi_si_intf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/char/ipmi/ipmi_si_intf.c +3 -1
@@ -1113,7 +1113,9 @@ static void smi_timeout(struct timer_lis * SI_USEC_PER_JIFFY); smi_result =smi_event_handler (smi_info, time_diff); -if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) { +if (smi_info->si_state ==SI_HOSED ) { + timeout = jiffies +SI_TIMEOUT_HOSED ; + }else if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {/* Running with interrupts, only do long timeouts. */ timeout = jiffies +SI_TIMEOUT_JIFFIES ;smi_inc_stat (smi_info, long_timeouts);
Greg Kroah-Hartman
maintainerPATCH 223/378 drm/bridge: samsung-dsim: Fix memory leak in error path
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
commit 803ec1faf7c1823e6e3b1f2aaa81be18528c9436 upstream.
In samsung_dsim_host_attach(), drm_bridge_add() is called to add the bridge. However, if samsung_dsim_register_te_irq() or pdata->host_ops->attach() fails afterwards, the function returns without removing the bridge, causing a memory leak.
Fix this by adding proper error handling with goto labels to ensure drm_bridge_remove() is called in all error paths. Also ensure that samsung_dsim_unregister_te_irq() is called if the attach operation fails after the TE IRQ has been registered.
samsung_dsim_unregister_te_irq() function is moved without changes to be before samsung_dsim_host_attach() to avoid forward declaration.
--- drivers/gpu/drm/bridge/samsung-dsim.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/gpu/drm/bridge/samsung-dsim.c +16 -9
@@ -1881,6 +1881,14 @@ static int samsung_dsim_register_te_irq(return 0 ; } +static void samsung_dsim_unregister_te_irq (struct samsung_dsim *dsi) +{ +if (dsi->te_gpio) { +free_irq (gpiod_to_irq (dsi->te_gpio), dsi); +gpiod_put (dsi->te_gpio); + } +} +static int samsung_dsim_host_attach (struct mipi_dsi_host *host,struct mipi_dsi_device *device) {
@@ -1955,13 +1963,13 @@ of_find_panel_or_bridge:if (!(device->mode_flags &MIPI_DSI_MODE_VIDEO )) { ret =samsung_dsim_register_te_irq (dsi, &device->dev);if (ret) -return ret; + goto err_remove_bridge; }if (pdata->host_ops && pdata->host_ops->attach) { ret = pdata->host_ops->attach (dsi, device);if (ret) -return ret; + goto err_unregister_te_irq; } dsi->lanes = device->lanes;
@@ -1969,14 +1977,13 @@ of_find_panel_or_bridge: dsi->mode_flags = device->mode_flags;return 0 ; -} -static void samsung_dsim_unregister_te_irq (struct samsung_dsim *dsi) -{ -if (dsi->te_gpio) { -free_irq (gpiod_to_irq (dsi->te_gpio), dsi); -gpiod_put (dsi->te_gpio); - } +err_unregister_te_irq: +if (!(device->mode_flags &MIPI_DSI_MODE_VIDEO )) +samsung_dsim_unregister_te_irq (dsi); +err_remove_bridge: +drm_bridge_remove (&dsi->bridge); +return ret; } static int samsung_dsim_host_detach(struct mipi_dsi_host *host,
Greg Kroah-Hartman
maintainerPATCH 224/378 drm/bridge: ti-sn65dsi86: Enable HPD polling if IRQ is not used
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Franz Schnyder <[email protected]>
commit 0b87d51690dd5131cbe9fbd23746b037aab89815 upstream.
Fallback to polling to detect hotplug events on systems without interrupts.
On systems where the interrupt line of the bridge is not connected, the bridge cannot notify hotplug events. Only add the DRM_BRIDGE_OP_HPD flag if an interrupt has been registered otherwise remain in polling mode.
--- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/bridge/ti-sn65dsi86.c +4 -2
@@ -1415,6 +1415,7 @@ static int ti_sn_bridge_probe(struct aux {struct ti_sn65dsi86 *pdata =dev_get_drvdata (adev->dev.parent);struct device_node *np = pdata->dev->of_node; +const struct i2c_client *client =to_i2c_client (pdata->dev);int ret; pdata->next_bridge =devm_drm_of_get_bridge (&adev->dev, np,1 ,0 );
@@ -1433,8 +1434,9 @@ static int ti_sn_bridge_probe(struct aux ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP;if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) { - pdata->bridge.ops =DRM_BRIDGE_OP_EDID |DRM_BRIDGE_OP_DETECT | -DRM_BRIDGE_OP_HPD ; + pdata->bridge.ops =DRM_BRIDGE_OP_EDID |DRM_BRIDGE_OP_DETECT ; +if (client->irq) + pdata->bridge.ops |=DRM_BRIDGE_OP_HPD ;/* * If comms were already enabled they would have been enabled * with the wrong value of HPD_DISABLE. Update it now. Comms
Greg Kroah-Hartman
maintainerPATCH 225/378 ipmi:si: Handle waiting messages when BMC failure detected
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit 52c9ee202edd21d0599ac3b5a6fe1da2a2f053e5 upstream.
If a BMC failure is detected, the current message is returned with an error. However, if there was a waiting message, it would not be handled.
Add a check for the waiting message after handling the current message.
--- drivers/char/ipmi/ipmi_si_intf.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/char/ipmi/ipmi_si_intf.c +6 -0
@@ -809,6 +809,12 @@ restart:*/ return_hosed_msg (smi_info,IPMI_BUS_ERR ); } +if (smi_info->waiting_msg !=NULL ) { +/* Also handle if there was a message waiting. */ + smi_info->curr_msg = smi_info->waiting_msg; + smi_info->waiting_msg =NULL ; +return_hosed_msg (smi_info,IPMI_BUS_ERR ); + }smi_mod_timer (smi_info, jiffies +SI_TIMEOUT_HOSED ); goto out; }
Greg Kroah-Hartman
maintainerPATCH 226/378 nouveau/gsp: drop WARN_ON in ACPI probes
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Airlie <[email protected]>
commit 9478c166c46934160135e197b049b5a05753f2ad upstream.
These WARN_ONs seem to trigger a lot, and we don't seem to have a plan to fix them, so just drop them, as they are most likely harmless.
--- drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +6 -6
@@ -737,8 +737,8 @@ r535_gsp_acpi_caps(acpi_handle handle, Cif (!obj) goto done; -if (WARN_ON (obj->type !=ACPI_TYPE_BUFFER ) || -WARN_ON (obj->buffer.length !=4 )) +if (obj->type !=ACPI_TYPE_BUFFER || + obj->buffer.length !=4 ) goto done; caps->status =0 ;
@@ -773,8 +773,8 @@ r535_gsp_acpi_jt(acpi_handle handle, JT_if (!obj) goto done; -if (WARN_ON (obj->type !=ACPI_TYPE_BUFFER ) || -WARN_ON (obj->buffer.length !=4 )) +if (obj->type !=ACPI_TYPE_BUFFER || + obj->buffer.length !=4 ) goto done; jt->status =0 ;
@@ -861,8 +861,8 @@ r535_gsp_acpi_dod(acpi_handle handle, DO _DOD = output.pointer; -if (WARN_ON (_DOD->type !=ACPI_TYPE_PACKAGE ) || -WARN_ON (_DOD->package.count >ARRAY_SIZE (dod->acpiIdList))) +if (_DOD->type !=ACPI_TYPE_PACKAGE || + _DOD->package.count >ARRAY_SIZE (dod->acpiIdList))return ;for (int i =0 ; i < _DOD->package.count; i++) {
Greg Kroah-Hartman
maintainerPATCH 227/378 drm/i915/alpm: ALPM disable fixes
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jouni Högander <[email protected]>
commit eb4a7139e97374f42b7242cc754e77f1623fbcd5 upstream.
PORT_ALPM_CTL is supposed to be written only before link training. Remove writing it from ALPM disable.
Also clearing ALPM_CTL_ALPM_AUX_LESS_ENABLE and is not about disabling ALPM but switching to AUX-Wake ALPM. Stop touching this bit on ALPM disable.
--- drivers/gpu/drm/i915/display/intel_alpm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/gpu/drm/i915/display/intel_alpm.c +1 -6
@@ -558,12 +558,7 @@ void intel_alpm_disable(struct intel_dpmutex_lock (&intel_dp->alpm.lock);intel_de_rmw (display,ALPM_CTL (display, cpu_transcoder), -ALPM_CTL_ALPM_ENABLE |ALPM_CTL_LOBF_ENABLE | -ALPM_CTL_ALPM_AUX_LESS_ENABLE ,0 ); - -intel_de_rmw (display, -PORT_ALPM_CTL (cpu_transcoder), -PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE ,0 ); +ALPM_CTL_ALPM_ENABLE |ALPM_CTL_LOBF_ENABLE ,0 );drm_dbg_kms (display->drm,"Disabling ALPM\n" );mutex_unlock (&intel_dp->alpm.lock);
Greg Kroah-Hartman
maintainerPATCH 228/378 gpiolib: normalize the return value of gc->get() on behalf of buggy drivers
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit ec2cceadfae72304ca19650f9cac4b2a97b8a2fc upstream.
Commit 86ef402d805d ("gpiolib: sanitize the return value of gpio_chip::get()") started checking the return value of the .get() callback in struct gpio_chip. Now - almost a year later - it turns out that there are quite a few drivers in tree that can break with this change. Partially revert it: normalize the return value in GPIO core but also emit a warning.
--- drivers/gpio/gpiolib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/gpio/gpiolib.c +6 -2
@@ -3268,8 +3268,12 @@ static int gpiochip_get(struct gpio_chip/* Make sure this is called after checking for gc->get(). */ ret = gc->get (gc, offset); -if (ret >1 ) - ret = -EBADE ; +if (ret >1 ) { +gpiochip_warn (gc, +"invalid return value from gc->get(): %d, consider fixing the driver\n" , + ret); + ret = !!ret; + }return ret; }
Greg Kroah-Hartman
maintainerPATCH 229/378 ipmi:si: Fix check for a misbehaving BMC
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <[email protected]>
commit cae66f1a1dcd23e17da5a015ef9d731129f9d2dd upstream.
There is a race on checking the state in the sender, it needs to be checked under a lock. But you also need a check to avoid issues with a misbehaving BMC for run to completion mode. So leave the check at the beginning for run to completion, and add a check under the lock to avoid the race.
--- drivers/char/ipmi/ipmi_si_intf.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
drivers/char/ipmi/ipmi_si_intf.c +13 -11
@@ -924,9 +924,14 @@ static int sender(void *send_info, struc {struct smi_info *smi_info = send_info;unsigned long flags; +int rv =IPMI_CC_NO_ERROR ;debug_timestamp (smi_info,"Enqueue" ); +/* +* Check here for run to completion mode. A check under lock is +* later. +*/ if (smi_info->si_state ==SI_HOSED )return IPMI_BUS_ERR ;
@@ -940,18 +945,15 @@ static int sender(void *send_info, struc }spin_lock_irqsave (&smi_info->si_lock, flags); -/* -* The following two lines don't need to be under the lock for -* the lock's sake, but they do need SMP memory barriers to -* avoid getting things out of order. We are already claiming -* the lock, anyway, so just do it under the lock to avoid the -* ordering problem. -*/ -BUG_ON (smi_info->waiting_msg); - smi_info->waiting_msg = msg; -check_start_timer_thread (smi_info); +if (smi_info->si_state ==SI_HOSED ) { + rv =IPMI_BUS_ERR ; + }else { +BUG_ON (smi_info->waiting_msg); + smi_info->waiting_msg = msg; +check_start_timer_thread (smi_info); + }spin_unlock_irqrestore (&smi_info->si_lock, flags); -return IPMI_CC_NO_ERROR ; +return rv; }static void set_run_to_completion (void *send_info,bool i_run_to_completion)
Greg Kroah-Hartman
maintainerPATCH 230/378 drm/xe/sync: Fix user fence leak on alloc failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
commit 0879c3f04f67e2a1677c25dcc24669ce21eb6a6c upstream.
When dma_fence_chain_alloc() fails, properly release the user fence reference to prevent a memory leak.
--- drivers/gpu/drm/xe/xe_sync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_sync.c +4 -2
@@ -200,8 +200,10 @@ int xe_sync_entry_parse(struct xe_deviceif (XE_IOCTL_DBG (xe,IS_ERR (sync->ufence)))return PTR_ERR (sync->ufence); sync->ufence_chain_fence =dma_fence_chain_alloc (); -if (!sync->ufence_chain_fence) -return -ENOMEM ; +if (!sync->ufence_chain_fence) { + err = -ENOMEM ; + goto free_sync; + } sync->ufence_syncobj = ufence_syncobj; }
Greg Kroah-Hartman
maintainerPATCH 231/378 drm/xe/sync: Cleanup partially initialized sync on parse failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
commit 1bfd7575092420ba5a0b944953c95b74a5646ff8 upstream.
xe_sync_entry_parse() can allocate references (syncobj, fence, chain fence, or user fence) before hitting a later failure path. Several of those paths returned directly, leaving partially initialized state and leaking refs.
Route these error paths through a common free_sync label and call xe_sync_entry_cleanup(sync) before returning the error.
--- drivers/gpu/drm/xe/xe_sync.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
drivers/gpu/drm/xe/xe_sync.c +17 -7
@@ -146,8 +146,10 @@ int xe_sync_entry_parse(struct xe_deviceif (!signal) { sync->fence =drm_syncobj_fence_get (sync->syncobj); -if (XE_IOCTL_DBG (xe, !sync->fence)) -return -EINVAL ; +if (XE_IOCTL_DBG (xe, !sync->fence)) { + err = -EINVAL ; + goto free_sync; + } }break ;
@@ -167,17 +169,21 @@ int xe_sync_entry_parse(struct xe_deviceif (signal) { sync->chain_fence =dma_fence_chain_alloc (); -if (!sync->chain_fence) -return -ENOMEM ; +if (!sync->chain_fence) { + err = -ENOMEM ; + goto free_sync; + } }else { sync->fence =drm_syncobj_fence_get (sync->syncobj); -if (XE_IOCTL_DBG (xe, !sync->fence)) -return -EINVAL ; +if (XE_IOCTL_DBG (xe, !sync->fence)) { + err = -EINVAL ; + goto free_sync; + } err =dma_fence_chain_find_seqno (&sync->fence, sync_in.timeline_value);if (err) -return err; + goto free_sync; }break ;
@@ -218,6 +224,10 @@ int xe_sync_entry_parse(struct xe_device sync->timeline_value = sync_in.timeline_value;return 0 ; + +free_sync: +xe_sync_entry_cleanup (sync); +return err; }ALLOW_ERROR_INJECTION (xe_sync_entry_parse,ERRNO );
Greg Kroah-Hartman
maintainerPATCH 232/378 s390/pfault: Fix virtual vs physical address confusion
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Gordeev <[email protected]>
commit d879ac6756b662a085a743e76023c768c3241579 upstream.
When Linux is running as guest, runs a user space process and the user space process accesses a page that the host has paged out, the guest gets a pfault interrupt and schedules a different process. Without this mechanism the host would have to suspend the whole virtual CPU until the page has been paged in.
To setup the pfault interrupt the real address of parameter list should be passed to DIAGNOSE 0x258, but a virtual address is passed instead.
That has a performance impact, since the pfault setup never succeeds, the interrupt is never delivered to a guest and the whole virtual CPU is suspended as result.
--- arch/s390/mm/pfault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/mm/pfault.c +2 -2
@@ -62,7 +62,7 @@ int __pfault_init(void)"0: nopr %%r7\n" EX_TABLE (0b ,0b ) : [rc] "+d" (rc) - : [refbk] "a" (&pfault_init_refbk), "m" (pfault_init_refbk) + : [refbk] "a" (virt_to_phys(&pfault_init_refbk)), "m" (pfault_init_refbk) : "cc"); return rc; }
@@ -84,7 +84,7 @@ void __pfault_fini(void)"0: nopr %%r7\n" EX_TABLE (0b ,0b ) : - : [refbk] "a" (&pfault_fini_refbk), "m" (pfault_fini_refbk) + : [refbk] "a" (virt_to_phys(&pfault_fini_refbk)), "m" (pfault_fini_refbk) : "cc"); }
Greg Kroah-Hartman
maintainerPATCH 233/378 bpf: Fix kprobe_multi cookies access in show_fdinfo callback
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Olsa <[email protected]>
commit ad6fface76da42721c15e8fb281570aaa44a2c01 upstream.
We don't check if cookies are available on the kprobe_multi link before accessing them in show_fdinfo callback, we should.
--- kernel/trace/bpf_trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/bpf_trace.c +3 -1
@@ -2441,8 +2441,10 @@ static void bpf_kprobe_multi_show_fdinfo struct seq_file *seq) {struct bpf_kprobe_multi_link *kmulti_link; +bool has_cookies; kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); + has_cookies = !!kmulti_link->cookies;seq_printf (seq, "kprobe_cnt:\t%u\n"
@@ -2454,7 +2456,7 @@ static void bpf_kprobe_multi_show_fdinfofor (int i =0 ; i < kmulti_link->cnt; i++) {seq_printf (seq,"%llu\t %pS\n" , - kmulti_link->cookies[i], + has_cookies ? kmulti_link->cookies[i] :0 , (void *)kmulti_link->addrs[i]); } }
Greg Kroah-Hartman
maintainerPATCH 234/378 arm64: gcs: Honour mprotect(PROT_NONE) on shadow stack mappings
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Catalin Marinas <[email protected]>
commit 47a8aad135ac1aed04b7b0c0a8157fd208075827 upstream.
vm_get_page_prot() short-circuits the protection_map[] lookup for a VM_SHADOW_STACK mapping since it uses a different PIE index from the typical read/write/exec permissions. However, the side effect is that it also ignores mprotect(PROT_NONE) by creating an accessible PTE.
Special-case the !(vm_flags & VM_ACCESS_FLAGS) flags to use the protection_map[VM_NONE] permissions instead. No GCS attributes are required for an inaccessible PTE.
--- arch/arm64/mm/mmap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/arm64/mm/mmap.c +5 -1
@@ -91,7 +91,11 @@ pgprot_t vm_get_page_prot(vm_flags_t vm_/* Short circuit GCS to avoid bloating the table. */ if (system_supports_gcs () && (vm_flags &VM_SHADOW_STACK )) { - prot = gcs_page_prot; +/* Honour mprotect(PROT_NONE) on shadow stack mappings */ +if (vm_flags &VM_ACCESS_FLAGS ) + prot = gcs_page_prot; +else + prot =pgprot_val (protection_map[VM_NONE ]); }else { prot =pgprot_val (protection_map[vm_flags & (VM_READ |VM_WRITE |VM_EXEC |VM_SHARED )]);
Greg Kroah-Hartman
maintainerPATCH 235/378 nfsd: Fix cred ref leak in nfsd_nl_listener_set_doit().
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
commit 92978c83bb4eef55d02a6c990c01c423131eefa7 upstream.
nfsd_nl_listener_set_doit() uses get_current_cred() without put_cred().
As we can see from other callers, svc_xprt_create_from_sa() does not require the extra refcount.
nfsd_nl_listener_set_doit() is always in the process context, sendmsg(), and current->cred does not go away.
Let's use current_cred() in nfsd_nl_listener_set_doit().
--- fs/nfsd/nfsctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfsctl.c +1 -1
@@ -1993,7 +1993,7 @@ int nfsd_nl_listener_set_doit(struct sk_ } ret =svc_xprt_create_from_sa (serv, xcl_name, net, sa,0 , -get_current_cred ()); +current_cred ());/* always save the latest error */ if (ret <0 ) err = ret;
Greg Kroah-Hartman
maintainerPATCH 236/378 device property: Allow secondary lookup in fwnode_get_next_child_node()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit 2692c614f8f05929d692b3dbfd3faef1f00fbaf0 upstream.
When device_get_child_node_count() got split to the fwnode and device respective APIs, the fwnode didn't inherit the ability to traverse over the secondary fwnode. Hence any user, that switches from device to fwnode API misses this feature. In particular, this was revealed by the commit 1490cbb9dbfd ("device property: Split fwnode_get_child_node_count()") that effectively broke the GPIO enumeration on Intel Galileo boards. Fix this by moving the secondary lookup from device to fwnode API.
Note, in general no device_*() API should go into the depth of the fwnode implementation.
--- drivers/base/property.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-)
drivers/base/property.c +13 -14
@@ -797,7 +797,18 @@ struct fwnode_handle * fwnode_get_next_child_node(const struct fwnode_handle *fwnode, struct fwnode_handle *child) { - return fwnode_call_ptr_op(fwnode, get_next_child_node, child); + struct fwnode_handle *next; + +if (IS_ERR_OR_NULL (fwnode)) +return NULL ; + +/* Try to find a child in primary fwnode */ + next =fwnode_call_ptr_op (fwnode, get_next_child_node, child); +if (next) +return next; + +/* When no more children in primary, continue with secondary */ +return fwnode_call_ptr_op (fwnode->secondary, get_next_child_node, child); }EXPORT_SYMBOL_GPL (fwnode_get_next_child_node);
@@ -841,19 +852,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_availastruct fwnode_handle *device_get_next_child_node (const struct device *dev,struct fwnode_handle *child) { -const struct fwnode_handle *fwnode =dev_fwnode (dev); -struct fwnode_handle *next; - -if (IS_ERR_OR_NULL (fwnode)) -return NULL ; - -/* Try to find a child in primary fwnode */ - next =fwnode_get_next_child_node (fwnode, child); -if (next) -return next; - -/* When no more children in primary, continue with secondary */ -return fwnode_get_next_child_node (fwnode->secondary, child); +return fwnode_get_next_child_node (dev_fwnode (dev), child); }EXPORT_SYMBOL_GPL (device_get_next_child_node);
Greg Kroah-Hartman
maintainerPATCH 237/378 irqchip/gic-v3-its: Limit number of per-device MSIs to the range the ITS supports
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit ce9e40a9a5e5cff0b1b0d2fa582b3d71a8ce68e8 upstream.
The ITS driver blindly assumes that EventIDs are in abundant supply, to the point where it never checks how many the hardware actually supports.
It turns out that some pretty esoteric integrations make it so that only a few bits are available, all the way down to a single bit.
Enforce the advertised limitation at the point of allocating the device structure, and hope that the endpoint driver can deal with such limitation.
--- drivers/irqchip/irq-gic-v3-its.c | 4 ++++ include/linux/irqchip/arm-gic-v3.h | 1 + 2 files changed, 5 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +4 -0
@@ -3475,6 +3475,7 @@ static struct its_device *its_create_devint lpi_base;int nr_lpis;int nr_ites; +int id_bits;int sz;if (!its_alloc_device_table (its, dev_id))
@@ -3486,7 +3487,10 @@ static struct its_device *its_create_dev/* * Even if the device wants a single LPI, the ITT must be * sized as a power of two (and you need at least one bit...). +* Also honor the ITS's own EID limit. */ + id_bits =FIELD_GET (GITS_TYPER_IDBITS , its->typer) +1 ; + nvecs = min_t(unsigned int, nvecs, BIT(id_bits)); nr_ites =max (2 , nvecs); sz = nr_ites * (FIELD_GET (GITS_TYPER_ITT_ENTRY_SIZE , its->typer) +1 ); sz =max (sz,ITS_ITT_ALIGN );
include/linux/irqchip/arm-gic-v3.h +1 -0
@@ -394,6 +394,7 @@#define GITS_TYPER_VLPIS (1UL << 1)#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4) +#define GITS_TYPER_IDBITS GENMASK_ULL(12, 8)#define GITS_TYPER_IDBITS_SHIFT 8#define GITS_TYPER_DEVBITS_SHIFT 13#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13)
Greg Kroah-Hartman
maintainerPATCH 238/378 btrfs: fix chunk map leak in btrfs_map_block() after btrfs_chunk_map_num_copies()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
commit f15fb3d41543244d1179f423da4a4832a55bc050 upstream.
Fix a chunk map leak in btrfs_map_block(): if we return early with -EINVAL, we're not freeing the chunk map that we've just looked up.
--- fs/btrfs/volumes.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/btrfs/volumes.c +4 -2
@@ -6707,8 +6707,10 @@ int btrfs_map_block(struct btrfs_fs_inforeturn PTR_ERR (map); num_copies =btrfs_chunk_map_num_copies (map); -if (io_geom.mirror_num > num_copies) -return -EINVAL ; +if (io_geom.mirror_num > num_copies) { + ret = -EINVAL ; + goto out; + } map_offset = logical - map->start; io_geom.raid56_full_stripe_start = (u64)-1 ;
Greg Kroah-Hartman
maintainerPATCH 239/378 sched_ext: Disable preemption between scx_claim_exit() and kicking helper work
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
commit 83236b2e43dba00bee5b82eb5758816b1a674f6a upstream.
scx_claim_exit() atomically sets exit_kind, which prevents scx_error() from triggering further error handling. After claiming exit, the caller must kick the helper kthread work which initiates bypass mode and teardown.
If the calling task gets preempted between claiming exit and kicking the helper work, and the BPF scheduler fails to schedule it back (since error handling is now disabled), the helper work is never queued, bypass mode never activates, tasks stop being dispatched, and the system wedges.
Disable preemption across scx_claim_exit() and the subsequent work kicking in all callers - scx_disable() and scx_vexit(). Add lockdep_assert_preemption_disabled() to scx_claim_exit() to enforce the requirement.
--- kernel/sched/ext.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
kernel/sched/ext.c +12 -0
@@ -4390,10 +4390,19 @@ done:scx_bypass (false); } +/* +* Claim the exit on @sch. The caller must ensure that the helper kthread work +* is kicked before the current task can be preempted. Once exit_kind is +* claimed, scx_error() can no longer trigger, so if the current task gets +* preempted and the BPF scheduler fails to schedule it back, the helper work +* will never be kicked and the whole system can wedge. +*/ static bool scx_claim_exit (struct scx_sched *sch,enum scx_exit_kind kind) {int none =SCX_EXIT_NONE ; +lockdep_assert_preemption_disabled (); +if (!atomic_try_cmpxchg (&sch->exit_kind, &none, kind))return false;
@@ -4416,6 +4425,7 @@ static void scx_disable(enum scx_exit_kircu_read_lock (); sch =rcu_dereference (scx_root);if (sch) { +guard (preempt)();scx_claim_exit (sch, kind);kthread_queue_work (sch->helper, &sch->disable_work); }
@@ -4738,6 +4748,8 @@ static bool scx_vexit(struct scx_sched * {struct scx_exit_info *ei = sch->exit_info; +guard (preempt)(); +if (!scx_claim_exit (sch, kind))return false;
Greg Kroah-Hartman
maintainerPATCH 240/378 sched_ext: Fix starvation of scx_enable() under fair-class saturation
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
commit b06ccbabe2506fd70b9167a644978b049150224a upstream.
During scx_enable(), the READY -> ENABLED task switching loop changes the calling thread's sched_class from fair to ext. Since fair has higher priority than ext, saturating fair-class workloads can indefinitely starve the enable thread, hanging the system. This was introduced when the enable path switched from preempt_disable() to scx_bypass() which doesn't protect against fair-class starvation. Note that the original preempt_disable() protection wasn't complete either - in partial switch modes, the calling thread could still be starved after preempt_enable() as it may have been switched to ext class.
Fix it by offloading the enable body to a dedicated system-wide RT (SCHED_FIFO) kthread which cannot be starved by either fair or ext class tasks. scx_enable() lazily creates the kthread on first use and passes the ops pointer through a struct scx_enable_cmd containing the kthread_work, then synchronously waits for completion.
The workfn runs on a different kthread from sch->helper (which runs disable_work), so it can safely flush disable_work on the error path without deadlock.
--- kernel/sched/ext.c | 66 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 10 deletions(-)
kernel/sched/ext.c +56 -10
@@ -4935,20 +4935,30 @@ static int validate_ops(struct scx_schedreturn 0 ; } -static int scx_enable (struct sched_ext_ops *ops,struct bpf_link *link) +/* +* scx_enable() is offloaded to a dedicated system-wide RT kthread to avoid +* starvation. During the READY -> ENABLED task switching loop, the calling +* thread's sched_class gets switched from fair to ext. As fair has higher +* priority than ext, the calling thread can be indefinitely starved under +* fair-class saturation, leading to a system hang. +*/ +struct scx_enable_cmd { +struct kthread_work work; +struct sched_ext_ops *ops; +int ret; +}; + +static void scx_enable_workfn (struct kthread_work *work) { +struct scx_enable_cmd *cmd = + container_of(work, struct scx_enable_cmd, work); +struct sched_ext_ops *ops = cmd->ops;struct scx_sched *sch;struct scx_task_iter sti;struct task_struct *p;unsigned long timeout;int i, cpu, ret; -if (!cpumask_equal (housekeeping_cpumask (HK_TYPE_DOMAIN ), - cpu_possible_mask)) { -pr_err ("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n" ); -return -EINVAL ; - } -mutex_lock (&scx_enable_mutex);if (scx_enable_state () !=SCX_DISABLED ) {
@@ -5165,13 +5175,15 @@ static int scx_enable(struct sched_ext_oatomic_long_inc (&scx_enable_seq); -return 0 ; + cmd->ret =0 ; +return ; err_free_ksyncs:free_kick_syncs (); err_unlock:mutex_unlock (&scx_enable_mutex); -return ret; + cmd->ret = ret; +return ; err_disable_unlock_all:scx_cgroup_unlock ();
@@ -5190,7 +5202,41 @@ err_disable:*/ scx_error (sch,"scx_enable() failed (%d)" , ret);kthread_flush_work (&sch->disable_work); -return 0 ; + cmd->ret =0 ; +} + +static int scx_enable (struct sched_ext_ops *ops,struct bpf_link *link) +{ +static struct kthread_worker *helper; +static DEFINE_MUTEX (helper_mutex); +struct scx_enable_cmd cmd; + +if (!cpumask_equal (housekeeping_cpumask (HK_TYPE_DOMAIN ), + cpu_possible_mask)) { +pr_err ("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n" ); +return -EINVAL ; + } + +if (!READ_ONCE (helper)) { +mutex_lock (&helper_mutex); +if (!helper) { + helper =kthread_run_worker (0 ,"scx_enable_helper" ); +if (IS_ERR_OR_NULL (helper)) { + helper =NULL ; +mutex_unlock (&helper_mutex); +return -ENOMEM ; + } +sched_set_fifo (helper->task); + } +mutex_unlock (&helper_mutex); + } + +kthread_init_work (&cmd.work, scx_enable_workfn); + cmd.ops = ops; + +kthread_queue_work (READ_ONCE (helper), &cmd.work); +kthread_flush_work (&cmd.work); +return cmd.ret; }
Re: [PATCH 6.19 240/378] sched_ext: Fix starvation of scx_enable() under fair-class saturation
Quoted 7 lines · Greg Kroah-Hartman
6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
commit
b06ccbabe2506fd70b9167a644978b049150224aupstream.
This one likely needs also:2fcfe5951eb2 sched_ext: Use WRITE_ONCE() for the write side of scx_enable helper pointer
thanks,
Signature · 2 lines
js suse labs
Greg Kroah-Hartman
maintainerRe: [PATCH 6.19 240/378] sched_ext: Fix starvation of scx_enable() under fair-class saturation
Quoted 5 lines · Jiri Slaby
Quoted 4 lines · Greg Kroah-Hartman
6.19-stable review patch. If anyone has any objections, please let me know.
------------------
Quoted 7 lines
Quoted 3 lines
From: Tejun Heo <[email protected]>
commit
b06ccbabe2506fd70b9167a644978b049150224aupstream.This one likely needs also:
2fcfe5951eb2sched_ext: UseWRITE_ONCE()for the write side ofscx_enablehelper pointer
Ugh, I missed that, thanks for catching it!
greg k-h
Greg Kroah-Hartman
maintainerPATCH 241/378 iomap: dont mark folio uptodate if read IO has bytes pending
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit debc1a492b2695d05973994fb0f796dbd9ceaae6 upstream.
If a folio has ifs metadata attached to it and the folio is partially read in through an async IO helper with the rest of it then being read in through post-EOF zeroing or as inline data, and the helper successfully finishes the read first, then post-EOF zeroing / reading inline will mark the folio as uptodate in iomap_set_range_uptodate().
This is a problem because when the read completion path later calls iomap_read_end(), it will call folio_end_read(), which sets the uptodate bit using XOR semantics. Calling folio_end_read() on a folio that was already marked uptodate clears the uptodate bit.
Fix this by not marking the folio as uptodate if the read IO has bytes pending. The folio uptodate state will be set in the read completion path through iomap_end_read() -> folio_end_read().
--- fs/iomap/buffered-io.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
fs/iomap/buffered-io.c +12 -3
@@ -79,18 +79,27 @@ static void iomap_set_range_uptodate(str {struct iomap_folio_state *ifs = folio->private;unsigned long flags; -bool uptodate = true; +bool mark_uptodate = true;if (folio_test_uptodate (folio))return ;if (ifs) {spin_lock_irqsave (&ifs->state_lock, flags); - uptodate =ifs_set_range_uptodate (folio, ifs, off, len); +/* +* If a read with bytes pending is in progress, we must not call +* folio_mark_uptodate(). The read completion path +* (iomap_read_end()) will call folio_end_read(), which uses XOR +* semantics to set the uptodate bit. If we set it here, the XOR +* in folio_end_read() will clear it, leaving the folio not +* uptodate. +*/ + mark_uptodate =ifs_set_range_uptodate (folio, ifs, off, len) && + !ifs->read_bytes_pending;spin_unlock_irqrestore (&ifs->state_lock, flags); } -if (uptodate) +if (mark_uptodate)folio_mark_uptodate (folio); }
Greg Kroah-Hartman
maintainerPATCH 242/378 iomap: reject delalloc mappings during writeback
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit d320f160aa5ff36cdf83c645cca52b615e866e32 upstream.
Filesystems should never provide a delayed allocation mapping to writeback; they're supposed to allocate the space before replying. This can lead to weird IO errors and crashes in the block layer if the filesystem is being malicious, or if it hadn't set iomap->dev because it's a delalloc mapping.
Fix this by failing writeback on delalloc mappings. Currently no filesystems actually misbehave in this manner, but we ought to be stricter about things like that.
--- fs/iomap/ioend.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/iomap/ioend.c +7 -6
@@ -163,17 +163,18 @@ ssize_t iomap_add_to_ioend(struct iomap_WARN_ON_ONCE (!folio->private && map_len < dirty_len);switch (wpc->iomap.type) { -case IOMAP_INLINE : -WARN_ON_ONCE (1 ); -return -EIO ; +case IOMAP_UNWRITTEN : + ioend_flags |=IOMAP_IOEND_UNWRITTEN ; +break ; +case IOMAP_MAPPED : +break ;case IOMAP_HOLE :return map_len;default : -break ; +WARN_ON_ONCE (1 ); +return -EIO ; } -if (wpc->iomap.type ==IOMAP_UNWRITTEN ) - ioend_flags |=IOMAP_IOEND_UNWRITTEN ;if (wpc->iomap.flags &IOMAP_F_SHARED ) ioend_flags |=IOMAP_IOEND_SHARED ;if (folio_test_dropbehind (folio))
Greg Kroah-Hartman
maintainerPATCH 243/378 nsfs: tighten permission checks for handle opening
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit d2324a9317f00013facb0ba00b00440e19d2af5e upstream.
Even privileged services should not necessarily be able to see other privileged service's namespaces so they can't leak information to each other. Use may_see_all_namespaces() helper that centralizes this policy until the nstree adapts.
--- fs/nsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nsfs.c +1 -1
@@ -614,7 +614,7 @@ static struct dentry *nsfs_fh_to_dentry(return ERR_PTR (-EOPNOTSUPP ); } -if (owning_ns && !ns_capable (owning_ns,CAP_SYS_ADMIN )) { +if (owning_ns && !may_see_all_namespaces ()) { ns->ops->put (ns);return ERR_PTR (-EPERM ); }
Greg Kroah-Hartman
maintainerPATCH 244/378 nstree: tighten permission checks for listing
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 8d76afe84fa2babf604b3c173730d4d2b067e361 upstream.
Even privileged services should not necessarily be able to see other privileged service's namespaces so they can't leak information to each other. Use may_see_all_namespaces() helper that centralizes this policy until the nstree adapts.
--- kernel/nstree.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-)
kernel/nstree.c +4 -25
@@ -515,32 +515,11 @@ static inline bool __must_check ns_requested(const struct klistns *kls,static inline bool __must_check may_list_ns (const struct klistns *kls,struct ns_common *ns) { -if (kls->user_ns) { -if (kls->userns_capable) -return true; - }else { -struct ns_common *owner; -struct user_namespace *user_ns; - - owner =ns_owner (ns); -if (owner) - user_ns =to_user_ns (owner); -else - user_ns = &init_user_ns; -if (ns_capable_noaudit (user_ns,CAP_SYS_ADMIN )) -return true; - } - +if (kls->user_ns && kls->userns_capable) +return true;if (is_current_namespace (ns))return true; - -if (ns->ns_type !=CLONE_NEWUSER ) -return false; - -if (ns_capable_noaudit (to_user_ns (ns),CAP_SYS_ADMIN )) -return true; - -return false; +return may_see_all_namespaces (); }static inline void ns_put (struct ns_common *ns)
@@ -600,7 +579,7 @@ static ssize_t do_listns_userns(struct klistns *kls) ret =0 ; head = &to_ns_common (kls->user_ns)->ns_owner_root.ns_list_head; - kls->userns_capable =ns_capable_noaudit (kls->user_ns,CAP_SYS_ADMIN ); + kls->userns_capable =may_see_all_namespaces ();rcu_read_lock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 245/378 ice: reintroduce retry mechanism for indirect AQ
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Staniszewski <[email protected]>
commit 326256c0a72d4877cec1d4df85357da106233128 upstream.
Add retry mechanism for indirect Admin Queue (AQ) commands. To do so we need to keep the command buffer.
This technically reverts commit 43a630e37e25
("ice: remove unused buffer copy code in ice_sq_send_cmd_retry()"), but combines it with a fix in the logic by using a kmemdup() call, making it more robust and less likely to break in the future due to programmer error.
--- drivers/net/ethernet/intel/ice/ice_common.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +9 -3
@@ -1879,6 +1879,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, {struct libie_aq_desc desc_cpy;bool is_cmd_for_retry; +u8 *buf_cpy =NULL ;u8 idx =0 ;u16 opcode;int status;
@@ -1888,8 +1889,11 @@ ice_sq_send_cmd_retry(struct ice_hw *hw,memset (&desc_cpy,0 ,sizeof (desc_cpy));if (is_cmd_for_retry) { -/* All retryable cmds are direct, without buf. */ -WARN_ON (buf); +if (buf) { + buf_cpy =kmemdup (buf, buf_size,GFP_KERNEL ); +if (!buf_cpy) +return -ENOMEM ; + }memcpy (&desc_cpy, desc,sizeof (desc_cpy)); }
@@ -1901,12 +1905,14 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY) break; +if (buf_cpy) +memcpy (buf, buf_cpy, buf_size);memcpy (desc, &desc_cpy,sizeof (desc_cpy)); -msleep (ICE_SQ_SEND_DELAY_TIME_MS ); }while (++idx <ICE_SQ_SEND_MAX_EXECUTE ); +kfree (buf_cpy);return status; }
Greg Kroah-Hartman
maintainerPATCH 246/378 kunit: irq: Ensure timer doesnt fire too frequently
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 201ceb94aa1def0024a7c18ce643e5f65026be06 upstream.
Fix a bug where kunit_run_irq_test() could hang if the system is too slow. This was noticed with the crypto library tests in certain VMs.
Specifically, if kunit_irq_test_timer_func() and the associated hrtimer code took over 5us to run, then the CPU would spend all its time executing that code in hardirq context. As a result, the task executing kunit_run_irq_test() never had a chance to run, exit the loop, and cancel the timer.
To fix it, make kunit_irq_test_timer_func() increase the timer interval when the other contexts aren't having a chance to run.
--- include/kunit/run-in-irq-context.h | 44 +++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-)
include/kunit/run-in-irq-context.h +28 -16
@@ -12,16 +12,16 @@#include <linux/hrtimer.h> #include <linux/workqueue.h> -#define KUNIT_IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5) -struct kunit_irq_test_state {bool (*func)(void *test_specific_state);void *test_specific_state;bool task_func_reported_failure;bool hardirq_func_reported_failure;bool softirq_func_reported_failure; +atomic_t task_func_calls;atomic_t hardirq_func_calls;atomic_t softirq_func_calls; +ktime_t interval;struct hrtimer timer;struct work_struct bh_work; };
@@ -30,14 +30,25 @@ static enum hrtimer_restart kunit_irq_te {struct kunit_irq_test_state *state =container_of (timer,typeof (*state), timer); +int task_calls, hardirq_calls, softirq_calls;WARN_ON_ONCE (!in_hardirq ()); -atomic_inc (&state->hardirq_func_calls); + task_calls =atomic_read (&state->task_func_calls); + hardirq_calls =atomic_inc_return (&state->hardirq_func_calls); + softirq_calls =atomic_read (&state->softirq_func_calls); + +/* +* If the timer is firing too often for the softirq or task to ever have +* a chance to run, increase the timer interval. This is needed on very +* slow systems. +*/ +if (hardirq_calls >=20 && (softirq_calls ==0 || task_calls ==0 )) + state->interval =ktime_add_ns (state->interval,250 );if (!state->func (state->test_specific_state)) state->hardirq_func_reported_failure = true; -hrtimer_forward_now (&state->timer,KUNIT_IRQ_TEST_HRTIMER_INTERVAL ); +hrtimer_forward_now (&state->timer, state->interval);queue_work (system_bh_wq, &state->bh_work);return HRTIMER_RESTART ; }
@@ -86,10 +97,14 @@ static inline void kunit_run_irq_test(ststruct kunit_irq_test_state state = { .func = func, .test_specific_state = test_specific_state, +/* +* Start with a 5us timer interval. If the system can't keep +* up, kunit_irq_test_timer_func() will increase it. +*/ + .interval =us_to_ktime (5 ), };unsigned long end_jiffies; -int hardirq_calls, softirq_calls; -bool allctx = false; +int task_calls, hardirq_calls, softirq_calls;/* * Set up a hrtimer (the way we access hardirq context) and a work
@@ -104,21 +119,18 @@ static inline void kunit_run_irq_test(st* and hardirq), or 1 second, whichever comes first. */ end_jiffies = jiffies +HZ ; -hrtimer_start (&state.timer,KUNIT_IRQ_TEST_HRTIMER_INTERVAL , -HRTIMER_MODE_REL_HARD ); -for (int task_calls =0 , calls =0 ; - ((calls < max_iterations) || !allctx) && - !time_after (jiffies, end_jiffies); - task_calls++) { +hrtimer_start (&state.timer, state.interval,HRTIMER_MODE_REL_HARD ); +do {if (!func (test_specific_state)) state.task_func_reported_failure = true; + task_calls =atomic_inc_return (&state.task_func_calls); hardirq_calls =atomic_read (&state.hardirq_func_calls); softirq_calls =atomic_read (&state.softirq_func_calls); - calls = task_calls + hardirq_calls + softirq_calls; - allctx = (task_calls >0 ) && (hardirq_calls >0 ) && - (softirq_calls >0 ); - } + }while ((task_calls + hardirq_calls + softirq_calls < max_iterations || + (task_calls ==0 || hardirq_calls ==0 || + softirq_calls ==0 )) && + !time_after (jiffies, end_jiffies));/* Cancel the timer and work. */ hrtimer_cancel (&state.timer);
Greg Kroah-Hartman
maintainerPATCH 247/378 ixgbevf: fix link setup issue
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jedrzej Jagielski <[email protected]>
commit feae40a6a178bb525a15f19288016e5778102a99 upstream.
It may happen that VF spawned for E610 adapter has problem with setting link up. This happens when ixgbevf supporting mailbox API 1.6 cooperates with PF driver which doesn't support this version of API, and hence doesn't support new approach for getting PF link data.
In that case VF asks PF to provide link data but as PF doesn't support it, returns -EOPNOTSUPP what leads to early bail from link configuration sequence.
Avoid such situation by using legacy VFLINKS approach whenever negotiated API version is less than 1.6.
To reproduce the issue just create VF and set its link up - adapter must be any from the E610 family, ixgbevf must support API 1.6 or higher while ixgbevf must not.
--- drivers/net/ethernet/intel/ixgbevf/vf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ixgbevf/vf.c +2 -1
@@ -852,7 +852,8 @@ static s32 ixgbevf_check_mac_link_vf(strif (!mac->get_link_status) goto out; -if (hw->mac.type == ixgbe_mac_e610_vf) { +if (hw->mac.type == ixgbe_mac_e610_vf && + hw->api_version >= ixgbe_mbox_api_16) { ret_val =ixgbevf_get_pf_link_state (hw, speed, link_up);if (ret_val) goto out;
Greg Kroah-Hartman
maintainerPATCH 248/378 mm: memfd_luo: always make all folios uptodate
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratyush Yadav (Google) <[email protected]>
commit 50d7b4332f27762d24641970fc34bb68a2621926 upstream.
Patch series "mm: memfd_luo: fixes for folio flag preservation".
This series contains a couple fixes for flag preservation for memfd live update.
The first patch fixes memfd preservation when fallocate() was used to pre-allocate some pages. For these memfds, all the writes to fallocated pages touched after preserve were lost.
The second patch fixes dirty flag tracking. If the dirty flag is not tracked correctly, the next kernel might incorrectly reclaim some folios under memory pressure, losing user data. This is a theoretical bug that I observed when reading the code, and haven't been able to reproduce it.
This patch (of 2):
When a folio is added to a shmem file via fallocate, it is not zeroed on allocation. This is done as a performance optimization since it is possible the folio will never end up being used at all. When the folio is used, shmem checks for the uptodate flag, and if absent, zeroes the folio (and sets the flag) before returning to user.
With LUO, the flags of each folio are saved at preserve time. It is possible to have a memfd with some folios fallocated but not uptodate. For those, the uptodate flag doesn't get saved. The folios might later end up being used and become uptodate. They would get passed to the next kernel via KHO correctly since they did get preserved. But they won't have the MEMFD_LUO_FOLIO_UPTODATE flag.
This means that when the memfd is retrieved, the folios will be added to the shmem file without the uptodate flag. They will be zeroed before first use, losing the data in those folios.
Since we take a big performance hit in allocating, zeroing, and pinning all folios at prepare time anyway, take some more and zero all non-uptodate ones too.
Later when there is a stronger need to make prepare faster, this can be optimized.
To avoid racing with another uptodate operation, take the folio lock.
--- mm/memfd_luo.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
mm/memfd_luo.c +23 -2
@@ -152,10 +152,31 @@ static int memfd_luo_preserve_folios(struct file *file,if (err) goto err_unpreserve; +folio_lock (folio); +if (folio_test_dirty (folio)) flags |=MEMFD_LUO_FOLIO_DIRTY ; -if (folio_test_uptodate (folio)) - flags |=MEMFD_LUO_FOLIO_UPTODATE ; + +/* +* If the folio is not uptodate, it was fallocated but never +* used. Saving this flag at prepare() doesn't work since it +* might change later when someone uses the folio. +* +* Since we have taken the performance penalty of allocating, +* zeroing, and pinning all the folios in the holes, take a bit +* more and zero all non-uptodate folios too. +* +* NOTE: For someone looking to improve preserve performance, +* this is a good place to look. +*/ +if (!folio_test_uptodate (folio)) { +folio_zero_range (folio,0 ,folio_size (folio)); +flush_dcache_folio (folio); +folio_mark_uptodate (folio); + } + flags |=MEMFD_LUO_FOLIO_UPTODATE ; + +folio_unlock (folio); pfolio->pfn =folio_pfn (folio); pfolio->flags = flags;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 249/378 mm: memfd_luo: always dirty all folios
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratyush Yadav (Google) <[email protected]>
commit 7e04bf1f33151a30e06a65b74b5f2c19fc2be128 upstream.
A dirty folio is one which has been written to. A clean folio is its opposite. Since a clean folio has no user data, it can be freed under memory pressure.
memfd preservation with LUO saves the flag at preserve(). This is problematic. The folio might get dirtied later. Saving it at freeze() also doesn't work, since the dirty bit from PTE is normally synced at unmap and there might still be mappings of the file at freeze().
To see why this is a problem, say a folio is clean at preserve, but gets dirtied later. The serialized state of the folio will mark it as clean. After retrieve, the next kernel will see the folio as clean and might try to reclaim it under memory pressure. This will result in losing user data.
Mark all folios of the file as dirty, and always set the MEMFD_LUO_FOLIO_DIRTY flag. This comes with the side effect of making all clean folios un-reclaimable. This is a cost that has to be paid for participants of live update. It is not expected to be a common use case to preserve a lot of clean folios anyway.
Since the value of pfolio->flags is a constant now, drop the flags variable and set it directly.
--- mm/memfd_luo.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-)
mm/memfd_luo.c +21 -5
@@ -146,7 +146,6 @@ static int memfd_luo_preserve_folios(struct file *file,for (i =0 ; i < nr_folios; i++) {struct memfd_luo_folio_ser *pfolio = &folios_ser[i];struct folio *folio = folios[i]; -unsigned int flags =0 ; err =kho_preserve_folio (folio);if (err)
@@ -154,8 +153,26 @@ static int memfd_luo_preserve_folios(struct file *file,folio_lock (folio); -if (folio_test_dirty (folio)) - flags |=MEMFD_LUO_FOLIO_DIRTY ; +/* +* A dirty folio is one which has been written to. A clean folio +* is its opposite. Since a clean folio does not carry user +* data, it can be freed by page reclaim under memory pressure. +* +* Saving the dirty flag at prepare() time doesn't work since it +* can change later. Saving it at freeze() also won't work +* because the dirty bit is normally synced at unmap and there +* might still be a mapping of the file at freeze(). +* +* To see why this is a problem, say a folio is clean at +* preserve, but gets dirtied later. The pfolio flags will mark +* it as clean. After retrieve, the next kernel might try to +* reclaim this folio under memory pressure, losing user data. +* +* Unconditionally mark it dirty to avoid this problem. This +* comes at the cost of making clean folios un-reclaimable after +* live update. +*/ +folio_mark_dirty (folio);/* * If the folio is not uptodate, it was fallocated but never
@@ -174,12 +191,11 @@ static int memfd_luo_preserve_folios(struct file *file,flush_dcache_folio (folio);folio_mark_uptodate (folio); } - flags |=MEMFD_LUO_FOLIO_UPTODATE ;folio_unlock (folio); pfolio->pfn =folio_pfn (folio); - pfolio->flags = flags; + pfolio->flags =MEMFD_LUO_FOLIO_DIRTY |MEMFD_LUO_FOLIO_UPTODATE ; pfolio->index = folio->index; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 250/378 mm/huge_memory: fix a folio_split() race condition with folio_try_get()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zi Yan <[email protected]>
commit 577a1f495fd78d8fb61b67ac3d3b595b01f6fcb0 upstream.
During a pagecache folio split, the values in the related xarray should not be changed from the original folio at xarray split time until all after-split folios are well formed and stored in the xarray. Current use of xas_try_split() in __split_unmapped_folio() lets some after-split folios show up at wrong indices in the xarray. When these misplaced after-split folios are unfrozen, before correct folios are stored via __xa_store(), and grabbed by folio_try_get(), they are returned to userspace at wrong file indices, causing data corruption. More detailed explanation is at the bottom.
The reproducer is at: https://github.com/dfinity/thp-madv-remove-test
It
1. creates a memfd,
2. forks,
3. in the child process, maps the file with large folios (via shmem code path) and reads the mapped file continuously with 16 threads,
4. in the parent process, uses madvise(MADV_REMOVE) to punch poles in the large folio.
Data corruption can be observed without the fix. Basically, data from a wrong page->index is returned.
Fix it by using the original folio in xas_try_split() calls, so that folio_try_get() can get the right after-split folios after the original folio is unfrozen.
Uniform split, split_huge_page*(), is not affected, since it uses xas_split_alloc() and xas_split() only once and stores the original folio in the xarray. Change xas_split() used in uniform split branch to use the original folio to avoid confusion.
Fixes below points to the commit introduces the code, but folio_split() is used in a later commit 7460b470a131f ("mm/truncate: use folio_split() in truncate operation").
More details:
For example, a folio f is split non-uniformly into f, f2, f3, f4 like below:
+----------------+---------+----+----+ | f | f2 | f3 | f4 | +----------------+---------+----+----+ but the xarray would look like below after __split_unmapped_folio() is done: +----------------+---------+----+----+ | f | f2 | f3 | f3 | +----------------+---------+----+----+
After __split_unmapped_folio(), the code changes the xarray and unfreezes after-split folios:
1. unfreezes f2, __xa_store(f2)
2. unfreezes f3, __xa_store(f3)
3. unfreezes f4, __xa_store(f4), which overwrites the second f3 to f4.
4. unfreezes f.
Meanwhile, a parallel filemap_get_entry() can read the second f3 from the xarray and use folio_try_get() on it at step 2 when f3 is unfrozen. Then, f3 is wrongly returned to user.
After the fix, the xarray looks like below after __split_unmapped_folio():
+----------------+---------+----+----+ | f | f | f | f | +----------------+---------+----+----+
so that the race window no longer exists.
--- mm/huge_memory.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
mm/huge_memory.c +9 -4
@@ -3631,6 +3631,7 @@ static int __split_unmapped_folio(structconst bool is_anon =folio_test_anon (folio);int old_order =folio_order (folio);int start_order = split_type ==SPLIT_TYPE_UNIFORM ? new_order : old_order -1 ; +struct folio *old_folio = folio;int split_order;/*
@@ -3651,12 +3652,16 @@ static int __split_unmapped_folio(struct* uniform split has xas_split_alloc() called before * irq is disabled to allocate enough memory, whereas * non-uniform split can handle ENOMEM. +* Use the to-be-split folio, so that a parallel +* folio_try_get() waits on it until xarray is updated +* with after-split folios and the original one is +* unfrozen. */ -if (split_type ==SPLIT_TYPE_UNIFORM ) -xas_split (xas, folio, old_order); -else { +if (split_type ==SPLIT_TYPE_UNIFORM ) { +xas_split (xas, old_folio, old_order); + }else {xas_set_order (xas, folio->index, split_order); -xas_try_split (xas, folio, old_order); +xas_try_split (xas, old_folio, old_order);if (xas_error (xas))return xas_error (xas); }
Greg Kroah-Hartman
maintainerPATCH 251/378 mm/damon/core: clear walk_control on inactive context in damos_walk()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raul Pazemecxas De Andrade <[email protected]>
commit d210fdcac9c0d1380eab448aebc93f602c1cd4e6 upstream.
damos_walk() sets ctx->walk_control to the caller-provided control structure before checking whether the context is running. If the context is inactive (damon_is_running() returns false), the function returns -EINVAL without clearing ctx->walk_control. This leaves a dangling pointer to a stack-allocated structure that will be freed when the caller returns.
This is structurally identical to the bug fixed in commit f9132fbc2e83 ("mm/damon/core: remove call_control in inactive contexts") for damon_call(), which had the same pattern of linking a control object and returning an error without unlinking it.
The dangling walk_control pointer can cause:
1. Use-after-free if the context is later started and kdamond dereferences ctx->walk_control (e.g., in damos_walk_cancel() which writes to control->canceled and calls complete())
2. Permanent -EBUSY from subsequent damos_walk() calls, since the stale pointer is non-NULL
Nonetheless, the real user impact is quite restrictive. The use-after-free is impossible because there is no damos_walk() callers who starts the context later. The permanent -EBUSY can actually confuse users, as DAMON is not running. But the symptom is kept only while the context is turned off. Turning it on again will make DAMON internally uses a newly generated damon_ctx object that doesn't have the invalid damos_walk_control pointer, so everything will work fine again.
Fix this by clearing ctx->walk_control under walk_control_lock before returning -EINVAL, mirroring the fix pattern from f9132fbc2e83.
--- mm/damon/core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
mm/damon/core.c +6 -1
@@ -1531,8 +1531,13 @@ int damos_walk(struct damon_ctx *ctx, st } ctx->walk_control = control;mutex_unlock (&ctx->walk_control_lock); -if (!damon_is_running (ctx)) +if (!damon_is_running (ctx)) { +mutex_lock (&ctx->walk_control_lock); +if (ctx->walk_control == control) + ctx->walk_control =NULL ; +mutex_unlock (&ctx->walk_control_lock);return -EINVAL ; + }wait_for_completion (&control->completion);if (control->canceled)return -ECANCELED ;
Greg Kroah-Hartman
maintainerPATCH 252/378 mm/slab: fix an incorrect check in obj_exts_alloc_size()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Yoo <[email protected]>
commit 8dafa9f5900c4855a65dbfee51e3bd00636deee1 upstream.
obj_exts_alloc_size() prevents recursive allocation of slabobj_ext array from the same cache, to avoid creating slabs that are never freed.
There is one mistake that returns the original size when memory allocation profiling is disabled. The assumption was that memcg-triggered slabobj_ext allocation is always served from KMALLOC_CGROUP type. But this is wrong [1]: when the caller specifies both __GFP_RECLAIMABLE and __GFP_ACCOUNT with SLUB_TINY enabled, the allocation is served from normal kmalloc. This is because kmalloc_type() prioritizes __GFP_RECLAIMABLE over __GFP_ACCOUNT, and SLUB_TINY aliases KMALLOC_RECLAIM with KMALLOC_NORMAL.
As a result, the recursion guard is bypassed and the problematic slabs can be created. Fix this by removing the mem_alloc_profiling_enabled() check entirely. The remaining is_kmalloc_normal() check is still sufficient to detect whether the cache is of KMALLOC_NORMAL type and avoid bumping the size if it's not.
Without SLUB_TINY, no functional change intended.
With SLUB_TINY, allocations with __GFP_ACCOUNT|__GFP_RECLAIMABLE now allocate a larger array if the sizes equal.
--- mm/slub.c | 7 ------- 1 file changed, 7 deletions(-)
mm/slub.c +0 -7
@@ -2113,13 +2113,6 @@ static inline size_t obj_exts_alloc_sizesize_t sz =sizeof (struct slabobj_ext ) * slab->objects;struct kmem_cache *obj_exts_cache; -/* -* slabobj_ext array for KMALLOC_CGROUP allocations -* are served from KMALLOC_NORMAL caches. -*/ -if (!mem_alloc_profiling_enabled ()) -return sz; -if (sz >KMALLOC_MAX_CACHE_SIZE )return sz;
Greg Kroah-Hartman
maintainerPATCH 253/378 staging: sm750fb: add missing pci_release_region on error and removal
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Artem Lytkin <[email protected]>
commit 8225489ddb900656cc21573b4e1b00c9181fd777 upstream.
hw_sm750_map() calls pci_request_region() but never releases the region on error paths or in lynxfb_pci_remove(). This causes a resource leak that prevents the PCI region from being mapped again after driver removal or a failed probe. A TODO comment in the code acknowledges this missing cleanup.
Restructure the error handling in hw_sm750_map() to properly release the PCI region on ioremap failures, and add pci_release_region() to lynxfb_pci_remove().
--- drivers/staging/sm750fb/sm750.c | 1 + drivers/staging/sm750fb/sm750_hw.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-)
drivers/staging/sm750fb/sm750.c +1 -0
@@ -1123,6 +1123,7 @@ static void lynxfb_pci_remove(struct pciiounmap (sm750_dev->pvReg);iounmap (sm750_dev->pvMem); +pci_release_region (pdev,1 );kfree (g_settings); }
drivers/staging/sm750fb/sm750_hw.c +11 -11
@@ -36,16 +36,11 @@ int hw_sm750_map(struct sm750_dev *sm750pr_info ("mmio phyAddr = %lx\n" , sm750_dev->vidreg_start); -/* -* reserve the vidreg space of smi adaptor -* if you do this, you need to add release region code -* in lynxfb_remove, or memory will not be mapped again -* successfully -*/ +/* reserve the vidreg space of smi adaptor */ ret =pci_request_region (pdev,1 ,"sm750fb" );if (ret) {pr_err ("Can not request PCI regions.\n" ); - goto exit; +return ret; }/* now map mmio and vidmem */
@@ -54,7 +49,7 @@ int hw_sm750_map(struct sm750_dev *sm750if (!sm750_dev->pvReg) {pr_err ("mmio failed\n" ); ret = -EFAULT ; - goto exit; + goto err_release_region; }pr_info ("mmio virtual addr = %p\n" , sm750_dev->pvReg);
@@ -79,13 +74,18 @@ int hw_sm750_map(struct sm750_dev *sm750 sm750_dev->pvMem =ioremap_wc (sm750_dev->vidmem_start, sm750_dev->vidmem_size);if (!sm750_dev->pvMem) { -iounmap (sm750_dev->pvReg);pr_err ("Map video memory failed\n" ); ret = -EFAULT ; - goto exit; + goto err_unmap_reg; }pr_info ("video memory vaddr = %p\n" , sm750_dev->pvMem); -exit: + +return 0 ; + +err_unmap_reg: +iounmap (sm750_dev->pvReg); +err_release_region: +pci_release_region (pdev,1 );return ret; }
Greg Kroah-Hartman
maintainerPATCH 254/378 staging: rtl8723bs: properly validate the data in rtw_get_ie_ex()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit f0109b9d3e1e455429279d602f6276e34689750a upstream.
Just like in commit 154828bf9559 ("staging: rtl8723bs: fix out-of-bounds read in rtw_get_ie() parser"), we don't trust the data in the frame so we should check the length better before acting on it
--- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +10 -5
@@ -185,20 +185,25 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len cnt =0 ; -while (cnt < in_len) { +while (cnt +2 <= in_len) { +u8 ie_len = in_ie[cnt +1 ]; + +if (cnt +2 + ie_len > in_len) +break ; +if (eid == in_ie[cnt] - && (!oui || !memcmp (&in_ie[cnt+2 ], oui, oui_len))) { + && (!oui || (ie_len >= oui_len && !memcmp (&in_ie[cnt +2 ], oui, oui_len)))) { target_ie = &in_ie[cnt];if (ie) -memcpy (ie, &in_ie[cnt], in_ie[cnt+1 ]+2 ); +memcpy (ie, &in_ie[cnt], ie_len +2 );if (ielen) - *ielen = in_ie[cnt+1 ]+2 ; + *ielen = ie_len +2 ;break ; } - cnt += in_ie[cnt+1 ]+2 ;/* goto next */ + cnt += ie_len +2 ;/* goto next */ }return target_ie;
Greg Kroah-Hartman
maintainerPATCH 255/378 staging: rtl8723bs: fix potential out-of-bounds read in rtw_restruct_wmm_ie
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luka Gejak <[email protected]>
commit a75281626fc8fa6dc6c9cc314ee423e8bc45203b upstream.
The current code checks 'i + 5 < in_len' at the end of the if statement. However, it accesses 'in_ie[i + 5]' before that check, which can lead to an out-of-bounds read. Move the length check to the beginning of the conditional to ensure the index is within bounds before accessing the array.
--- drivers/staging/rtl8723bs/core/rtw_mlme.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/staging/rtl8723bs/core/rtw_mlme.c +4 -1
@@ -2002,7 +2002,10 @@ int rtw_restruct_wmm_ie(struct adapter *while (i < in_len) { ielength = initial_out_len; -if (in_ie[i] ==0xDD && in_ie[i+2 ] ==0x00 && in_ie[i+3 ] ==0x50 && in_ie[i+4 ] ==0xF2 && in_ie[i+5 ] ==0x02 && i+5 < in_len) {/* WMM element ID and OUI */ +if (i +5 < in_len && + in_ie[i] ==0xDD && in_ie[i +2 ] ==0x00 && + in_ie[i +3 ] ==0x50 && in_ie[i +4 ] ==0xF2 && + in_ie[i +5 ] ==0x02 ) {for (j = i; j < i +9 ; j++) { out_ie[ielength] = in_ie[j]; ielength++;
Greg Kroah-Hartman
maintainerPATCH 256/378 pinctrl: cy8c95x0: Dont miss reading the last bank registers
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit b6c3af46c26f2d07c10a1452adc34b821719327e upstream.
When code had been changed to use for_each_set_clump8(), it mistakenly switched from chip->nport to chip->tpin since the cy8c9540 and cy8c9560 have a 4-pin gap. This, in particular, led to the missed read of the last bank interrupt status register and hence missing interrupts on those pins. Restore the upper limit in for_each_set_clump8() to take into consideration that gap.
--- drivers/pinctrl/pinctrl-cy8c95x0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pinctrl/pinctrl-cy8c95x0.c +2 -2
@@ -627,7 +627,7 @@ static int cy8c95x0_write_regs_mask(strubitmap_scatter (tmask, mask, chip->map,MAX_LINE );bitmap_scatter (tval, val, chip->map,MAX_LINE ); -for_each_set_clump8 (offset, bits, tmask, chip->tpin) { +for_each_set_clump8 (offset, bits, tmask, chip->nport *BANK_SZ ) {unsigned int i = offset /8 ; write_val =bitmap_get_value8 (tval, offset);
@@ -655,7 +655,7 @@ static int cy8c95x0_read_regs_mask(strucbitmap_scatter (tmask, mask, chip->map,MAX_LINE );bitmap_scatter (tval, val, chip->map,MAX_LINE ); -for_each_set_clump8 (offset, bits, tmask, chip->tpin) { +for_each_set_clump8 (offset, bits, tmask, chip->nport *BANK_SZ ) {unsigned int i = offset /8 ; ret =cy8c95x0_regmap_read_bits (chip, reg, i, bits, &read_val);
Greg Kroah-Hartman
maintainerPATCH 257/378 selftests: fix mntns iteration selftests
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 4c7b2ec23cc5d880e3ffe35e8c2aad686b67723a upstream.
Now that we changed permission checking make sure that we reflect that in the selftests.
--- tools/testing/selftests/filesystems/nsfs/iterate_mntns.c | 25 +++++++++------ 1 file changed, 15 insertions(+), 10 deletions(-)
tools/testing/selftests/filesystems/nsfs/iterate_mntns.c +15 -10
@@ -37,17 +37,20 @@ FIXTURE(iterate_mount_namespaces) {__u64 mnt_ns_id[MNT_NS_COUNT ]; }; +static inline bool mntns_in_list (__u64 *mnt_ns_id,struct mnt_ns_info *info) +{ +for (int i =0 ; i <MNT_NS_COUNT ; i++) { +if (mnt_ns_id[i] == info->mnt_ns_id) +return true; + } +return false; +} +FIXTURE_SETUP (iterate_mount_namespaces) {for (int i =0 ; i <MNT_NS_COUNT ; i++) self->fd_mnt_ns[i] = -EBADF ; -/* -* Creating a new user namespace let's us guarantee that we only see -* mount namespaces that we did actually create. -*/ -ASSERT_EQ (unshare (CLONE_NEWUSER ),0 ); -for (int i =0 ; i <MNT_NS_COUNT ; i++) {struct mnt_ns_info info = {};
@@ -75,13 +78,15 @@ TEST_F(iterate_mount_namespaces, iterate fd_mnt_ns_cur =fcntl (self->fd_mnt_ns[0 ],F_DUPFD_CLOEXEC );ASSERT_GE (fd_mnt_ns_cur,0 ); -for (;; count++) { +for (;;) {struct mnt_ns_info info = {};int fd_mnt_ns_next; fd_mnt_ns_next =ioctl (fd_mnt_ns_cur,NS_MNT_GET_NEXT , &info);if (fd_mnt_ns_next <0 && errno ==ENOENT )break ; +if (mntns_in_list (self->mnt_ns_id, &info)) + count++;ASSERT_GE (fd_mnt_ns_next,0 );ASSERT_EQ (close (fd_mnt_ns_cur),0 ); fd_mnt_ns_cur = fd_mnt_ns_next;
@@ -96,13 +101,15 @@ TEST_F(iterate_mount_namespaces, iterate fd_mnt_ns_cur =fcntl (self->fd_mnt_ns[MNT_NS_LAST_INDEX ],F_DUPFD_CLOEXEC );ASSERT_GE (fd_mnt_ns_cur,0 ); -for (;; count++) { +for (;;) {struct mnt_ns_info info = {};int fd_mnt_ns_prev; fd_mnt_ns_prev =ioctl (fd_mnt_ns_cur,NS_MNT_GET_PREV , &info);if (fd_mnt_ns_prev <0 && errno ==ENOENT )break ; +if (mntns_in_list (self->mnt_ns_id, &info)) + count++;ASSERT_GE (fd_mnt_ns_prev,0 );ASSERT_EQ (close (fd_mnt_ns_cur),0 ); fd_mnt_ns_cur = fd_mnt_ns_prev;
@@ -125,7 +132,6 @@ TEST_F(iterate_mount_namespaces, iterateASSERT_GE (fd_mnt_ns_next,0 );ASSERT_EQ (close (fd_mnt_ns_cur),0 ); fd_mnt_ns_cur = fd_mnt_ns_next; -ASSERT_EQ (info.mnt_ns_id, self->mnt_ns_id[i]); } }
@@ -144,7 +150,6 @@ TEST_F(iterate_mount_namespaces, iterateASSERT_GE (fd_mnt_ns_prev,0 );ASSERT_EQ (close (fd_mnt_ns_cur),0 ); fd_mnt_ns_cur = fd_mnt_ns_prev; -ASSERT_EQ (info.mnt_ns_id, self->mnt_ns_id[i]); } }
Greg Kroah-Hartman
maintainerPATCH 258/378 media: dvb-net: fix OOB access in ULE extension header tables
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ariel Silver <[email protected]>
commit 24d87712727a5017ad142d63940589a36cd25647 upstream.
The ule_mandatory_ext_handlers[] and ule_optional_ext_handlers[] tables in handle_one_ule_extension() are declared with 255 elements (valid indices 0-254), but the index htype is derived from network-controlled data as (ule_sndu_type & 0x00FF), giving a range of 0-255. When htype equals 255, an out-of-bounds read occurs on the function pointer table, and the OOB value may be called as a function pointer.
Add a bounds check on htype against the array size before either table is accessed. Out-of-range values now cause the SNDU to be discarded.
--- drivers/media/dvb-core/dvb_net.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/media/dvb-core/dvb_net.c +3 -0
@@ -228,6 +228,9 @@ static int handle_one_ule_extension( strunsigned char hlen = (p->ule_sndu_type &0x0700 ) >>8 ;unsigned char htype = p->ule_sndu_type &0x00FF ; +if (htype >=ARRAY_SIZE (ule_mandatory_ext_handlers)) +return -1 ; +/* Discriminate mandatory and optional extension headers. */ if (hlen ==0 ) {/* Mandatory extension header */
Greg Kroah-Hartman
maintainerPATCH 259/378 net: mana: Ring doorbell at 4 CQ wraparounds
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
commit dabffd08545ffa1d7183bc45e387860984025291 upstream.
MANA hardware requires at least one doorbell ring every 8 wraparounds of the CQ. The driver rings the doorbell as a form of flow control to inform hardware that CQEs have been consumed.
The NAPI poll functions mana_poll_tx_cq() and mana_poll_rx_cq() can poll up to CQE_POLLING_BUFFER (512) completions per call. If the CQ has fewer than 512 entries, a single poll call can process more than 4 wraparounds without ringing the doorbell. The doorbell threshold check also uses ">" instead of ">=", delaying the ring by one extra CQE beyond 4 wraparounds. Combined, these issues can cause the driver to exceed the 8-wraparound hardware limit, leading to missed completions and stalled queues.
Fix this by capping the number of CQEs polled per call to 4 wraparounds of the CQ in both TX and RX paths. Also change the doorbell threshold from ">" to ">=" so the doorbell is rung as soon as 4 wraparounds are reached.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +18 -5
@@ -1725,8 +1725,14 @@ static void mana_poll_tx_cq(struct mana_ ndev = txq->ndev; apc =netdev_priv (ndev); +/* Limit CQEs polled to 4 wraparounds of the CQ to ensure the +* doorbell can be rung in time for the hardware's requirement +* of at least one doorbell ring every 8 wraparounds. +*/ comp_read =mana_gd_poll_cq (cq->gdma_cq, completions, -CQE_POLLING_BUFFER ); +min ((cq->gdma_cq->queue_size / +COMP_ENTRY_SIZE ) *4 , +CQE_POLLING_BUFFER ));if (comp_read <1 )return ;
@@ -2111,7 +2117,14 @@ static void mana_poll_rx_cq(struct mana_struct mana_rxq *rxq = cq->rxq;int comp_read, i; - comp_read =mana_gd_poll_cq (cq->gdma_cq, comp,CQE_POLLING_BUFFER ); +/* Limit CQEs polled to 4 wraparounds of the CQ to ensure the +* doorbell can be rung in time for the hardware's requirement +* of at least one doorbell ring every 8 wraparounds. +*/ + comp_read =mana_gd_poll_cq (cq->gdma_cq, comp, +min ((cq->gdma_cq->queue_size / +COMP_ENTRY_SIZE ) *4 , +CQE_POLLING_BUFFER ));WARN_ON_ONCE (comp_read >CQE_POLLING_BUFFER ); rxq->xdp_flush = false;
@@ -2156,11 +2169,11 @@ static int mana_cq_handler(void *contextmana_gd_ring_cq (gdma_queue,SET_ARM_BIT ); cq->work_done_since_doorbell =0 ;napi_complete_done (&cq->napi, w); - }else if (cq->work_done_since_doorbell > - cq->gdma_cq->queue_size /COMP_ENTRY_SIZE *4 ) { + }else if (cq->work_done_since_doorbell >= + (cq->gdma_cq->queue_size /COMP_ENTRY_SIZE ) *4 ) {/* MANA hardware requires at least one doorbell ring every 8 * wraparounds of CQ even if there is no need to arm the CQ. -* This driver rings the doorbell as soon as we have exceeded +* This driver rings the doorbell as soon as it has processed * 4 wraparounds. */ mana_gd_ring_cq (gdma_queue,0 );
Greg Kroah-Hartman
maintainerPATCH 260/378 net: Fix rcu_tasks stall in threaded busypoll
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: YiFei Zhu <[email protected]>
commit 1a86a1f7d88996085934139fa4c063b6299a2dd3 upstream.
I was debugging a NIC driver when I noticed that when I enable threaded busypoll, bpftrace hangs when starting up. dmesg showed:
rcu_tasks_wait_gp: rcu_tasks grace period number 85 (since boot) is 10658 jiffies old.
rcu_tasks_wait_gp: rcu_tasks grace period number 85 (since boot) is 40793 jiffies old.
rcu_tasks_wait_gp: rcu_tasks grace period number 85 (since boot) is 131273 jiffies old.
rcu_tasks_wait_gp: rcu_tasks grace period number 85 (since boot) is 402058 jiffies old.
INFO: rcu_tasks detected stalls on tasks: 00000000769f52cd: .N nvcsw: 2/2 holdout: 1 idle_cpu: -1/64 task:napi/eth2-8265 state:R running task stack:0 pid:48300 tgid:48300 ppid:2 task_flags:0x208040 flags:0x00004000 Call Trace: <TASK> ? napi_threaded_poll_loop+0x27c/0x2c0 ? __pfx_napi_threaded_poll+0x10/0x10 ? napi_threaded_poll+0x26/0x80 ? kthread+0xfa/0x240 ? __pfx_kthread+0x10/0x10 ? ret_from_fork+0x31/0x50 ? __pfx_kthread+0x10/0x10 ? ret_from_fork_asm+0x1a/0x30 </TASK>
The cause is that in threaded busypoll, the main loop is in napi_threaded_poll rather than napi_threaded_poll_loop, where the latter rarely iterates more than once within its loop. For rcu_softirq_qs_periodic inside napi_threaded_poll_loop to report its qs state, the last_qs must be 100ms behind, and this can't happen because napi_threaded_poll_loop rarely iterates in threaded busypoll, and each time napi_threaded_poll_loop is called last_qs is reset to latest jiffies.
This patch changes so that in threaded busypoll, last_qs is saved in the outer napi_threaded_poll, and whether busy_poll_last_qs is NULL indicates whether napi_threaded_poll_loop is called for busypoll. This way last_qs would not reset to latest jiffies on each invocation of napi_threaded_poll_loop.
--- net/core/dev.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
net/core/dev.c +11 -6
@@ -7788,11 +7788,12 @@ static int napi_thread_wait(struct napi_return -1 ; } -static void napi_threaded_poll_loop (struct napi_struct *napi,bool busy_poll) +static void napi_threaded_poll_loop (struct napi_struct *napi, +unsigned long *busy_poll_last_qs) { +unsigned long last_qs = busy_poll_last_qs ? *busy_poll_last_qs : jiffies;struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;struct softnet_data *sd; -unsigned long last_qs = jiffies;for (;;) {bool repoll = false;
@@ -7821,12 +7822,12 @@ static void napi_threaded_poll_loop(stru/* When busy poll is enabled, the old packets are not flushed in * napi_complete_done. So flush them here. */ -if (busy_poll) +if (busy_poll_last_qs)gro_flush_normal (&napi->gro,HZ >=1000 );local_bh_enable ();/* Call cond_resched here to avoid watchdog warnings. */ -if (repoll || busy_poll) { +if (repoll || busy_poll_last_qs) {rcu_softirq_qs_periodic (last_qs);cond_resched (); }
@@ -7834,11 +7835,15 @@ static void napi_threaded_poll_loop(struif (!repoll)break ; } + +if (busy_poll_last_qs) + *busy_poll_last_qs = last_qs; }static int napi_threaded_poll (void *data) {struct napi_struct *napi = data; +unsigned long last_qs = jiffies;bool want_busy_poll;bool in_busy_poll;unsigned long val;
@@ -7856,7 +7861,7 @@ static int napi_threaded_poll(void *dataassign_bit (NAPI_STATE_IN_BUSY_POLL , &napi->state, want_busy_poll); -napi_threaded_poll_loop (napi, want_busy_poll); +napi_threaded_poll_loop (napi, want_busy_poll ? &last_qs :NULL ); }return 0 ;
@@ -13167,7 +13172,7 @@ static void run_backlog_napi(unsigned in {struct softnet_data *sd =per_cpu_ptr (&softnet_data, cpu); -napi_threaded_poll_loop (&sd->backlog, false); +napi_threaded_poll_loop (&sd->backlog,NULL ); }static void backlog_napi_setup (unsigned int cpu)
Greg Kroah-Hartman
maintainerPATCH 261/378 ice: fix retry for AQ command 0x06EE
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Staniszewski <[email protected]>
commit fb4903b3354aed4a2301180cf991226f896c87ed upstream.
Executing ethtool -m can fail reporting a netlink I/O error while firmware link management holds the i2c bus used to communicate with the module.
According to Intel(R) Ethernet Controller E810 Datasheet Rev 2.8 [1] Section 3.3.10.4 Read/Write SFF EEPROM (0x06EE)
request should to be retried upon receiving EBUSY from firmware.
Commit e9c9692c8a81 ("ice: Reimplement module reads used by ethtool") implemented it only for part of ice_get_module_eeprom(), leaving all other calls to ice_aq_sff_eeprom() vulnerable to returning early on getting EBUSY without retrying.
Remove the retry loop from ice_get_module_eeprom() and add Admin Queue (AQ) command with opcode 0x06EE to the list of commands that should be retried on receiving EBUSY from firmware.
--- drivers/net/ethernet/intel/ice/ice_common.c | 1 drivers/net/ethernet/intel/ice/ice_ethtool.c | 35 ++++++++++----------------- 2 files changed, 15 insertions(+), 21 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +1 -0
@@ -1854,6 +1854,7 @@ static bool ice_should_retry_sq_send_cmdcase ice_aqc_opc_lldp_stop:case ice_aqc_opc_lldp_start:case ice_aqc_opc_lldp_filter_ctrl: +case ice_aqc_opc_sff_eeprom:return true; }
drivers/net/ethernet/intel/ice/ice_ethtool.c +14 -21
@@ -4508,7 +4508,7 @@ ice_get_module_eeprom(struct net_deviceu8 addr =ICE_I2C_EEPROM_DEV_ADDR ;struct ice_hw *hw = &pf->hw;bool is_sfp = false; -unsigned int i, j; +unsigned int i;u16 offset =0 ;u8 page =0 ;int status;
@@ -4550,26 +4550,19 @@ ice_get_module_eeprom(struct net_deviceif (page ==0 || !(data[0x2 ] &0x4 )) {u32 copy_len; -/* If i2c bus is busy due to slow page change or -* link management access, call can fail. This is normal. -* So we retry this a few times. -*/ -for (j =0 ; j <4 ; j++) { - status =ice_aq_sff_eeprom (hw,0 , addr, offset, page, - !is_sfp, value, -SFF_READ_BLOCK_SIZE , -0 ,NULL ); -netdev_dbg (netdev,"SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n" , - addr, offset, page, is_sfp, - value[0 ], value[1 ], value[2 ], value[3 ], - value[4 ], value[5 ], value[6 ], value[7 ], - status); -if (status) { -usleep_range (1500 ,2500 ); -memset (value,0 ,SFF_READ_BLOCK_SIZE ); -continue ; - } -break ; + status =ice_aq_sff_eeprom (hw,0 , addr, offset, page, + !is_sfp, value, +SFF_READ_BLOCK_SIZE , +0 ,NULL ); +netdev_dbg (netdev,"SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%pe)\n" , + addr, offset, page, is_sfp, + value[0 ], value[1 ], value[2 ], value[3 ], + value[4 ], value[5 ], value[6 ], value[7 ], +ERR_PTR (status)); +if (status) { +netdev_err (netdev,"%s: error reading module EEPROM: status %pe\n" , + __func__,ERR_PTR (status)); +return status; }/* Make sure we have enough room for the new block */
Greg Kroah-Hartman
maintainerPATCH 262/378 fgraph: Fix thresh_return clear per-task notrace
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengming Hu <[email protected]>
commit 6ca8379b5d36e22b04e6315c3e49a6083377c862 upstream.
When tracing_thresh is enabled, function graph tracing uses trace_graph_thresh_return() as the return handler. Unlike trace_graph_return(), it did not clear the per-task TRACE_GRAPH_NOTRACE flag set by the entry handler for set_graph_notrace addresses. This could leave the task permanently in "notrace" state and effectively disable function graph tracing for that task.
Mirror trace_graph_return()'s per-task notrace handling by clearing TRACE_GRAPH_NOTRACE and returning early when set.
--- kernel/trace/trace_functions_graph.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/trace/trace_functions_graph.c +3 -2
@@ -400,14 +400,15 @@ static void trace_graph_thresh_return(ststruct fgraph_ops *gops, struct ftrace_regs *fregs) { + unsigned long *task_var = fgraph_get_task_var(gops);struct fgraph_times *ftimes;struct trace_array *tr;int size;ftrace_graph_addr_finish (gops, trace); -if (trace_recursion_test (TRACE_GRAPH_NOTRACE_BIT )) { -trace_recursion_clear (TRACE_GRAPH_NOTRACE_BIT ); +if (*task_var &TRACE_GRAPH_NOTRACE ) { + *task_var &= ~TRACE_GRAPH_NOTRACE ;return ; }
Greg Kroah-Hartman
maintainerPATCH 263/378 tracing: Fix syscall events activation by ensuring refcount hits zero
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
commit 0a663b764dbdf135a126284f454c9f01f95a87d4 upstream.
When multiple syscall events are specified in the kernel command line (e.g., trace_event=syscalls:sys_enter_openat,syscalls:sys_enter_close), they are often not captured after boot, even though they appear enabled in the tracing/set_event file.
The issue stems from how syscall events are initialized. Syscall tracepoints require the global reference count (sys_tracepoint_refcount) to transition from 0 to 1 to trigger the registration of the syscall work (TIF_SYSCALL_TRACEPOINT) for tasks, including the init process (pid 1).
The current implementation of early_enable_events() with disable_first=true used an interleaved sequence of "Disable A -> Enable A -> Disable B -> Enable B". If multiple syscalls are enabled, the refcount never drops to zero, preventing the 0->1 transition that triggers actual registration.
Fix this by splitting early_enable_events() into two distinct phases:
1. Disable all events specified in the buffer.
2. Enable all events specified in the buffer.
This ensures the refcount hits zero before re-enabling, allowing syscall events to be properly activated during early boot.
The code is also refactored to use a helper function to avoid logic duplication between the disable and enable phases.
--- kernel/trace/trace_events.c | 52 +++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-)
kernel/trace/trace_events.c +37 -15
@@ -4512,26 +4512,22 @@ static __init int event_trace_memsetup(vreturn 0 ; } -__init void -early_enable_events (struct trace_array *tr,char *buf,bool disable_first) +/* +* Helper function to enable or disable a comma-separated list of events +* from the bootup buffer. +*/ +static __init void __early_set_events (struct trace_array *tr,char *buf,bool enable) {char *token; -int ret; - -while (true) { - token =strsep (&buf,"," ); - -if (!token) -break ; +while ((token =strsep (&buf,"," ))) {if (*token) { -/* Restarting syscalls requires that we stop them first */ -if (disable_first) +if (enable) { +if (ftrace_set_clr_event (tr, token,1 )) +pr_warn ("Failed to enable trace event: %s\n" , token); + }else {ftrace_set_clr_event (tr, token,0 ); - - ret =ftrace_set_clr_event (tr, token,1 ); -if (ret) -pr_warn ("Failed to enable trace event: %s\n" , token); + } }/* Put back the comma to allow this to be called again */
@@ -4540,6 +4536,32 @@ early_enable_events(struct trace_array * } } +/** +* early_enable_events - enable events from the bootup buffer +* @tr: The trace array to enable the events in +* @buf: The buffer containing the comma separated list of events +* @disable_first: If true, disable all events in @buf before enabling them +* +* This function enables events from the bootup buffer. If @disable_first +* is true, it will first disable all events in the buffer before enabling +* them. +* +* For syscall events, which rely on a global refcount to register the +* SYSCALL_WORK_SYSCALL_TRACEPOINT flag (especially for pid 1), we must +* ensure the refcount hits zero before re-enabling them. A simple +* "disable then enable" per-event is not enough if multiple syscalls are +* used, as the refcount will stay above zero. Thus, we need a two-phase +* approach: disable all, then enable all. +*/ +__init void +early_enable_events (struct trace_array *tr,char *buf,bool disable_first) +{ +if (disable_first) +__early_set_events (tr, buf, false); + +__early_set_events (tr, buf, true); +} +static __init int event_trace_enable (void ) {struct trace_array *tr =top_trace_array ();
Greg Kroah-Hartman
maintainerPATCH 264/378 net/tcp-ao: Fix MAC comparison to be constant-time
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 67edfec516d30d3e62925c397be4a1e5185802fc upstream.
To prevent timing attacks, MACs need to be compared in constant time. Use the appropriate helper function for this.
--- net/ipv4/Kconfig | 1 + net/ipv4/tcp_ao.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
net/ipv4/Kconfig +1 -0
@@ -748,6 +748,7 @@ config TCP_SIGPOOL config TCP_AO bool "TCP: Authentication Option (RFC5925)" select CRYPTO + select CRYPTO_LIB_UTILS select TCP_SIGPOOL depends on 64BIT && IPV6 != m # seq-number extension needs WRITE_ONCE(u64) help
net/ipv4/tcp_ao.c +2 -1
@@ -10,6 +10,7 @@#define pr_fmt (fmt) "TCP: " fmt#include <crypto/hash.h> +#include <crypto/utils.h> #include <linux/inetdevice.h> #include <linux/tcp.h>
@@ -922,7 +923,7 @@ tcp_ao_verify_hash(const struct sock *sk/* XXX: make it per-AF callback? */ tcp_ao_hash_skb (family, hash_buf, key, sk, skb, traffic_key, (phash - (u8 *)th), sne); -if (memcmp (phash, hash_buf, maclen)) { +if (crypto_memneq (phash, hash_buf, maclen)) {NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPAOBAD );atomic64_inc (&info->counters.pkt_bad);atomic64_inc (&key->pkt_bad);
Greg Kroah-Hartman
maintainerPATCH 265/378 fgraph: Fix thresh_return nosleeptime double-adjust
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengming Hu <[email protected]>
commit b96d0c59cdbb2a22b2545f6f3d5c6276b05761dd upstream.
trace_graph_thresh_return() called handle_nosleeptime() and then delegated to trace_graph_return(), which calls handle_nosleeptime() again. When sleep-time accounting is disabled this double-adjusts calltime and can produce bogus durations (including underflow).
Fix this by computing rettime once, applying handle_nosleeptime() only once, using the adjusted calltime for threshold comparison, and writing the return event directly via __trace_graph_return() when the threshold is met.
--- kernel/trace/trace_functions_graph.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
kernel/trace/trace_functions_graph.c +10 -4
@@ -403,8 +403,12 @@ static void trace_graph_thresh_return(stunsigned long *task_var =fgraph_get_task_var (gops);struct fgraph_times *ftimes;struct trace_array *tr; +unsigned int trace_ctx; +u64 calltime, rettime;int size; + rettime =trace_clock_local (); +ftrace_graph_addr_finish (gops, trace);if (*task_var &TRACE_GRAPH_NOTRACE ) {
@@ -419,11 +423,13 @@ static void trace_graph_thresh_return(st tr = gops->private;handle_nosleeptime (tr, trace, ftimes, size); -if (tracing_thresh && - (trace_clock_local () - ftimes->calltime < tracing_thresh)) + calltime = ftimes->calltime; + +if (tracing_thresh && (rettime - calltime < tracing_thresh))return ; -else -trace_graph_return (trace, gops, fregs); + + trace_ctx =tracing_gen_ctx (); +__trace_graph_return (tr, trace, trace_ctx, calltime, rettime); }static struct fgraph_ops funcgraph_ops = {
Greg Kroah-Hartman
maintainerPATCH 266/378 net/tcp-md5: Fix MAC comparison to be constant-time
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 46d0d6f50dab706637f4c18a470aac20a21900d3 upstream.
To prevent timing attacks, MACs need to be compared in constant time. Use the appropriate helper function for this.
--- net/ipv4/Kconfig | 1 + net/ipv4/tcp.c | 3 ++- net/ipv4/tcp_ipv4.c | 3 ++- net/ipv6/tcp_ipv6.c | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-)
net/ipv4/Kconfig +1 -0
@@ -762,6 +762,7 @@ config TCP_AO config TCP_MD5SIG bool "TCP: MD5 Signature Option support (RFC2385)" select CRYPTO_LIB_MD5 + select CRYPTO_LIB_UTILS help RFC2385 specifies a method of giving MD5 protection to TCP sessions. Its main (only?) use is to protect BGP sessions between core routers
net/ipv4/tcp.c +2 -1
@@ -244,6 +244,7 @@#define pr_fmt (fmt) "TCP: " fmt#include <crypto/md5.h> +#include <crypto/utils.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h>
@@ -4912,7 +4913,7 @@ tcp_inbound_md5_hash(const struct sock *tcp_v4_md5_hash_skb (newhash, key,NULL , skb); else tp->af_specific->calc_md5_hash(newhash, key, NULL, skb); -if (memcmp (hash_location, newhash,16 ) !=0 ) { +if (crypto_memneq (hash_location, newhash,16 )) {NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPMD5FAILURE );trace_tcp_hash_md5_mismatch (sk, skb);return SKB_DROP_REASON_TCP_MD5FAILURE ;
net/ipv4/tcp_ipv4.c +2 -1
@@ -88,6 +88,7 @@#include <linux/skbuff_ref.h> #include <crypto/md5.h> +#include <crypto/utils.h> #include <trace/events/tcp.h>
@@ -838,7 +839,7 @@ static void tcp_v4_send_reset(const stru goto out;tcp_v4_md5_hash_skb (newhash, key,NULL , skb); -if (memcmp (md5_hash_location, newhash,16 ) !=0 ) +if (crypto_memneq (md5_hash_location, newhash,16 )) goto out; }
net/ipv6/tcp_ipv6.c +2 -1
@@ -68,6 +68,7 @@#include <linux/seq_file.h> #include <crypto/md5.h> +#include <crypto/utils.h> #include <trace/events/tcp.h>
@@ -1043,7 +1044,7 @@ static void tcp_v6_send_reset(const stru key.type =TCP_KEY_MD5 ;tcp_v6_md5_hash_skb (newhash, key.md5_key,NULL , skb); -if (memcmp (md5_hash_location, newhash,16 ) !=0 ) +if (crypto_memneq (md5_hash_location, newhash,16 )) goto out; }#endif
Greg Kroah-Hartman
maintainerPATCH 267/378 batman-adv: Avoid double-rtnl_lock ELP metric worker
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit cfc83a3c71517b59c1047db57da31e26a9dc2f33 upstream.
batadv_v_elp_get_throughput() might be called when the RTNL lock is already held. This could be problematic when the work queue item is cancelled via cancel_delayed_work_sync() in batadv_v_elp_iface_disable(). In this case, an rtnl_lock() would cause a deadlock.
To avoid this, rtnl_trylock() was used in this function to skip the retrieval of the ethtool information in case the RTNL lock was already held.
But for cfg80211 interfaces, batadv_get_real_netdev() was called - which also uses rtnl_lock(). The approach for __ethtool_get_link_ksettings() must also be used instead and the lockless version __batadv_get_real_netdev() has to be called.
--- net/batman-adv/bat_v_elp.c | 10 +++++++++- net/batman-adv/hard-interface.c | 8 ++++---- net/batman-adv/hard-interface.h | 1 + 3 files changed, 14 insertions(+), 5 deletions(-)
net/batman-adv/bat_v_elp.c +9 -1
@@ -111,7 +111,15 @@ static bool batadv_v_elp_get_throughput(/* unsupported WiFi driver version */ goto default_throughput; - real_netdev =batadv_get_real_netdev (hard_iface->net_dev); +/* only use rtnl_trylock because the elp worker will be cancelled while +* the rntl_lock is held. the cancel_delayed_work_sync() would otherwise +* wait forever when the elp work_item was started and it is then also +* trying to rtnl_lock +*/ +if (!rtnl_trylock ()) +return false; + real_netdev =__batadv_get_real_netdev (hard_iface->net_dev); +rtnl_unlock ();if (!real_netdev) goto default_throughput;
net/batman-adv/hard-interface.c +4 -4
@@ -204,7 +204,7 @@ static bool batadv_is_valid_iface(const }/** -* batadv_get_real_netdevice() - check if the given netdev struct is a virtual +* __batadv_get_real_netdev() - check if the given netdev struct is a virtual * interface on top of another 'real' interface * @netdev: the device to check *
@@ -214,7 +214,7 @@ static bool batadv_is_valid_iface(const* Return: the 'real' net device or the original net device and NULL in case * of an error. */ -static struct net_device *batadv_get_real_netdevice (struct net_device *netdev) +struct net_device *__batadv_get_real_netdev (struct net_device *netdev) {struct batadv_hard_iface *hard_iface =NULL ;struct net_device *real_netdev =NULL ;
@@ -267,7 +267,7 @@ struct net_device *batadv_get_real_netdestruct net_device *real_netdev;rtnl_lock (); - real_netdev =batadv_get_real_netdevice (net_device); + real_netdev =__batadv_get_real_netdev (net_device);rtnl_unlock ();return real_netdev;
@@ -336,7 +336,7 @@ static u32 batadv_wifi_flags_evaluate(stif (batadv_is_cfg80211_netdev (net_device)) wifi_flags |=BATADV_HARDIF_WIFI_CFG80211_DIRECT ; - real_netdev =batadv_get_real_netdevice (net_device); + real_netdev =__batadv_get_real_netdev (net_device);if (!real_netdev)return wifi_flags;
net/batman-adv/hard-interface.h +1 -0
@@ -67,6 +67,7 @@ enum batadv_hard_if_bcast {extern struct notifier_block batadv_hard_if_notifier; +struct net_device *__batadv_get_real_netdev (struct net_device *net_device);struct net_device *batadv_get_real_netdev (struct net_device *net_device);bool batadv_is_cfg80211_hardif (struct batadv_hard_iface *hard_iface);bool batadv_is_wifi_hardif (struct batadv_hard_iface *hard_iface);
Greg Kroah-Hartman
maintainerPATCH 268/378 drm/xe/xe2_hpg: Correct implementation of Wa_16025250150
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Roper <[email protected]>
commit 89865e6dc8487b627302bdced3f965cd0c406835 upstream.
Wa_16025250150 asks us to set five register fields of the register to 0x1 each. However we were just OR'ing this into the existing register value (which has a default of 0x4 for each nibble-sized field) resulting in final field values of 0x5 instead of the desired 0x1. Correct the RTP programming (use FIELD_SET instead of SET) to ensure each field is assigned to exactly the value we want.
--- drivers/gpu/drm/xe/xe_wa.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/gpu/drm/xe/xe_wa.c +7 -6
@@ -255,12 +255,13 @@ static const struct xe_rtp_entry_sr gt_w {XE_RTP_NAME ("16025250150" ),XE_RTP_RULES (GRAPHICS_VERSION (2001 )), -XE_RTP_ACTIONS (SET (LSN_VC_REG2 , -LSN_LNI_WGT (1 ) | -LSN_LNE_WGT (1 ) | -LSN_DIM_X_WGT (1 ) | -LSN_DIM_Y_WGT (1 ) | -LSN_DIM_Z_WGT (1 ))) +XE_RTP_ACTIONS (FIELD_SET (LSN_VC_REG2 , +LSN_LNI_WGT_MASK |LSN_LNE_WGT_MASK | +LSN_DIM_X_WGT_MASK |LSN_DIM_Y_WGT_MASK | +LSN_DIM_Z_WGT_MASK , +LSN_LNI_WGT (1 ) |LSN_LNE_WGT (1 ) | +LSN_DIM_X_WGT (1 ) |LSN_DIM_Y_WGT (1 ) | +LSN_DIM_Z_WGT (1 ))) },/* Xe2_HPM */
Greg Kroah-Hartman
maintainerPATCH 269/378 pmdomain: rockchip: Fix PD_VCODEC for RK3588
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shawn Lin <[email protected]>
commit 0fb59eaca18f1254ecdce34354eec3cb1b3b5e10 upstream.
Quoted 1 line
From the RK3588 TRM Table 7-1 RK3588 Voltage Domain and Power Domain Summary,
PD_RKVDEC0/1 and PD_VENC0/1 rely on VD_VCODEC which require extra voltages to be applied, otherwise it breaks RK3588-evb1-v10 board after vdec support landed[1]. The panic looks like below:
rockchip-pm-domain fd8d8000.power-management:power-controller: failed to set domain 'rkvdec0' on, val=0 rockchip-pm-domain fd8d8000.power-management:power-controller: failed to set domain 'rkvdec1' on, val=0
...
Hardware name: Rockchip RK3588S EVB1 V10 Board (DT) Workqueue: pm genpd_power_off_work_fn Call trace: show_stack+0x18/0x24 (C) dump_stack_lvl+0x40/0x84 dump_stack+0x18/0x24 vpanic+0x1ec/0x4fc vpanic+0x0/0x4fc check_panic_on_warn+0x0/0x94 arm64_serror_panic+0x6c/0x78 do_serror+0xc4/0xcc el1h_64_error_handler+0x3c/0x5c el1h_64_error+0x6c/0x70 regmap_mmio_read32le+0x18/0x24 (P) regmap_bus_reg_read+0xfc/0x130 regmap_read+0x188/0x1ac regmap_read+0x54/0x78 rockchip_pd_power+0xcc/0x5f0 rockchip_pd_power_off+0x1c/0x4c genpd_power_off+0x84/0x120 genpd_power_off+0x1b4/0x260 genpd_power_off_work_fn+0x38/0x58 process_scheduled_works+0x194/0x2c4 worker_thread+0x2ac/0x3d8 kthread+0x104/0x124 ret_from_fork+0x10/0x20 SMP: stopping secondary CPUs Kernel Offset: disabled CPU features: 0x3000000,000e0005,40230521,0400720b Memory Limit: none ---[ end Kernel panic - not syncing: Asynchronous SError Interrupt ]---
Chaoyi pointed out the PD_VCODEC is the parent of PD_RKVDEC0/1 and PD_VENC0/1, so checking the PD_VCODEC is enough.
[1] https://lore.kernel.org/linux-rockchip/[email protected]/
--- drivers/pmdomain/rockchip/pm-domains.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pmdomain/rockchip/pm-domains.c +1 -1
@@ -1311,7 +1311,7 @@ static const struct rockchip_domain_infostatic const struct rockchip_domain_info rk3588_pm_domains[] = { [RK3588_PD_GPU ] =DOMAIN_RK3588 ("gpu" ,0x0 ,BIT (0 ),0 ,0x0 ,0 ,BIT (1 ),0x0 ,BIT (0 ),BIT (0 ), false, true), [RK3588_PD_NPU ] =DOMAIN_RK3588 ("npu" ,0x0 ,BIT (1 ),BIT (1 ),0x0 ,0 ,0 ,0x0 ,0 ,0 , false, true), - [RK3588_PD_VCODEC ] =DOMAIN_RK3588 ("vcodec" ,0x0 ,BIT (2 ),BIT (2 ),0x0 ,0 ,0 ,0x0 ,0 ,0 , false, false), + [RK3588_PD_VCODEC ] =DOMAIN_RK3588 ("vcodec" ,0x0 ,BIT (2 ),BIT (2 ),0x0 ,0 ,0 ,0x0 ,0 ,0 , false, true), [RK3588_PD_NPUTOP ] =DOMAIN_RK3588 ("nputop" ,0x0 ,BIT (3 ),0 ,0x0 ,BIT (11 ),BIT (2 ),0x0 ,BIT (1 ),BIT (1 ), false, false), [RK3588_PD_NPU1 ] =DOMAIN_RK3588 ("npu1" ,0x0 ,BIT (4 ),0 ,0x0 ,BIT (12 ),BIT (3 ),0x0 ,BIT (2 ),BIT (2 ), false, false), [RK3588_PD_NPU2 ] =DOMAIN_RK3588 ("npu2" ,0x0 ,BIT (5 ),0 ,0x0 ,BIT (13 ),BIT (4 ),0x0 ,BIT (3 ),BIT (3 ), false, false),
Greg Kroah-Hartman
maintainerPATCH 270/378 parisc: Increase initial mapping to 64 MB with KALLSYMS
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit 8e732934fb81282be41602550e7e07baf265e972 upstream.
The 32MB initial kernel mapping can become too small when CONFIG_KALLSYMS is used. Increase the mapping to 64 MB in this case.
--- arch/parisc/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/parisc/include/asm/pgtable.h +1 -1
@@ -85,7 +85,7 @@ extern void __update_cache(pte_t pte);printk ("%s:%d: bad pgd %08lx.\n" , __FILE__, __LINE__, (unsigned long )pgd_val (e)) /* This is the size of the initially mapped kernel memory */ -#if defined(CONFIG_64BIT ) +#if defined(CONFIG_64BIT ) || defined(CONFIG_KALLSYMS )#define KERNEL_INITIAL_ORDER 26/* 1<<26 = 64MB */ #else #define KERNEL_INITIAL_ORDER 25/* 1<<25 = 32MB */
Greg Kroah-Hartman
maintainerPATCH 271/378 nouveau/dpcd: return EBUSY for aux xfer if the device is asleep
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Airlie <[email protected]>
commit 8f3c6f08ababad2e3bdd239728cf66a9949446b4 upstream.
If we have runtime suspended, and userspace wants to use /dev/drm_dp_* then just tell it the device is busy instead of crashing in the GSP code.
WARNING: CPU: 2 PID: 565741 at drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c:164 r535_gsp_msgq_wait+0x9a/0xb0 [nouveau] CPU: 2 UID: 0 PID: 565741 Comm: fwupd Not tainted 6.18.10-200.fc43.x86_64 #1 PREEMPT(lazy) Hardware name: LENOVO 20QTS0PQ00/20QTS0PQ00, BIOS N2OET65W (1.52 ) 08/05/2024 RIP: 0010:r535_gsp_msgq_wait+0x9a/0xb0 [nouveau]
This is a simple fix to get backported. We should probably engineer a proper power domain solution to wake up devices and keep them awake while fw updates are happening.
--- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/nouveau/nouveau_connector.c +3 -0
@@ -1230,6 +1230,9 @@ nouveau_connector_aux_xfer(struct drm_dpu8 size = msg->size;int ret; +if (pm_runtime_suspended (nv_connector->base.dev->dev)) +return -EBUSY ; + nv_encoder =find_encoder (&nv_connector->base,DCB_OUTPUT_DP );if (!nv_encoder)return -ENODEV ;
Greg Kroah-Hartman
maintainerPATCH 272/378 arm64: mm: Add PTE_DIRTY back to PAGE_KERNEL* to fix kexec/hibernation
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Catalin Marinas <[email protected]>
commit c25c4aa3f79a488cc270507935a29c07dc6bddfc upstream.
Commit 143937ca51cc ("arm64, mm: avoid always making PTE dirty in pte_mkwrite()") changed pte_mkwrite_novma() to only clear PTE_RDONLY when PTE_DIRTY is set. This was to allow writable-clean PTEs for swap pages that haven't actually been written.
However, this broke kexec and hibernation for some platforms. Both go through trans_pgd_create_copy() -> _copy_pte(), which calls pte_mkwrite_novma() to make the temporary linear-map copy fully writable. With the updated pte_mkwrite_novma(), read-only kernel pages (without PTE_DIRTY) remain read-only in the temporary mapping. While such behaviour is fine for user pages where hardware DBM or trapping will make them writeable, subsequent in-kernel writes by the kexec relocation code will fault.
Add PTE_DIRTY back to all _PAGE_KERNEL* protection definitions. This was the case prior to 5.4, commit aa57157be69f ("arm64: Ensure VM_WRITE|VM_SHARED ptes are clean by default"). With the kernel linear-map PTEs always having PTE_DIRTY set, pte_mkwrite_novma() correctly clears PTE_RDONLY.
--- arch/arm64/include/asm/pgtable-prot.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/arm64/include/asm/pgtable-prot.h +5 -5
@@ -50,11 +50,11 @@#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) -#define _PAGE_KERNEL (PROT_NORMAL) -#define _PAGE_KERNEL_RO ((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY) -#define _PAGE_KERNEL_ROX ((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY) -#define _PAGE_KERNEL_EXEC (PROT_NORMAL & ~PTE_PXN) -#define _PAGE_KERNEL_EXEC_CONT ((PROT_NORMAL & ~PTE_PXN) | PTE_CONT) +#define _PAGE_KERNEL (PROT_NORMAL | PTE_DIRTY) +#define _PAGE_KERNEL_RO ((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY | PTE_DIRTY) +#define _PAGE_KERNEL_ROX ((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY | PTE_DIRTY) +#define _PAGE_KERNEL_EXEC ((PROT_NORMAL & ~PTE_PXN) | PTE_DIRTY) +#define _PAGE_KERNEL_EXEC_CONT ((PROT_NORMAL & ~PTE_PXN) | PTE_CONT | PTE_DIRTY)#define _PAGE_SHARED (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)#define _PAGE_SHARED_EXEC (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
Greg Kroah-Hartman
maintainerPATCH 273/378 hwmon: (pmbus/q54sj108a2) fix stack overflow in debugfs read
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit 25dd70a03b1f5f3aa71e1a5091ecd9cd2a13ee43 upstream.
The q54sj108a2_debugfs_read function suffers from a stack buffer overflow due to incorrect arguments passed to bin2hex(). The function currently passes 'data' as the destination and 'data_char' as the source.
Because bin2hex() converts each input byte into two hex characters, a 32-byte block read results in 64 bytes of output. Since 'data' is only 34 bytes (I2C_SMBUS_BLOCK_MAX + 2), this writes 30 bytes past the end of the buffer onto the stack.
Additionally, the arguments were swapped: it was reading from the zero-initialized 'data_char' and writing to 'data', resulting in all-zero output regardless of the actual I2C read.
Fix this by:
1. Expanding 'data_char' to 66 bytes to safely hold the hex output.
2. Correcting the bin2hex() argument order and using the actual read count.
3. Using a pointer to select the correct output buffer for the final simple_read_from_buffer call.
--- drivers/hwmon/pmbus/q54sj108a2.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
drivers/hwmon/pmbus/q54sj108a2.c +10 -9
@@ -78,7 +78,8 @@ static ssize_t q54sj108a2_debugfs_read(sint idx = *idxp;struct q54sj108a2_data *psu =to_psu (idxp, idx);char data[I2C_SMBUS_BLOCK_MAX +2 ] = {0 }; -char data_char[I2C_SMBUS_BLOCK_MAX +2 ] = {0 }; +char data_char[I2C_SMBUS_BLOCK_MAX *2 +2 ] = {0 }; +char *out = data;char *res;switch (idx) {
@@ -149,27 +150,27 @@ static ssize_t q54sj108a2_debugfs_read(sif (rc <0 )return rc; - res =bin2hex (data, data_char,32 ); - rc = res - data; - + res =bin2hex (data_char, data, rc); + rc = res - data_char; + out = data_char;break ;case Q54SJ108A2_DEBUGFS_FLASH_KEY : rc =i2c_smbus_read_block_data (psu->client,PMBUS_FLASH_KEY_WRITE , data);if (rc <0 )return rc; - res =bin2hex (data, data_char,4 ); - rc = res - data; - + res =bin2hex (data_char, data, rc); + rc = res - data_char; + out = data_char;break ;default :return -EINVAL ; } - data[rc] ='\n' ; + out[rc] ='\n' ; rc +=2 ; -return simple_read_from_buffer (buf, count, ppos, data, rc); +return simple_read_from_buffer (buf, count, ppos, out, rc); } static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,
Greg Kroah-Hartman
maintainerPATCH 274/378 io_uring/zcrx: use READ_ONCE with user shared RQEs
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov <[email protected]>
commit 531bb98a030cc1073bd7ed9a502c0a3a781e92ee upstream.
Refill queue entries are shared with the user space, use READ_ONCE when reading them.
--- io_uring/zcrx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
io_uring/zcrx.c +3 -2
@@ -898,11 +898,12 @@ static inline bool io_parse_rqe(struct istruct io_zcrx_ifq *ifq, struct net_iov **ret_niov) { + __u64 off = READ_ONCE(rqe->off);unsigned niov_idx, area_idx;struct io_zcrx_area *area; - area_idx = rqe->off >>IORING_ZCRX_AREA_SHIFT ; - niov_idx = (rqe->off & ~IORING_ZCRX_AREA_MASK ) >> ifq->niov_shift; + area_idx = off >>IORING_ZCRX_AREA_SHIFT ; + niov_idx = (off & ~IORING_ZCRX_AREA_MASK ) >> ifq->niov_shift;if (unlikely (rqe->__pad || area_idx))return false;
Greg Kroah-Hartman
maintainerPATCH 275/378 parisc: Fix initial page table creation for boot
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit 8475d8fe21ec9c7eb2faca555fbc5b68cf0d2597 upstream.
The KERNEL_INITIAL_ORDER value defines the initial size (usually 32 or 64 MB) of the page table during bootup. Up until now the whole area was initialized with PTE entries, but there was no check if we filled too many entries. Change the code to fill up with so many entries that the "_end" symbol can be reached by the kernel, but not more entries than actually fit into the initial PTE tables.
--- arch/parisc/kernel/head.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/parisc/kernel/head.S +6 -1
@@ -56,6 +56,7 @@ ENTRY(parisc_kernel_start) .import __bss_start,data .import __bss_stop,data + .import __end,data load32 PA(__bss_start),%r3 load32 PA(__bss_stop),%r4
@@ -149,7 +150,11 @@ $cpu_ok: * everything ... it will get remapped correctly later */ ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */ load32 (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */ - load32 PA(pg0),%r1 + load32 PA(_end),%r1 + SHRREG %r1,PAGE_SHIFT,%r1 /* %r1 is PFN count for _end symbol */ + cmpb,<<,n %r11,%r1,1f + copy %r1,%r11 /* %r1 PFN count smaller than %r11 */ +1: load32 PA(pg0),%r1 $pgt_fill_loop: STREGM %r3,ASM_PTE_ENTRY_SIZE(%r1)
Greg Kroah-Hartman
maintainerPATCH 276/378 arm64: contpte: fix set_access_flags() no-op check for SMMU/ATS faults
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Piotr Jaroszynski <[email protected]>
commit 97c5550b763171dbef61e6239cab372b9f9cd4a2 upstream.
contpte_ptep_set_access_flags() compared the gathered ptep_get() value against the requested entry to detect no-ops. ptep_get() ORs AF/dirty from all sub-PTEs in the CONT block, so a dirty sibling can make the target appear already-dirty. When the gathered value matches entry, the function returns 0 even though the target sub-PTE still has PTE_RDONLY set in hardware.
For a CPU with FEAT_HAFDBS this gathered view is fine, since hardware may set AF/dirty on any sub-PTE and CPU TLB behavior is effectively gathered across the CONT range. But page-table walkers that evaluate each descriptor individually (e.g. a CPU without DBM support, or an SMMU without HTTU, or with HA/HD disabled in CD.TCR) can keep faulting on the unchanged target sub-PTE, causing an infinite fault loop.
Gathering can therefore cause false no-ops when only a sibling has been updated:
- write faults: target still has PTE_RDONLY (needs PTE_RDONLY cleared)
- read faults: target still lacks PTE_AF
Fix by checking each sub-PTE against the requested AF/dirty/write state (the same bits consumed by __ptep_set_access_flags()), using raw per-PTE values rather than the gathered ptep_get() view, before returning no-op. Keep using the raw target PTE for the write-bit unfold decision.
Per Arm ARM (DDI 0487) D8.7.1 ("The Contiguous bit"), any sub-PTE in a CONT range may become the effective cached translation and software must maintain consistent attributes across the range.
--- arch/arm64/mm/contpte.c | 53 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-)
arch/arm64/mm/contpte.c +49 -4
@@ -581,6 +581,27 @@ void contpte_clear_young_dirty_ptes(stru }EXPORT_SYMBOL_GPL (contpte_clear_young_dirty_ptes); +static bool contpte_all_subptes_match_access_flags (pte_t *ptep,pte_t entry) +{ +pte_t *cont_ptep =contpte_align_down (ptep); +/* +* PFNs differ per sub-PTE. Match only bits consumed by +* __ptep_set_access_flags(): AF, DIRTY and write permission. +*/ +const pteval_t cmp_mask =PTE_RDONLY |PTE_AF |PTE_WRITE |PTE_DIRTY ; +pteval_t entry_cmp =pte_val (entry) & cmp_mask; +int i; + +for (i =0 ; i <CONT_PTES ; i++) { +pteval_t pte_cmp =pte_val (__ptep_get (cont_ptep + i)) & cmp_mask; + +if (pte_cmp != entry_cmp) +return false; + } + +return true; +} +int contpte_ptep_set_access_flags (struct vm_area_struct *vma,unsigned long addr,pte_t *ptep,pte_t entry,int dirty)
@@ -590,14 +611,38 @@ int contpte_ptep_set_access_flags(structint i;/* -* Gather the access/dirty bits for the contiguous range. If nothing has -* changed, its a noop. +* Check whether all sub-PTEs in the CONT block already match the +* requested access flags/write permission, using raw per-PTE values +* rather than the gathered ptep_get() view. +* +* __ptep_set_access_flags() can update AF, dirty and write +* permission, but only to make the mapping more permissive. +* +* ptep_get() gathers AF/dirty state across the whole CONT block, +* which is correct for a CPU with FEAT_HAFDBS. But page-table +* walkers that evaluate each descriptor individually (e.g. a CPU +* without DBM support, or an SMMU without HTTU, or with HA/HD +* disabled in CD.TCR) can keep faulting on the target sub-PTE if +* only a sibling has been updated. Gathering can therefore cause +* false no-ops when only a sibling has been updated: +* - write faults: target still has PTE_RDONLY (needs PTE_RDONLY cleared) +* - read faults: target still lacks PTE_AF +* +* Per Arm ARM (DDI 0487) D8.7.1, any sub-PTE in a CONT range may +* become the effective cached translation, so all entries must have +* consistent attributes. Check the full CONT block before returning +* no-op, and when any sub-PTE mismatches, proceed to update the whole +* range. */ - orig_pte =pte_mknoncont (ptep_get (ptep)); -if (pte_val (orig_pte) ==pte_val (entry)) +if (contpte_all_subptes_match_access_flags (ptep, entry))return 0 ;/* +* Use raw target pte (not gathered) for write-bit unfold decision. +*/ + orig_pte =pte_mknoncont (__ptep_get (ptep)); + +/* * We can fix up access/dirty bits without having to unfold the contig * range. But if the write bit is changing, we must unfold. */
Greg Kroah-Hartman
maintainerPATCH 277/378 parisc: Check kernel mapping earlier at bootup
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit 17c144f1104bfc29a3ce3f7d0931a1bfb7a3558c upstream.
The check if the initial mapping is sufficient needs to happen much earlier during bootup. Move this test directly to the start_parisc() function and use native PDC iodc functions to print the warning, because panic() and printk() are not functional yet.
This fixes boot when enabling various KALLSYSMS options which need much more space.
--- arch/parisc/kernel/setup.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
arch/parisc/kernel/setup.c +12 -8
@@ -120,14 +120,6 @@ void __init setup_arch(char **cmdline_p)#endif printk (KERN_CONT ".\n" ); -/* -* Check if initial kernel page mappings are sufficient. -* panic early if not, else we may access kernel functions -* and variables which can't be reached. -*/ -if (__pa ((unsigned long ) &_end) >=KERNEL_INITIAL_SIZE ) -panic ("KERNEL_INITIAL_ORDER too small!" ); -#ifdef CONFIG_64BIT if (parisc_narrow_firmware) {printk (KERN_INFO "Kernel is using PDC in 32-bit mode.\n" );
@@ -279,6 +271,18 @@ void __init start_parisc(void)int ret, cpunum;struct pdc_coproc_cfg coproc_cfg; +/* +* Check if initial kernel page mapping is sufficient. +* Print warning if not, because we may access kernel functions and +* variables which can't be reached yet through the initial mappings. +* Note that the panic() and printk() functions are not functional +* yet, so we need to use direct iodc() firmware calls instead. +*/ +const char warn1[] ="CRITICAL: Kernel may crash because " +"KERNEL_INITIAL_ORDER is too small.\n" ; +if (__pa ((unsigned long ) &_end) >=KERNEL_INITIAL_SIZE ) +pdc_iodc_print (warn1,sizeof (warn1) -1 ); +/* check QEMU/SeaBIOS marker in PAGE0 */ running_on_qemu = (memcmp (&PAGE0 ->pad0,"SeaBIOS" ,8 ) ==0 );
Greg Kroah-Hartman
maintainerPATCH 278/378 io_uring/net: reject SEND_VECTORIZED when unsupported
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov <[email protected]>
commit c36e28becd0586ac98318fd335e5e91d19cd2623 upstream.
IORING_SEND_VECTORIZED with registered buffers is not implemented but could be. Don't silently ignore the flag in this case but reject it with an error. It only affects sendzc as normal sends don't support registered buffers.
--- io_uring/net.c | 2 ++ 1 file changed, 2 insertions(+)
io_uring/net.c +2 -0
@@ -375,6 +375,8 @@ static int io_send_setup(struct io_kiocb kmsg->msg.msg_namelen = addr_len; }if (sr->flags &IORING_RECVSEND_FIXED_BUF ) { +if (sr->flags &IORING_SEND_VECTORIZED ) +return -EINVAL ; req->flags |=REQ_F_IMPORT_BUFFER ;return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 279/378 regulator: pf9453: Respect IRQ trigger settings from firmware
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Franz Schnyder <[email protected]>
commit 2d85ecd6fb0eb2fee0ffa040ec1ddea57b09bc38 upstream.
The datasheet specifies, that the IRQ_B pin is pulled low when any unmasked interrupt bit status is changed, and it is released high once the application processor reads the INT1 register. As it specifies a level-low behavior, it should not force a falling-edge interrupt.
Remove the IRQF_TRIGGER_FALLING to not force the falling-edge interrupt and instead rely on the flag from the device tree.
--- drivers/regulator/pf9453-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/regulator/pf9453-regulator.c +1 -1
@@ -809,7 +809,7 @@ static int pf9453_i2c_probe(struct i2c_c } ret =devm_request_threaded_irq (pf9453->dev, pf9453->irq,NULL , pf9453_irq_handler, - (IRQF_TRIGGER_FALLING |IRQF_ONESHOT ), +IRQF_ONESHOT ,"pf9453-irq" , pf9453);if (ret)return dev_err_probe (pf9453->dev, ret,"Failed to request IRQ: %d\n" , pf9453->irq);
Greg Kroah-Hartman
maintainerPATCH 280/378 pmdomain: bcm: bcm2835-power: Fix broken reset status read
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
commit 550bae2c0931dbb664a61b08c21cf156f0a5362a upstream.
bcm2835_reset_status() has a misplaced parenthesis on every PM_READ() call. Since PM_READ(reg) expands to readl(power->base + (reg)), the expression:
PM_READ(PM_GRAFX & PM_V3DRSTN)
computes the bitwise AND of the register offset PM_GRAFX with the bitmask PM_V3DRSTN before using the result as a register offset, reading from the wrong MMIO address instead of the intended PM_GRAFX register. The same issue affects the PM_IMAGE cases.
Fix by moving the closing parenthesis so PM_READ() receives only the register offset, and the bitmask is applied to the value returned by the read.
--- drivers/pmdomain/bcm/bcm2835-power.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/pmdomain/bcm/bcm2835-power.c +3 -3
@@ -580,11 +580,11 @@ static int bcm2835_reset_status(struct rswitch (id) {case BCM2835_RESET_V3D : -return !PM_READ (PM_GRAFX &PM_V3DRSTN ); +return !(PM_READ (PM_GRAFX ) &PM_V3DRSTN );case BCM2835_RESET_H264 : -return !PM_READ (PM_IMAGE &PM_H264RSTN ); +return !(PM_READ (PM_IMAGE ) &PM_H264RSTN );case BCM2835_RESET_ISP : -return !PM_READ (PM_IMAGE &PM_ISPRSTN ); +return !(PM_READ (PM_IMAGE ) &PM_ISPRSTN );default :return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 281/378 drm/ttm: Fix ttm_pool_beneficial_order() return type
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tvrtko Ursulin <[email protected]>
commit 6e3f4514e3b432871ac81717d24f56b441857f77 upstream.
Fix a nasty copy and paste bug, where the incorrect boolean return type of the ttm_pool_beneficial_order() helper had a consequence of avoiding direct reclaim too eagerly for drivers which use this feature (currently amdgpu).
--- drivers/gpu/drm/ttm/ttm_pool_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/ttm/ttm_pool_internal.h +1 -1
@@ -17,7 +17,7 @@ static inline bool ttm_pool_uses_dma32(struct ttm_pool *pool)return pool->alloc_flags &TTM_ALLOCATION_POOL_USE_DMA32 ; } -static inline bool ttm_pool_beneficial_order (struct ttm_pool *pool) +static inline unsigned int ttm_pool_beneficial_order (struct ttm_pool *pool) {return pool->alloc_flags &0xff ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 282/378 crypto: ccp - allow callers to use HV-Fixed page API when SEV is disabled
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ashish Kalra <[email protected]>
commit 8168a7b72bdee3790b126f63bd30306759206b15 upstream.
When SEV is disabled, the HV-Fixed page allocation call fails, which in turn causes SFS initialization to fail.
Fix the HV-Fixed API so callers (for example, SFS) can use it even when SEV is disabled by performing normal page allocation and freeing.
--- drivers/crypto/ccp/sev-dev.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/crypto/ccp/sev-dev.c +4 -6
@@ -1105,15 +1105,12 @@ struct page *snp_alloc_hv_fixed_pages(un {struct psp_device *psp_master =psp_get_master_device ();struct snp_hv_fixed_pages_entry *entry; -struct sev_device *sev;unsigned int order;struct page *page; -if (!psp_master || !psp_master->sev_data) +if (!psp_master)return NULL ; - sev = psp_master->sev_data; - order =get_order (PMD_SIZE * num_2mb_pages);/*
@@ -1126,7 +1123,8 @@ struct page *snp_alloc_hv_fixed_pages(un* This API uses SNP_INIT_EX to transition allocated pages to HV_Fixed * page state, fail if SNP is already initialized. */ -if (sev->snp_initialized) +if (psp_master->sev_data && + ((struct sev_device *)psp_master->sev_data)->snp_initialized)return NULL ;/* Re-use freed pages that match the request */
@@ -1162,7 +1160,7 @@ void snp_free_hv_fixed_pages(struct pagestruct psp_device *psp_master =psp_get_master_device ();struct snp_hv_fixed_pages_entry *entry, *nentry; -if (!psp_master || !psp_master->sev_data) +if (!psp_master)return ;/*
Greg Kroah-Hartman
maintainerPATCH 283/378 s390/stackleak: Fix __stackleak_poison() inline assembly constraint
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
commit 674c5ff0f440a051ebf299d29a4c013133d81a65 upstream.
The __stackleak_poison() inline assembly comes with a "count" operand where the "d" constraint is used. "count" is used with the exrl instruction and "d" means that the compiler may allocate any register from 0 to 15.
If the compiler would allocate register 0 then the exrl instruction would not or the value of "count" into the executed instruction - resulting in a stackframe which is only partially poisoned.
Use the correct "a" constraint, which excludes register 0 from register allocation.
--- arch/s390/include/asm/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/include/asm/processor.h +1 -1
@@ -158,7 +158,7 @@ static __always_inline void __stackleak_" j 4f\n" "3: mvc 8(1,%[addr]),0(%[addr])\n" "4:" - : [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp) + : [addr] "+&a" (erase_low), [count] "+&a" (count), [tmp] "=&a" (tmp) : [poison] "d" (poison) : "memory", "cc" );
Greg Kroah-Hartman
maintainerPATCH 284/378 ata: libata-core: Disable LPM on ST1000DM010-2EP102
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maximilian Pezzullo <[email protected]>
commit b3b1d3ae1d87bc9398fb715c945968bf4c75a09a upstream.
According to a user report, the ST1000DM010-2EP102 has problems with LPM, causing random system freezes. The drive belongs to the same BarraCuda family as the ST2000DM008-2FR102 which has the same issue.
--- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+)
drivers/ata/libata-core.c +1 -0
@@ -4186,6 +4186,7 @@ static const struct ata_dev_quirks_entry ATA_QUIRK_FIRMWARE_WARN },/* Seagate disks with LPM issues */ + { "ST1000DM010-2EP102", NULL, ATA_QUIRK_NOLPM }, { "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM },/* drives which fail FPDMA_AA activation (some may freeze afterwards)
Greg Kroah-Hartman
maintainerPATCH 285/378 s390/xor: Fix xor_xc_2() inline assembly constraints
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
commit f775276edc0c505dc0f782773796c189f31a1123 upstream.
The inline assembly constraints for xor_xc_2() are incorrect. "bytes", "p1", and "p2" are input operands, while all three of them are modified within the inline assembly. Given that the function consists only of this inline assembly it seems unlikely that this may cause any problems, however fix this in any case.
--- arch/s390/lib/xor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/lib/xor.c +2 -2
@@ -28,8 +28,8 @@ static void xor_xc_2(unsigned long bytes" j 3f\n" "2: xc 0(1,%1),0(%2)\n" "3:" - : : "d" (bytes), "a" (p1), "a" (p2) - : "0", "cc", "memory"); + : "+d" (bytes), "+a" (p1), "+a" (p2) + : : "0", "cc", "memory"); } static void xor_xc_3(unsigned long bytes, unsigned long * __restrict p1,
Greg Kroah-Hartman
maintainerPATCH 286/378 drm/amd/display: Fallback to boot snapshot for dispclk
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dillon Varone <[email protected]>
commit 30d937f63bd19bbcaafa4b892eb251f8bbbf04ef upstream.
[WHY & HOW]
If the dentist is unavailable, fallback to reading CLKIP via the boot snapshot to get the current dispclk.
--- drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +5 -1
@@ -71,7 +71,11 @@ void dcn401_initialize_min_clocks(struct* audio corruption. Read current DISPCLK from DENTIST and request the same * freq to ensure that the timing is valid and unchanged. */ - clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist (dc->clk_mgr); +if (dc->clk_mgr->funcs->get_dispclk_from_dentist) { + clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist (dc->clk_mgr); + }else { + clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk *1000 ; + } } clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0 ].dtbclk_mhz *1000 ; clocks->fclk_p_state_change_support = true;
Greg Kroah-Hartman
maintainerPATCH 287/378 s390/xor: Fix xor_xc_5() inline assembly
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Gorbik <[email protected]>
commit 5f25805303e201f3afaff0a90f7c7ce257468704 upstream.
xor_xc_5() contains a larl 1,2f that is not used by the asm and is not declared as a clobber. This can corrupt a compiler-allocated value in %r1 and lead to miscompilation. Remove the instruction.
--- arch/s390/lib/xor.c | 1 - 1 file changed, 1 deletion(-)
arch/s390/lib/xor.c +0 -1
@@ -96,7 +96,6 @@ static void xor_xc_5(unsigned long bytes const unsigned long * __restrict p5) { asmvolatile ( -" larl 1,2f\n" " aghi %0,-1\n" " jm 6f\n" " srlg 0,%0,8\n"
Greg Kroah-Hartman
maintainerPATCH 288/378 slab: distinguish lock and trylock for sheaf_flush_main()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlastimil Babka <[email protected]>
commit 48647d3f9a644d1e81af6558102d43cdb260597b upstream.
sheaf_flush_main() can be called from __pcs_replace_full_main() where it's fine if the trylock fails, and pcs_flush_all() where it's not expected to and for some flush callers (when destroying the cache or memory hotremove) it would be actually a problem if it failed and left the main sheaf not flushed. The flush callers can however safely use local_lock() instead of trylock.
The trylock failure should not happen in practice on !PREEMPT_RT, but can happen on PREEMPT_RT. The impact is limited in practice because when a trylock fails in the kmem_cache_destroy() path, it means someone is using the cache while destroying it, which is a bug on its own. The memory hotremove path is unlikely to be employed in a production RT config, but it's possible.
To fix this, split the function into sheaf_flush_main() (using local_lock()) and sheaf_try_flush_main() (using local_trylock()) where both call __sheaf_flush_main_batch() to flush a single batch of objects. This will also allow lockdep to verify our context assumptions.
The problem was raised in an off-list question by Marcelo.
--- mm/slub.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-)
mm/slub.c +37 -10
@@ -2730,19 +2730,19 @@ static void __kmem_cache_free_bulk(struc* object pointers are moved to a on-stack array under the lock. To bound the * stack usage, limit each batch to PCS_BATCH_MAX. * -* returns true if at least partially flushed +* Must be called with s->cpu_sheaves->lock locked, returns with the lock +* unlocked. +* +* Returns how many objects are remaining to be flushed */ -static bool sheaf_flush_main (struct kmem_cache *s) +static unsigned int __sheaf_flush_main_batch (struct kmem_cache *s) {struct slub_percpu_sheaves *pcs;unsigned int batch, remaining;void *objects[PCS_BATCH_MAX ];struct slab_sheaf *sheaf; -bool ret = false; -next_batch: -if (!local_trylock (&s->cpu_sheaves->lock)) -return ret; +lockdep_assert_held (this_cpu_ptr (&s->cpu_sheaves->lock)); pcs =this_cpu_ptr (s->cpu_sheaves); sheaf = pcs->main;
@@ -2760,10 +2760,37 @@ next_batch:stat_add (s,SHEAF_FLUSH , batch); - ret = true; +return remaining; +} -if (remaining) - goto next_batch; +static void sheaf_flush_main (struct kmem_cache *s) +{ +unsigned int remaining; + +do { +local_lock (&s->cpu_sheaves->lock); + + remaining =__sheaf_flush_main_batch (s); + + }while (remaining); +} + +/* +* Returns true if the main sheaf was at least partially flushed. +*/ +static bool sheaf_try_flush_main (struct kmem_cache *s) +{ +unsigned int remaining; +bool ret = false; + +do { +if (!local_trylock (&s->cpu_sheaves->lock)) +return ret; + + ret = true; + remaining =__sheaf_flush_main_batch (s); + + }while (remaining);return ret; }
@@ -6215,7 +6242,7 @@ alloc_empty:if (put_fail)stat (s,BARN_PUT_FAIL ); -if (!sheaf_flush_main (s)) +if (!sheaf_try_flush_main (s))return NULL ;if (!local_trylock (&s->cpu_sheaves->lock))