6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 103/1376 s390/vfio-ap: Fix control domain removal in vfio_ap_mdev_cfg_remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 6b8a02e216f6b520cc029e43ddc83956605135d5 upstream.
The vfio_ap_config_remove function uses the bitmap_andnot function to clear bits from the matrix_mdev->matrix.adm bitmap (specifies the control domains assigned to the mdev). This prevents the explicitly unplugged control domains from being removed the KVM guest. The bitmap_and function is used instead.
--- drivers/s390/crypto/vfio_ap_ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +3 -3
@@ -2561,9 +2561,9 @@ static void vfio_ap_mdev_cfg_remove(unsi do_remove |=bitmap_and (aqrem, aq_remove, matrix_mdev->matrix.aqm,AP_DOMAINS ); - do_remove |=bitmap_andnot (cdrem, cd_remove, - matrix_mdev->matrix.adm, -AP_DOMAINS ); + do_remove |=bitmap_and (cdrem, cd_remove, + matrix_mdev->matrix.adm, +AP_DOMAINS );if (do_remove) vfio_ap_mdev_hot_unplug_cfg(matrix_mdev, aprem, aqrem,
Greg Kroah-Hartman
maintainerPATCH 104/1376 s390/vfio-ap: Fix dereference matrix_mdev->kvm without checking for NULL
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit d50346801b4f144e42b49cd4f1496010498ab114 upstream.
The ap_driver structure has two fields which are function pointers to callbacks:
* .on_config_changed: called at the start of the AP bus scan function to notify the device driver that the host AP configuration has changed and the associated AP devices will be added or removed accordingly. This gives the implementor a chance to evaluate the configuration changes and respond to them before the associated devices are added or removed.
* .on_scan_complete: Called at the end of the AP bus scan function to notify the device driver that the host AP configuration has changed and the AP devices have been added or removed accordingly. This gives the implementor the opportunity to respond to the changes after the associated devices are added or removed.
These two callbacks are implemented in the vfio_ap device driver via the vfio_ap_on_cfg_changed and vfio_ap_on_scan_complete functions respectively.
Within the call stack of these two callback functions the matrix_mdev->kvm->lock mutex is taken without checking whether matrix_mdev->kvm is NULL or not. If matrix_mdev->kvm has never been set, trying to take the lock will trigger a NULL pointer dereference. This patch adds checks for matrix_mdev->kvm == NULL before taking the matrix_mdev->kvm->lock mutex.
Note that the matrix_mdev->kvm->lock mutex taken in the vfio_ap_mdev_hot_plug_config function is moved to the calling function along with the matrix_dev->mdevs_lock which is needed there to access the fields of the matrix_mdev. It makes little sense to make the change the check for matrix_mdev->kvm there before taking the kvm->lock mutex only to have to move it out via another patch, so it is done in this patch.
It is important to make note of the following:
1. The matrix_dev->guests_lock is acquired at the start of both callback functions. This ensures that matrix_mdev will not be removed via the vfio_ap_mdev_remove function because it too takes matrix_dev_guests_lock before removing the object; so, matrix_mdev will be available for the duration of the callback functions.
2. The matrix_dev->mdevs_lock mutex must be taken in order to access fields within the matrix_mdev structure
3. matrix_mdev->kvm->lock mutex must be taken before the matrix_dev->mdevs_lock to prevent a lockdep splat.
4: The kvm->lock must be held while plugging the guest's AP configuration
into its SIE state description via the vfio_ap_mdev_update_guest_apcb function.
5. The vfio_ap_mdev_update_guest_apcb checks matrix_mdev->kvm to verify it is not NULL before doing the hot plug of the guest's AP configuration.
--- drivers/s390/crypto/vfio_ap_ops.c | 39 +++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +30 -9
@@ -2551,8 +2551,20 @@ static void vfio_ap_mdev_cfg_remove(unsiDECLARE_BITMAP (cdrem,AP_DOMAINS );int do_remove; +/* +* It is safe to traverse this list here because the +* required guard - matrix_dev->guests_lock - is taken in the +* vfio_ap_on_cfg_changed function prior to this function getting +* called. +*/ list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { -mutex_lock (&matrix_mdev->kvm->lock); +/* +* The mdevs_lock must be held to access fields within matrix_mdev, +* and kvm->lock must be taken before mdevs_lock to satisfy the lock +* ordering requirement and prevent a lockdep splat. +*/ +if (matrix_mdev->kvm) +mutex_lock (&matrix_mdev->kvm->lock);mutex_lock (&matrix_dev->mdevs_lock); do_remove = bitmap_and(aprem, ap_remove,
@@ -2570,7 +2582,8 @@ static void vfio_ap_mdev_cfg_remove(unsi cdrem);mutex_unlock (&matrix_dev->mdevs_lock); -mutex_unlock (&matrix_mdev->kvm->lock); +if (matrix_mdev->kvm) +mutex_unlock (&matrix_mdev->kvm->lock); } }
@@ -2767,9 +2780,6 @@ static void vfio_ap_mdev_hot_plug_cfg(stDECLARE_BITMAP (apm_filtered,AP_DEVICES );bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false; -mutex_lock (&matrix_mdev->kvm->lock); -mutex_lock (&matrix_dev->mdevs_lock); - filter_adapters =bitmap_intersects (matrix_mdev->matrix.apm, matrix_mdev->apm_add,AP_DEVICES ); filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
@@ -2787,9 +2797,6 @@ static void vfio_ap_mdev_hot_plug_cfg(stvfio_ap_mdev_update_guest_apcb (matrix_mdev);reset_queues_for_apids (matrix_mdev, apm_filtered); - -mutex_unlock (&matrix_dev->mdevs_lock); -mutex_unlock (&matrix_mdev->kvm->lock); } void vfio_ap_on_scan_complete(struct ap_config_info *new_config_info,
@@ -2800,15 +2807,29 @@ void vfio_ap_on_scan_complete(struct ap_mutex_lock (&matrix_dev->guests_lock);list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { +/* +* The mdevs_lock must be held to access fields within matrix_mdev, +* and kvm->lock must be taken before mdevs_lock to satisfy the lock +* ordering requirement and prevent a lockdep splat. +*/ +if (matrix_mdev->kvm) +mutex_lock (&matrix_mdev->kvm->lock); +mutex_lock (&matrix_dev->mdevs_lock); +if (bitmap_empty (matrix_mdev->apm_add,AP_DEVICES ) &&bitmap_empty (matrix_mdev->aqm_add,AP_DOMAINS ) &&bitmap_empty (matrix_mdev->adm_add,AP_DOMAINS )) -continue ; + goto do_unlock;vfio_ap_mdev_hot_plug_cfg (matrix_mdev);bitmap_clear (matrix_mdev->apm_add,0 ,AP_DEVICES );bitmap_clear (matrix_mdev->aqm_add,0 ,AP_DOMAINS );bitmap_clear (matrix_mdev->adm_add,0 ,AP_DOMAINS ); + +do_unlock: +mutex_unlock (&matrix_dev->mdevs_lock); +if (matrix_mdev->kvm) +mutex_unlock (&matrix_mdev->kvm->lock); }mutex_unlock (&matrix_dev->guests_lock);
Greg Kroah-Hartman
maintainerPATCH 105/1376 s390/vfio-ap: Fix hot-unplug skipped when last AP adapter or domain removed
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 917f509bfb88048094dbb85c4e9dbc4d6fe4a886 upstream.
The vfio_ap_mdev_hot_unplug_cfg() function uses the return value of bitmap_andnot() to determine whether the guest APCB needs to be updated. However, bitmap_andnot() returns false when the resulting destination bitmap is empty. This means that if the only adapter, domain or control domain assigned to an mdev is removed from the host's AP configuration, the bit is correctly cleared from the shadow APCB, but bitmap_andnot() returns false because the result is an empty bitmap. Consequently, do_hotplug remains 0 and vfio_ap_mdev_update_guest_apcb() is never called, leaving the KVM guest with stale hardware access to the unplugged AP devices.
Fix this by replacing the bitmap_andnot() return value check with bitmap_intersects() to determine whether the shadow APCB actually overlaps with the removal mask. If there is an intersection, call bitmap_andnot() solely for its side effect of clearing the bits, then unconditionally set do_hotplug to trigger the guest APCB update.
--- drivers/s390/crypto/vfio_ap_ops.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +17 -13
@@ -2505,24 +2505,28 @@ static void vfio_ap_mdev_hot_unplug_cfg(unsigned long *aqrem, unsigned long *cdrem) { - int do_hotplug = 0; + bool do_hotplug = false; -if (!bitmap_empty (aprem,AP_DEVICES )) { - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.apm, - matrix_mdev->shadow_apcb.apm, - aprem,AP_DEVICES ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.apm, aprem,AP_DEVICES )) { +bitmap_andnot (matrix_mdev->shadow_apcb.apm, + matrix_mdev->shadow_apcb.apm, + aprem,AP_DEVICES ); + do_hotplug = true; } -if (!bitmap_empty (aqrem,AP_DOMAINS )) { - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.aqm, - matrix_mdev->shadow_apcb.aqm, - aqrem,AP_DEVICES ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.aqm, aqrem,AP_DOMAINS )) { +bitmap_andnot (matrix_mdev->shadow_apcb.aqm, + matrix_mdev->shadow_apcb.aqm, + aqrem,AP_DOMAINS ); + do_hotplug = true; } -if (!bitmap_empty (cdrem,AP_DOMAINS )) - do_hotplug |=bitmap_andnot (matrix_mdev->shadow_apcb.adm, - matrix_mdev->shadow_apcb.adm, - cdrem,AP_DOMAINS ); +if (bitmap_intersects (matrix_mdev->shadow_apcb.adm, cdrem,AP_DOMAINS )) { +bitmap_andnot (matrix_mdev->shadow_apcb.adm, + matrix_mdev->shadow_apcb.adm, + cdrem,AP_DOMAINS ); + do_hotplug = true; + }if (do_hotplug)vfio_ap_mdev_update_guest_apcb (matrix_mdev);
Greg Kroah-Hartman
maintainerPATCH 106/1376 s390/vfio-ap: Fix NULL deref in status_show() during queue probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit dd6f4ef6f8a37412909ad787c837332fb070159c upstream.
When vfio_ap_mdev_probe_queue() creates the sysfs attribute group, the queue's driver data has not yet been set. A concurrent read of the 'status' attribute can therefore call dev_get_drvdata() and get NULL, which is then passed directly to vfio_ap_mdev_for_queue() where q->apqn is unconditionally dereferenced, causing a NULL pointer dereference.
Fix this by acquiring the update locks before calling sysfs_create_group(). The status_show() function acquires guests_lock before reading the driver data, so any concurrent read will block until after dev_set_drvdata() has been called and the update locks are released.
As a bonus, the APQN no longer needs to be read from the queue struct after allocation — it can be read directly from apdev before allocation and stored in a local variable, which is then assigned to q->apqn once the allocation succeeds.
--- drivers/s390/crypto/vfio_ap_ops.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +29 -4
@@ -2261,6 +2261,23 @@ static ssize_t status_show(struct devicemutex_lock (&matrix_dev->mdevs_lock); q =dev_get_drvdata (&apdev->device); + +/* +* Make sure the drvdata has been set before proceeding. There is a +* possibility that the drvdata was not set if the vfio_ap_queue object +* could not be allocated when the queue device was probed. In that case, +* the locks used in vfio_ap_mdev_probe_queue() are released prior to +* removing the sysfs status attribute to avoid a lockdep +* splat. That opens a very small window where the status attribute is +* still available without the vfio_ap_queue object having been +* stored in the device drvdata. In that case, indicate the queue is not +* assigned. +*/ +if (!q) { + nchars =sysfs_emit (buf,"%s\n" ,AP_QUEUE_UNASSIGNED ); + goto done; + } + matrix_mdev =vfio_ap_mdev_for_queue (q);/* If the queue is assigned to the matrix mediated device, then
@@ -2288,6 +2305,7 @@ static ssize_t status_show(struct device AP_QUEUE_UNASSIGNED); } +done:mutex_unlock (&matrix_dev->mdevs_lock);return nchars;
@@ -2361,14 +2379,17 @@ void vfio_ap_mdev_unregister(void)int vfio_ap_mdev_probe_queue (struct ap_device *apdev) { -int ret; +int ret, apqn;struct vfio_ap_queue *q;DECLARE_BITMAP (apm_filtered,AP_DEVICES );struct ap_matrix_mdev *matrix_mdev; + apqn =to_ap_queue (&apdev->device)->qid; + matrix_mdev =get_update_locks_by_apqn (apqn); + ret =sysfs_create_group (&apdev->device.kobj, &vfio_queue_attr_group);if (ret) -return ret; + goto err_release_locks; q =kzalloc (sizeof (*q),GFP_KERNEL );if (!q) {
@@ -2376,11 +2397,10 @@ int vfio_ap_mdev_probe_queue(struct ap_d goto err_remove_group; } - q->apqn =to_ap_queue (&apdev->device)->qid; + q->apqn = apqn; q->saved_isc =VFIO_AP_ISC_INVALID ;memset (&q->reset_status,0 ,sizeof (q->reset_status));INIT_WORK (&q->reset_work, apq_reset_check); - matrix_mdev =get_update_locks_by_apqn (q->apqn);if (matrix_mdev) {vfio_ap_mdev_link_queue (matrix_mdev, q);
@@ -2409,8 +2429,13 @@ done:return ret; err_remove_group: +release_update_locks_for_mdev (matrix_mdev);sysfs_remove_group (&apdev->device.kobj, &vfio_queue_attr_group);return ret; + +err_release_locks: +release_update_locks_for_mdev (matrix_mdev); +return ret; }void vfio_ap_mdev_remove_queue (struct ap_device *apdev)
Greg Kroah-Hartman
maintainerPATCH 107/1376 s390/vfio-ap: fix potential use of uninitialized apm_filtered bitmap
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit bf09b9d7cd7890bc3a3b7eb63d5ece15f88bfde7 upstream.
The DECLARE_BITMAP(apm_filtered, AP_DEVICES) macro allocates the bitmap on the stack without zero-initializing it.
In vfio_ap_mdev_hot_plug_cfg(), the vfio_ap_mdev_filter_matrix() function is only called to initialize and populate apm_filtered if either filter_adapters or filter_domains is true. If the hot plug configuration change only adds control domains (meaning filter_cdoms is true, but filter_adapters and filter_domains are both false), vfio_ap_mdev_filter_matrix() is bypassed.
Consequently, apm_filtered is passed to reset_queues_for_apids() with uninitialized stack garbage. This can cause reset_queues_for_apids() to interpret arbitrary stack garbage bits as valid APIDs to reset, potentially performing unintended guest hardware queue resets.
Fix this by zero-initializing the apm_filtered bitmap at the beginning of vfio_ap_mdev_hot_plug_cfg() using bitmap_zero().
--- drivers/s390/crypto/vfio_ap_ops.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +9 -0
@@ -2809,6 +2809,15 @@ static void vfio_ap_mdev_hot_plug_cfg(stDECLARE_BITMAP (apm_filtered,AP_DEVICES );bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false; +/* +* Zero out the apm_filtered bitmap in case there are no adapters or +* domains to be added, but only control domains. In that case, +* vfio_ap_mdev_filter_matrix() - which initializes apm_filtered - will +* not get called and the reset_queues_for_apids will crash because it +* will access an uninitialized bitmap. +*/ +bitmap_zero (apm_filtered,AP_DEVICES ); + filter_adapters =bitmap_intersects (matrix_mdev->matrix.apm, matrix_mdev->apm_add,AP_DEVICES ); filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
Greg Kroah-Hartman
maintainerPATCH 108/1376 s390/vfio-ap: Fix required lock not held during update of ap_matrix_mdev object
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Krowiak <[email protected]>
commit 5883528250be57fa92270459b33603ff52de0a91 upstream.
In the vfio_ap_mdev_cfg_add function, the apm_add, aqm_add and adm_add fields of an ap_matrix_mdev object fields are modified while not holding the matrix_dev->mdevs_lock. This lock must be held while making these to guard against a race condition with another caller that may be concurrently modifying these fields or any of the fields in the matrix_mdev->matrix.
--- drivers/s390/crypto/vfio_ap_ops.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +8 -0
@@ -2737,12 +2737,20 @@ static void vfio_ap_mdev_cfg_add(unsignevfio_ap_filter_apid_by_qtype (apm_add, aqm_add);list_for_each_entry (matrix_mdev, &matrix_dev->mdev_list, node) { +/* +* The mdevs_lock must be held in order to access fields +* within matrix_mdev +*/ +mutex_lock (&matrix_dev->mdevs_lock); +bitmap_and (matrix_mdev->apm_add, matrix_mdev->matrix.apm, apm_add,AP_DEVICES );bitmap_and (matrix_mdev->aqm_add, matrix_mdev->matrix.aqm, aqm_add,AP_DOMAINS );bitmap_and (matrix_mdev->adm_add, matrix_mdev->matrix.adm, adm_add,AP_DEVICES ); + +mutex_unlock (&matrix_dev->mdevs_lock); } }
Greg Kroah-Hartman
maintainerPATCH 109/1376 mtd: afs: validate v2 image info bounds
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e9290031f736e99ad17c25c00311c92c266843b7 upstream.
The AFS v2 parser uses footer[8] to locate the image information block inside the current erase block, then uses the image information region_count to walk entries from a fixed local array. The footer offset and region count come from flash contents and are not checked against the erase block or the local image-info array before use.
Reject v2 entries whose image information offset would underflow the erase block calculation, and reject region counts that cannot fit in the local image-info array before walking region entries.
--- drivers/mtd/parsers/afs.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/mtd/parsers/afs.c +7 -0
@@ -235,6 +235,9 @@ static int afs_parse_v2_partition(structpr_debug ("Parsing v2 partition @%08x-%08x\n" , off, off + mtd->erasesize); +if (mtd->erasesize <sizeof (footer)) +return -EINVAL ; +/* First read the footer */ ptr = off + mtd->erasesize -sizeof (footer); ret =mtd_read (mtd, ptr,sizeof (footer), &sz, (u_char *)footer);
@@ -245,6 +248,8 @@ static int afs_parse_v2_partition(struct } name = (char *) &footer[0 ]; version = footer[9 ]; +if (footer[8 ] > mtd->erasesize -sizeof (footer)) +return -EINVAL ; ptr = off + mtd->erasesize -sizeof (footer) - footer[8 ]; pr_debug("found image \"%s\", version %08x, info @%08x\n",
@@ -278,6 +283,8 @@ static int afs_parse_v2_partition(struct entrypoint = imginfo[pad]; attributes = imginfo[pad+1 ]; region_count = imginfo[pad+2 ]; +if (region_count > (ARRAY_SIZE (imginfo) - pad -3 ) /4 ) +return -EINVAL ; block_start = imginfo[20 ]; block_end = imginfo[21 ];
Greg Kroah-Hartman
maintainerPATCH 110/1376 mtd: mtdoops: free page bitmap when the backing MTD is removed
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 956e7da12c114f13c63d126ab1d79c3b6a819060 upstream.
mtdoops_notify_add() allocates oops_page_used when the configured MTD device is registered. mtdoops_notify_remove() detaches from that device but leaves the bitmap allocated. If the same MTD device is later registered again, the add path allocates a new bitmap and overwrites the old pointer, leaking one vmalloc allocation per remove/add cycle.
This is only visible when the backing MTD device can disappear and be registered again while mtdoops remains loaded, so the usual static MTD case does not expose it.
Free the bitmap after unregistering the dumper and flushing the pending workers, then clear the pointer and page count before a later attach can allocate fresh state. Clearing the pointer also keeps the module exit path from freeing the same bitmap a second time after a remove event.
--- drivers/mtd/mtdoops.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/mtd/mtdoops.c +3 -0
@@ -393,6 +393,9 @@ static void mtdoops_notify_remove(struct cxt->mtd =NULL ;flush_work (&cxt->work_erase);flush_work (&cxt->work_write); +vfree (cxt->oops_page_used); + cxt->oops_page_used =NULL ; + cxt->oops_pages =0 ; }
Greg Kroah-Hartman
maintainerPATCH 111/1376 mtd: rawnand: validate ONFI extended parameter page sections
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e5e415262330bd70f983e091d8919d9dcd99e475 upstream.
nand_flash_detect_ext_param_page() allocates the length declared by the ONFI parameter page, then treats the data as a fixed header followed by variable-length sections. It reads that header and advances over sections without first proving that the fixed page and each current section fit in the allocation.
Reject pages shorter than the fixed header, track the remaining variable area while walking sections, and require the ECC section to contain every field read from struct onfi_ext_ecc_info. Use device-scoped diagnostics that identify the malformed ONFI section.
--- drivers/mtd/nand/raw/nand_onfi.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/mtd/nand/raw/nand_onfi.c +25 -2
@@ -35,16 +35,21 @@ static int nand_flash_detect_ext_param_p struct nand_onfi_params *p) {struct nand_device *base = &chip->base; +struct mtd_info *mtd =nand_to_mtd (chip);struct nand_ecc_props requirements;struct onfi_ext_param_page *ep;struct onfi_ext_section *s;struct onfi_ext_ecc_info *ecc; +size_t remaining, section_len;uint8_t *cursor;int ret;int len;int i; len =le16_to_cpu (p->ext_param_page_length) *16 ; +if (len <sizeof (*ep)) +return -EINVAL ; + ep =kmalloc (len,GFP_KERNEL );if (!ep)return -ENOMEM ;
@@ -77,11 +82,29 @@ static int nand_flash_detect_ext_param_p/* find the ECC section. */ cursor = (uint8_t *)(ep +1 ); + remaining = len -sizeof (*ep);for (i =0 ; i <ONFI_EXT_SECTION_MAX ; i++) { s = ep->sections + i; -if (s->type ==ONFI_SECTION_TYPE_2 ) + section_len = s->length *16 ; +if (section_len > remaining) { +dev_dbg (&mtd->dev, +"ONFI extended parameter section %d exceeds page\n" , + i); + goto ext_out; + } + +if (s->type ==ONFI_SECTION_TYPE_2 ) { +if (section_len <sizeof (*ecc)) { +dev_dbg (&mtd->dev, +"ONFI extended parameter ECC section %d is too short\n" , + i); + goto ext_out; + }break ; - cursor += s->length *16 ; + } + + cursor += section_len; + remaining -= section_len; }if (i ==ONFI_EXT_SECTION_MAX ) {pr_debug ("We can not find the ECC section.\n" );
Greg Kroah-Hartman
maintainerPATCH 112/1376 batman-adv: fix stale receive device on merged fragments
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit ad46c907d7d9975a285c1e89a4adde652eaa93f5 upstream.
Fragment reassembly reuses the skb from the highest-numbered buffered fragment as the merged packet. When that fragment was received on a hard interface which is deleted before the chain completes, the merged skb can re-enter the receive path with a stale skb->dev and skb_iif.
batadv_batman_skb_recv() passes such merged packets through the normal receive handlers again. DAT and bridge loop avoidance both derive the ARP header length from skb->dev, so they can dereference the freed net_device before the packet reaches the local mesh interface.
Refresh the receive device metadata from the current receive device before running the packet handlers. This keeps internally reinjected merged fragments consistent with the normal receive path after hard interface teardown.
--- net/batman-adv/main.c | 4 ++++ 1 file changed, 4 insertions(+)
net/batman-adv/main.c +4 -0
@@ -458,6 +458,10 @@ int batadv_batman_skb_recv(struct sk_bufif (!skb) goto err_put; +/* Merged fragments re-enter here with reused skb metadata. */ + skb->dev = dev; + skb->skb_iif = dev->ifindex; +/* packet should hold at least type and version */ if (unlikely (!pskb_may_pull (skb,2 ))) goto err_free;
Greg Kroah-Hartman
maintainerPATCH 113/1376 batman-adv: mcast: ensure unshared skb for multicast packets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 82bf207f48ebb7a38157f1d91dac884fc9b8cfd8 upstream.
When a packet is transmitted via a batman-adv interface and has already enough room for the header then nothing will make sure that the skbuff is unshared. But it is not allowed to modify a currently shared skbuff.
Always make sure that the pskb_expand_head() is not only called for a too small header but also for shared skbuffs.
--- net/batman-adv/multicast_forw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/batman-adv/multicast_forw.c +1 -2
@@ -1100,8 +1100,7 @@ static int batadv_mcast_forw_expand_headreturn -EINVAL ; } -if (skb_headroom (skb) < hdr_size && -pskb_expand_head (skb, hdr_size,0 ,GFP_ATOMIC ) <0 ) +if (skb_cow (skb, hdr_size) <0 )return -ENOMEM ;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 114/1376 batman-adv: mcast: linearize skbuff for packet generation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 6a30a59e2660afd03c975f1b8eae6a2301161197 upstream.
batadv_mcast_forw_packet() and batadv_mcast_forw_scrape() is not only called (indirectly) by the unsharing+linearizing batadv_recv_mcast_packet() handler. When it is called (indirectly) by batadv_mcast_forw_mcsend() then it will be unshared but not linearized. The SKB_LINEAR_ASSERT() can therefore cause a fatal BUG().
The linearization should happen during the expansion of the head because the scrape function can be hit already during the initial batadv_mcast_forw_mode() selection code:
* batadv_interface_tx
* batadv_mcast_forw_mode
* batadv_mcast_forw_mode_by_count()
* batadv_mcast_forw_push()
-> calls batadv_mcast_forw_expand_head() before everything else
* batadv_mcast_forw_push_tvlvs()
* batadv_mcast_forw_push_dests()
* batadv_mcast_forw_push_adjust_padding()
* batadv_mcast_forw_scrape()
--- net/batman-adv/multicast_forw.c | 4 ++++ 1 file changed, 4 insertions(+)
net/batman-adv/multicast_forw.c +4 -0
@@ -1103,6 +1103,10 @@ static int batadv_mcast_forw_expand_headif (skb_cow (skb, hdr_size) <0 )return -ENOMEM ; +/* batadv_mcast_forw_scrape() + batadv_mcast_forw_packet() require linearized skb */ +if (skb_linearize (skb) <0 ) +return -ENOMEM ; +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 115/1376 batman-adv: dat: avoid unaligned fault in IP extraction
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 0121afa52cdb88cfb4d5d7bd126a23a9100121d8 upstream.
Independent of the alignment of the ARP packet in the SKB, either the batadv_arp_ip_src or the batadv_arp_ip_dst will have an unaligned access (on HW without native unaligned read support).
Use get_unaligned() to handle this properly on all architectures.
--- net/batman-adv/distributed-arp-table.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/batman-adv/distributed-arp-table.c +6 -2
@@ -250,7 +250,10 @@ static u8 *batadv_arp_hw_src(struct sk_b*/ static __be32 batadv_arp_ip_src (struct sk_buff *skb,int hdr_size) { -return *(__force __be32 *)(batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ); +u8 *src =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ; +__be32 *ip = (__force __be32 *)src; + +return get_unaligned (ip); }/**
@@ -275,8 +278,9 @@ static u8 *batadv_arp_hw_dst(struct sk_bstatic __be32 batadv_arp_ip_dst (struct sk_buff *skb,int hdr_size) {u8 *dst =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN *2 +4 ; +__be32 *ip = (__force __be32 *)dst; -return *(__force __be32 *)dst; +return get_unaligned (ip); }/**
Greg Kroah-Hartman
maintainerPATCH 116/1376 batman-adv: bla: fix freeing of claims on meshif deletion
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 8d128c932bced74e3b1625ba3d7c78ef122a88a7 upstream.
When the mesh interface is getting deleted, then batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could make sure that all claims gets removed. But this function is only executed when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is always setting it to NULL before it is (indirectly) called, it was never actually executed.
But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the moment too fragile because the BLA code is not handling the rehashing in batadv_bla_update_orig_address(). The stored backbone address doesn't have to be the one actually used for the hash bucket selection during the initial adding of the backbone. The batadv_handle_unclaim() can therefore fail to find the respective backbone for the unclaim and then stop the deletion.
But the actual backbone_gw object is not needed for the unclaim because all relevant information is always provided by the caller. And the check for the existence of the backbone_gw doesn't provide any additional security check for the deletion of a claim.
--- net/batman-adv/bridge_loop_avoidance.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +1 -9
@@ -941,26 +941,18 @@ static bool batadv_handle_unclaim(struct const u8 *backbone_addr, const u8 *claim_addr, unsigned short vid) { - struct batadv_bla_backbone_gw *backbone_gw; - /* unclaim in any case if it is our own */ if (primary_if && batadv_compare_eth(backbone_addr, primary_if->net_dev->dev_addr)) batadv_bla_send_claim(bat_priv, claim_addr, vid, BATADV_CLAIM_TYPE_UNCLAIM); - backbone_gw =batadv_backbone_hash_find (bat_priv, backbone_addr, vid); - -if (!backbone_gw) -return true; -/* this must be an UNCLAIM frame */ batadv_dbg (BATADV_DBG_BLA , bat_priv,"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n" , __func__, - claim_addr,batadv_print_vid (vid), backbone_gw->orig); + claim_addr,batadv_print_vid (vid), backbone_addr);batadv_bla_del_claim (bat_priv, claim_addr, vid); -batadv_backbone_gw_put (backbone_gw);return true; }
Greg Kroah-Hartman
maintainerPATCH 117/1376 batman-adv: bla: prevent CRC corruptions after claim flush
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 89f3502ff6878798be96461b2eebd64ba3c3874c upstream.
When batadv_bla_del_backbone_claims() tried to remove all claims of a backbone, it sets the CRC to 0. It assumes that the it had the last reference of the claims because batadv_claim_release() (which runs after the last reference was released), is XORing the crc16 of the claim address with the backbone CRC.
If there would be a parallel holder of any of these references, it could happen that the backbone CRC is (0 ^ crc16(delayed_released_claim)). Which is the wrong starting point for the new claims it may receive when the remote answers the claim request from batadv_bla_send_request().
This reinitializations can be completely dropped to avoid this problem. batadv_claim_release() will take care of fixing the backbone CRC.
--- net/batman-adv/bridge_loop_avoidance.c | 5 ----- 1 file changed, 5 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +0 -5
@@ -323,11 +323,6 @@ batadv_bla_del_backbone_claims(struct ba }spin_unlock_bh (list_lock); } - -/* all claims gone, initialize CRC */ -spin_lock_bh (&backbone_gw->crc_lock); - backbone_gw->crc =BATADV_BLA_CRC_INIT ; -spin_unlock_bh (&backbone_gw->crc_lock); }/**
Greg Kroah-Hartman
maintainerPATCH 118/1376 clk: qcom: gcc-msm8916: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit c5339edc6abb601ea10df910ea0b1592fa1016f3 upstream.
According to the APQ8016E TRM, the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8916.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8916.c +3 -2
@@ -1589,9 +1589,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .parent_data = &(const struct clk_parent_data ){
Greg Kroah-Hartman
maintainerPATCH 119/1376 clk: qcom: gcc-msm8939: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit fc611445b021262b0d4ace6f716a360663816287 upstream.
MSM8939 is similar to MSM8916, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8939.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8939.c +3 -2
@@ -1929,9 +1929,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .ops = &clk_branch2_ops,
Greg Kroah-Hartman
maintainerPATCH 120/1376 clk: rockchip: rk3588: Dont change PLL rates when setting dclk_vop2_src
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Stuebner <[email protected]>
commit 13b10571cc353448275365ede1a5396d20dfe839 upstream.
dclk_vop2_src currently has the CLK_SET_RATE_PARENT flag set, which is very different from dclk_vop0_src or dclk_vop1_src, which don't have it.
With this flag in dclk_vop2_src, actually setting the clock then results in a lot of other peripherals breaking, because setting the rate results in the PLL source getting changed:
[ 14.898718] clk_core_set_rate_nolock: setting rate for dclk_vop2 to 152840000 [ 15.155017] clk_change_rate: setting rate for pll_gpll to 1680000000
[ clk adjusting every gpll user ]
This includes possibly the other vops, i2s, spdif and even the uarts. Among other possible things, this breaks the uart console on a board I use. Sometimes it recovers later on, but there will be a big block of garbled output for a while at least.
Shared PLLs should not be changed by individual users, so drop this flag from dclk_vop2_src.
--- drivers/clk/rockchip/clk-rk3588.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/rockchip/clk-rk3588.c +1 -1
@@ -2113,7 +2113,7 @@ static struct rockchip_clk_branch rk3588COMPOSITE (DCLK_VOP1_SRC ,"dclk_vop1_src" , gpll_cpll_v0pll_aupll_p,0 ,RK3588_CLKSEL_CON (111 ),14 ,2 ,MFLAGS ,9 ,5 ,DFLAGS ,RK3588_CLKGATE_CON (52 ),11 ,GFLAGS ), -COMPOSITE (DCLK_VOP2_SRC ,"dclk_vop2_src" , gpll_cpll_v0pll_aupll_p,CLK_SET_RATE_PARENT |CLK_SET_RATE_NO_REPARENT , +COMPOSITE (DCLK_VOP2_SRC ,"dclk_vop2_src" , gpll_cpll_v0pll_aupll_p,CLK_SET_RATE_NO_REPARENT ,RK3588_CLKSEL_CON (112 ),5 ,2 ,MFLAGS ,0 ,5 ,DFLAGS ,RK3588_CLKGATE_CON (52 ),12 ,GFLAGS ), COMPOSITE_NODIV(DCLK_VOP0, "dclk_vop0", dclk_vop0_p,
Greg Kroah-Hartman
maintainerPATCH 121/1376 clk: qcom: gcc-mdm9607: Drop incorrect apss_tcu_clk_src
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 38d06956f60675f906dc3f5b70b3b52103b86a7d upstream.
This clock does not exist on the specified address on MDM9607. Reading/writing the registers always results in 0 or crashes. The math in the frequency table is also broken. GPLL2 on MDM9607 runs at 480 MHz, so:
- F(155000000, P_GPLL2, 6, 0, 0), // 480 MHz/6 = 80 MHz, not 155 MHz
- F(310000000, P_GPLL2, 3, 0, 0), // 480 MHz/3 = 160 MHz, not 310 MHz
Presumably, this definition was mistakenly copied as-is from gcc-msm8916 (which uses 930 MHz for GPLL2). There are no branch consumers of this root clock inside gcc-mdm9607 (notably, gcc_apss_tcu_clk has bimc_ddr_clk_src as parent instead of this clock), so we can just drop it.
It seems like this clock does exist on this SoC on a different address, but since there is no user and reference code for it, it is still better to drop it.
--- drivers/clk/qcom/gcc-mdm9607.c | 35 ----------------------------------- 1 file changed, 35 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -35
@@ -158,20 +158,6 @@ static const struct clk_parent_data gcc_ { .hw = &gpll2.clkr.hw }, }; -static const struct parent_map gcc_xo_gpll0_gpll1_gpll2_map[] = { - {P_XO ,0 }, - {P_GPLL0 ,1 }, - {P_GPLL1 ,2 }, - {P_GPLL2 ,3 }, -}; - -static const struct clk_parent_data gcc_xo_gpll0_gpll1_gpll2[] = { - { .fw_name ="xo" }, - { .hw = &gpll0.clkr.hw }, - { .hw = &gpll1_vote.hw }, - { .hw = &gpll2.clkr.hw }, -}; -static const struct freq_tbl ftbl_apss_ahb_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (50000000 ,P_GPLL0 ,16 ,0 ,0 ),
@@ -674,26 +660,6 @@ static struct clk_rcg2 sdcc2_apps_clk_sr }, }; -static const struct freq_tbl ftbl_gcc_apss_tcu_clk[] = { -F (155000000 ,P_GPLL2 ,6 ,0 ,0 ), -F (310000000 ,P_GPLL2 ,3 ,0 ,0 ), -F (400000000 ,P_GPLL0 ,2 ,0 ,0 ), - { } -}; - -static struct clk_rcg2 apss_tcu_clk_src = { - .cmd_rcgr =0x1207c , - .hid_width =5 , - .parent_map = gcc_xo_gpll0_gpll1_gpll2_map, - .freq_tbl = ftbl_gcc_apss_tcu_clk, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="apss_tcu_clk_src" , - .parent_data = gcc_xo_gpll0_gpll1_gpll2, - .num_parents =4 , - .ops = &clk_rcg2_ops, - }, -}; -static const struct freq_tbl ftbl_gcc_usb_hs_system_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (57140000 ,P_GPLL0 ,14 ,0 ,0 ),
@@ -1511,7 +1477,6 @@ static struct clk_regmap *gcc_mdm9607_cl [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, - [APSS_TCU_CLK_SRC] = &apss_tcu_clk_src.clkr, [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
Greg Kroah-Hartman
maintainerPATCH 122/1376 clk: qcom: gcc-mdm9607: Drop incorrect system_noc_bfdcd_clk_src
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 17784427df923a0573a7ea83f9198456ff1ec1a5 upstream.
This clock does not exist on MDM9607. Reading/writing the registers always results in 0.
Presumably, this definition was mistakenly copied from gcc-msm8916. On MSM8916, this root clock is used for multimedia subsystems (camera, display, video). MDM9607 has none of that, so this clock was probably omitted in the hardware.
There are no users inside gcc-mdm9607, so we can just drop it.
--- drivers/clk/qcom/gcc-mdm9607.c | 13 ------------- 1 file changed, 13 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +0 -13
@@ -240,18 +240,6 @@ static struct clk_rcg2 pcnoc_bfdcd_clk_s }, }; -static struct clk_rcg2 system_noc_bfdcd_clk_src = { - .cmd_rcgr =0x26004 , - .hid_width =5 , - .parent_map = gcc_xo_gpll0_bimc_map, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="system_noc_bfdcd_clk_src" , - .parent_data = gcc_xo_gpll0_bimc, - .num_parents =ARRAY_SIZE (gcc_xo_gpll0_bimc), - .ops = &clk_rcg2_ops, - }, -}; -static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (50000000 ,P_GPLL0 ,16 ,0 ,0 ),
@@ -1450,7 +1438,6 @@ static struct clk_regmap *gcc_mdm9607_cl [BIMC_PLL_VOTE] = &bimc_pll_vote, [BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr, [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr, - [SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr, [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
Greg Kroah-Hartman
maintainerPATCH 123/1376 clk: qcom: gcc-mdm9607: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit 944d0fb38cffe57a1d1ebf82c5c077bad82dcdbb upstream.
MDM9607 is similar to MSM8909, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-mdm9607.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +3 -2
@@ -744,9 +744,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x1004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x1004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .parent_data = &(const struct clk_parent_data ){
Greg Kroah-Hartman
maintainerPATCH 124/1376 clk: qcom: gcc-mdm9607: Fix halt_reg for gcc_apss_axi_clk
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit ca7e6cc30cde4f0cbeff2e205a84bedf431e9156 upstream.
gcc_apss_axi_clk specifies a halt_reg of 0x4601c, but this is already used by gcc_apss_ahb_clk. The correct value according to the downstream driver is 0x46020.
--- drivers/clk/qcom/gcc-mdm9607.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -1
@@ -1414,7 +1414,7 @@ static struct clk_branch gcc_apss_ahb_cl };static struct clk_branch gcc_apss_axi_clk = { - .halt_reg =0x4601c , + .halt_reg =0x46020 , .halt_check =BRANCH_HALT_VOTED , .clkr = { .enable_reg =0x45004 ,
Greg Kroah-Hartman
maintainerPATCH 125/1376 clk: qcom: gcc-mdm9607: Drop incorrect BIMC PLL and related clocks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit e111ddda092ad961870a634e4c9263c10a3e8485 upstream.
The gcc-mdm9607 driver was originally based on gcc-msm8916, but a closer match nowadays is gcc-msm8909. Looking at the differences between gcc-mdm9607 and gcc-msm8909, there is quite some confusion around the definitions for the BIMC PLL.
It turns out the BIMC PLL on MDM9607 is actually an Alpha PLL just like on MSM8909. We can vote for it using BIT(2), which explains why BIT(3) was used for GPLL2.
In practice, the BIMC PLL is exclusively controlled by the RPM firmware and Linux should not touch it. So far, it was defined to model the full clock hierarchy, but even in read-only mode with CLK_GET_RATE_NOCACHE this is problematic since the RPM will silently change the clock parents without notifying Linux about it. The clock framework reads the clock parent only once during boot, so the resulting rates will still be often wrong.
Follow the example of more recent SoCs and drop the BIMC PLL and all remaining related clocks to avoid reporting stale status data. This means we cannot determine the rate of these clocks anymore. This is not a big problem in practice, since these are NoC-related clocks that are independently managed through the interconnect subsystem.
--- drivers/clk/qcom/gcc-mdm9607.c | 125 ----------------------------------------- 1 file changed, 1 insertion(+), 124 deletions(-)
drivers/clk/qcom/gcc-mdm9607.c +1 -124
@@ -26,7 +26,6 @@enum {P_XO , -P_BIMC ,P_GPLL0 ,P_GPLL1 ,P_GPLL2 ,
@@ -121,7 +120,7 @@ static struct clk_alpha_pll gpll2_early .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x45000, - .enable_mask = BIT(3), /* Yeah, apparently it's not 2 */ + .enable_mask = BIT(3), /* BIT(2) is used for BIMC PLL */ .hw.init = &(struct clk_init_data) { .name = "gpll2_early",
@@ -178,68 +177,6 @@ static struct clk_rcg2 apss_ahb_clk_src }, }; -static struct clk_pll bimc_pll = { - .l_reg =0x23004 , - .m_reg =0x23008 , - .n_reg =0x2300c , - .config_reg =0x23010 , - .mode_reg =0x23000 , - .status_reg =0x2301c , - .status_bit =17 , - .clkr.hw.init = &(struct clk_init_data ){ - .name ="bimc_pll" , - .parent_data = &(const struct clk_parent_data ){ - .fw_name ="xo" , - }, - .num_parents =1 , - .ops = &clk_pll_ops, - }, -}; - -static struct clk_regmap bimc_pll_vote = { - .enable_reg =0x45000 , - .enable_mask =BIT (3 ), - .hw.init = &(struct clk_init_data ){ - .name ="bimc_pll_vote" , - .parent_hws = (const struct clk_hw *[]){ &bimc_pll.clkr.hw }, - .num_parents =1 , - .ops = &clk_pll_vote_ops, - }, -}; - -static const struct parent_map gcc_xo_gpll0_bimc_map[] = { - {P_XO ,0 }, - {P_GPLL0 ,1 }, - {P_BIMC ,2 }, -}; - -static const struct clk_parent_data gcc_xo_gpll0_bimc[] = { - { .fw_name ="xo" }, - { .hw = &gpll0.clkr.hw }, - { .hw = &bimc_pll_vote.hw }, -}; - -static const struct freq_tbl ftbl_pcnoc_bfdcd_clk_src[] = { -F (19200000 ,P_XO ,1 ,0 ,0 ), -F (50000000 ,P_GPLL0 ,16 ,0 ,0 ), -F (100000000 ,P_GPLL0 ,8 ,0 ,0 ), - { } -}; - -static struct clk_rcg2 pcnoc_bfdcd_clk_src = { - .cmd_rcgr =0x27000 , - .freq_tbl = ftbl_pcnoc_bfdcd_clk_src, - .hid_width =5 , - .parent_map = gcc_xo_gpll0_bimc_map, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="pcnoc_bfdcd_clk_src" , - .parent_data = gcc_xo_gpll0_bimc, - .num_parents =ARRAY_SIZE (gcc_xo_gpll0_bimc), - .ops = &clk_rcg2_ops, - .flags =CLK_IS_CRITICAL , - }, -}; -static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {F (19200000 ,P_XO ,1 ,0 ,0 ),F (50000000 ,P_GPLL0 ,16 ,0 ,0 ),
@@ -735,8 +672,6 @@ static struct clk_branch gcc_blsp1_ahb_c .enable_mask = BIT(10), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , .ops = &clk_branch2_ops, }, },
@@ -1038,8 +973,6 @@ static struct clk_branch gcc_boot_rom_ah .enable_mask = BIT(7), .hw.init = &(struct clk_init_data ){ .name ="gcc_boot_rom_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , .ops = &clk_branch2_ops, }, },
@@ -1053,9 +986,6 @@ static struct clk_branch gcc_crypto_ahb_ .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_crypto_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1069,9 +999,6 @@ static struct clk_branch gcc_crypto_axi_ .enable_mask = BIT(1), .hw.init = &(struct clk_init_data ){ .name ="gcc_crypto_axi_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1145,9 +1072,6 @@ static struct clk_branch gcc_mss_cfg_ahb .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_mss_cfg_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1175,9 +1099,6 @@ static struct clk_branch gcc_pdm_ahb_clk .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_pdm_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1191,9 +1112,6 @@ static struct clk_branch gcc_prng_ahb_cl .enable_mask = BIT(8), .hw.init = &(struct clk_init_data ){ .name ="gcc_prng_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1206,9 +1124,6 @@ static struct clk_branch gcc_sdcc1_ahb_c .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_sdcc1_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1236,9 +1151,6 @@ static struct clk_branch gcc_sdcc2_ahb_c .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_sdcc2_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1259,19 +1171,6 @@ static struct clk_branch gcc_sdcc2_apps_ }, }; -static struct clk_rcg2 bimc_ddr_clk_src = { - .cmd_rcgr =0x32004 , - .hid_width =5 , - .parent_map = gcc_xo_gpll0_bimc_map, - .clkr.hw.init = &(struct clk_init_data ){ - .name ="bimc_ddr_clk_src" , - .parent_data = gcc_xo_gpll0_bimc, - .num_parents =3 , - .ops = &clk_rcg2_ops, - .flags =CLK_GET_RATE_NOCACHE , - }, -}; -static struct clk_branch gcc_mss_q6_bimc_axi_clk = { .halt_reg =0x49004 , .clkr = {
@@ -1279,9 +1178,6 @@ static struct clk_branch gcc_mss_q6_bimc .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_mss_q6_bimc_axi_clk" , - .parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1295,8 +1191,6 @@ static struct clk_branch gcc_apss_tcu_cl .enable_mask = BIT(1), .hw.init = &(struct clk_init_data ){ .name ="gcc_apss_tcu_clk" , - .parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw }, - .num_parents =1 , .ops = &clk_branch2_ops, }, },
@@ -1310,9 +1204,6 @@ static struct clk_branch gcc_smmu_cfg_cl .enable_mask = BIT(12), .hw.init = &(struct clk_init_data ){ .name ="gcc_smmu_cfg_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1360,9 +1251,6 @@ static struct clk_branch gcc_usb_hs_phy_ .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_usb_hs_phy_cfg_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1375,9 +1263,6 @@ static struct clk_branch gcc_usb_hs_ahb_ .enable_mask = BIT(0), .hw.init = &(struct clk_init_data ){ .name ="gcc_usb_hs_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , - .flags =CLK_SET_RATE_PARENT , .ops = &clk_branch2_ops, }, },
@@ -1406,8 +1291,6 @@ static struct clk_branch gcc_apss_ahb_cl .enable_mask = BIT(14), .hw.init = &(struct clk_init_data ){ .name ="gcc_apss_ahb_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , .ops = &clk_branch2_ops, }, },
@@ -1421,8 +1304,6 @@ static struct clk_branch gcc_apss_axi_cl .enable_mask = BIT(13), .hw.init = &(struct clk_init_data ){ .name ="gcc_apss_axi_clk" , - .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw }, - .num_parents =1 , .ops = &clk_branch2_ops, }, },
@@ -1435,10 +1316,6 @@ static struct clk_regmap *gcc_mdm9607_cl [GPLL1_VOTE] = &gpll1_vote, [GPLL2] = &gpll2.clkr, [GPLL2_EARLY] = &gpll2_early.clkr, - [BIMC_PLL] = &bimc_pll.clkr, - [BIMC_PLL_VOTE] = &bimc_pll_vote, - [BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr, - [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr, [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
Greg Kroah-Hartman
maintainerPATCH 126/1376 i2c: mux: demux-pinctrl: fix OF node leak on kstrdup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
commit 62edb8ca0aa44517cc23cfa26cd8a51f15ea92fe upstream.
of_parse_phandle() takes a reference on the parent node. If a later devm_kstrdup() fails, err_rollback only releases nodes for indices 0..i-1, so the current node is leaked.
of_node_put() the current parent before rolling back.
--- drivers/i2c/muxes/i2c-demux-pinctrl.c | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/muxes/i2c-demux-pinctrl.c +1 -0
@@ -247,6 +247,7 @@ static int i2c_demux_pinctrl_probe(struc props[i].value =devm_kstrdup (&pdev->dev,"ok" ,GFP_KERNEL );if (!props[i].name || !props[i].value) { err = -ENOMEM ; +of_node_put (adap_np); goto err_rollback; } props[i].length =3 ;
Greg Kroah-Hartman
maintainerPATCH 127/1376 ASoC: cs35l33: drain threaded IRQ before runtime suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit e074c12c428c633e079154301207a6079a208583 upstream.
cs35l33_runtime_suspend() currently switches the codec into regcache_cache_only(true) and powers it down without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l33_irq_thread() can still run after suspend has closed off live register access.
A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1/2 after cache_only has been enabled, ignores the regmap_read() failures, and can still drive the AMP_SHORT_RLS, CAL_ERR_RLS, OTE_RLS, and OTW_RLS release paths.
Use disable_irq() before entering cache_only/power-off so any in-flight threaded handler is drained and no new IRQ thread can run during the suspended state. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only warns if devm_request_threaded_irq() fails, track whether the IRQ was actually installed before disabling or re-enabling it.
--- sound/soc/codecs/cs35l33.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l33.c +12 -2
@@ -40,6 +40,7 @@ struct cs35l33_private {struct regmap *regmap;struct gpio_desc *reset_gpio;bool amp_cal; +bool irq_requested;int mclk_int;struct regulator_bulk_data core_supplies[2 ];int num_core_supplies;
@@ -881,6 +882,9 @@ static int __maybe_unused cs35l33_runtim goto err; } +if (cs35l33->irq_requested) +enable_irq (to_i2c_client (dev)->irq); +return 0 ; err:
@@ -900,6 +904,10 @@ static int __maybe_unused cs35l33_runtim/* redo the calibration in next power up */ cs35l33->amp_cal = false; +/* Drain and block the threaded IRQ before cache_only/power-off. */ +if (cs35l33->irq_requested) +disable_irq (to_i2c_client (dev)->irq); +regcache_cache_only (cs35l33->regmap, true);regcache_mark_dirty (cs35l33->regmap); regulator_bulk_disable(cs35l33->num_core_supplies,
@@ -1156,10 +1164,12 @@ static int cs35l33_i2c_probe(struct i2c_ } ret =devm_request_threaded_irq (&i2c_client->dev, i2c_client->irq,NULL , - cs35l33_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , -"cs35l33" , cs35l33); + cs35l33_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , +"cs35l33" , cs35l33);if (ret !=0 )dev_warn (&i2c_client->dev,"Failed to request IRQ: %d\n" , ret); +else + cs35l33->irq_requested = true;/* We could issue !RST or skip it based on AMP topology */ cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
Greg Kroah-Hartman
maintainerPATCH 128/1376 ASoC: cs35l34: drain threaded IRQ before runtime suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 4105a4c0678b2808fc8046b60321b4f1cc7dae75 upstream.
cs35l34_runtime_suspend() currently switches the codec into regcache_cache_only(true), asserts reset low, and powers the device off without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l34_irq_thread() can still run after suspend has removed live hardware access.
A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1..4 after cache_only has been enabled, ignores the regmap_read() failures, and can still execute the PROT_RELEASE_CTL release sequence or the BST fault power-down writes.
Use disable_irq() before entering cache_only/reset-low/power-off so any in-flight threaded handler is drained and no new IRQ thread can run while the device is suspended. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only logs request_threaded_irq() failures and keeps going, track whether the IRQ was actually installed before disabling or re-enabling it.
--- sound/soc/codecs/cs35l34.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l34.c +12 -2
@@ -45,6 +45,7 @@ struct cs35l34_private {int num_core_supplies;int mclk_int;bool tdm_mode; +bool irq_requested;struct gpio_desc *reset_gpio;/* Active-low reset GPIO */ };
@@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_ } ret =devm_request_threaded_irq (&i2c_client->dev, i2c_client->irq,NULL , - cs35l34_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , -"cs35l34" , cs35l34); + cs35l34_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , +"cs35l34" , cs35l34);if (ret !=0 )dev_err (&i2c_client->dev,"Failed to request IRQ: %d\n" , ret); +else + cs35l34->irq_requested = true; cs35l34->reset_gpio =devm_gpiod_get_optional (&i2c_client->dev,"reset" ,GPIOD_OUT_LOW );
@@ -1140,6 +1143,9 @@ static int __maybe_unused cs35l34_runtimdev_err (dev,"Failed to restore register cache\n" ); goto err; } + +if (cs35l34->irq_requested) +enable_irq (to_i2c_client (dev)->irq);return 0 ; err:regcache_cache_only (cs35l34->regmap, true);
@@ -1153,6 +1159,10 @@ static int __maybe_unused cs35l34_runtim {struct cs35l34_private *cs35l34 =dev_get_drvdata (dev); +/* Drain and block the threaded IRQ before cache_only/power-off. */ +if (cs35l34->irq_requested) +disable_irq (to_i2c_client (dev)->irq); +regcache_cache_only (cs35l34->regmap, true);regcache_mark_dirty (cs35l34->regmap);
Greg Kroah-Hartman
maintainerPATCH 129/1376 ASoC: fsl: mpc5200-i2s: Free DMA resources on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 3a89ddcf0c3d9a068631e8c24d5c9e81d1e6512a upstream.
mpc5200_audio_dma_create() creates the DMA resources before registering the component. If snd_soc_register_component() fails, the function returns directly and leaves the DMA resources allocated.
Call mpc5200_audio_dma_destroy() before returning from this error path.
--- sound/soc/fsl/mpc5200_psc_i2s.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/fsl/mpc5200_psc_i2s.c +1 -0
@@ -170,6 +170,7 @@ static int psc_i2s_of_probe(struct platf psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));if (rc !=0 ) {pr_err ("Failed to register DAI\n" ); +mpc5200_audio_dma_destroy (op);return rc; }
Greg Kroah-Hartman
maintainerPATCH 130/1376 ASoC: hdac_hda: Fix hlink refcount leak on component registration failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 6ad4892c4f5cb437a928a02f5b7d37d496aa9268 upstream.
hdac_hda_dev_probe() gets the HDA link with snd_hdac_ext_bus_link_get() before registering the ASoC component. If component registration fails, the function returns without dropping the link reference.
Always call snd_hdac_ext_bus_link_put() after the registration attempt so the reference taken during probe is balanced on both success and failure.
--- sound/soc/codecs/hdac_hda.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
sound/soc/codecs/hdac_hda.c +1 -3
@@ -643,10 +643,8 @@ static int hdac_hda_dev_probe(struct hda &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); -if (ret <0 ) { +if (ret <0 )dev_err (&hdev->dev,"%s: failed to register HDA codec %d\n" , __func__, ret); -return ret; - }snd_hdac_ext_bus_link_put (hdev->bus, hlink);
Greg Kroah-Hartman
maintainerPATCH 131/1376 AsoC: intel: sst: fix PCI device reference leak on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 016f29997ebd29d6ab59c8162ce0e7f73bd1e517 upstream.
intel_sst_probe() takes a reference to the PCI device with pci_dev_get(). If sst_platform_get_resources() fails afterwards, the probe error path cleans up the driver context but does not drop the PCI device reference.
Add a pci_dev_put() error path for failures after pci_dev_get().
--- sound/soc/intel/atom/sst/sst_pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/intel/atom/sst/sst_pci.c +3 -1
@@ -140,13 +140,15 @@ static int intel_sst_probe(struct pci_de sst_drv_ctx->pci =pci_dev_get (pci); ret =sst_platform_get_resources (sst_drv_ctx);if (ret <0 ) - goto do_free_drv_ctx; + goto do_put_pci;pci_set_drvdata (pci, sst_drv_ctx);sst_configure_runtime_pm (sst_drv_ctx);return ret; +do_put_pci: +pci_dev_put (sst_drv_ctx->pci); do_free_drv_ctx:sst_context_cleanup (sst_drv_ctx);dev_err (sst_drv_ctx->dev,"Probe failed with %d\n" , ret);
Greg Kroah-Hartman
maintainerPATCH 132/1376 ASoC: loongson: Fix error handling in ACPI property parsing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Binbin Zhou <[email protected]>
commit 0eb0e3c623ac1da8b85d518043fef7660af7805d upstream.
In loongson_card_parse_acpi(), the return value of device_property_read_string() for the codec-dai-name property was ignored. If the property is missing or invalid, an uninitialized pointer would be used later, potentially leading to undefined behavior.
Fix this by checking the return value and propagating the error appropriately.
--- sound/soc/loongson/loongson_card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
sound/soc/loongson/loongson_card.c +4 -2
@@ -91,7 +91,7 @@ static int loongson_card_parse_acpi(struconst char *codec_dai_name;struct acpi_device *adev;struct device *phy_dev; -int i; +int i, ret;/* fixup platform name based on reference node */ adev =loongson_card_acpi_find_device (card,"cpu" );
@@ -108,7 +108,9 @@ static int loongson_card_parse_acpi(strureturn -ENOENT ;snprintf (codec_name,sizeof (codec_name),"i2c-%s" ,acpi_dev_name (adev)); -device_property_read_string (card->dev,"codec-dai-name" , &codec_dai_name); + ret =device_property_read_string (card->dev,"codec-dai-name" , &codec_dai_name); +if (ret) +return ret;for (i =0 ; i < card->num_links; i++) { loongson_dai_links[i].platforms->name =dev_name (phy_dev);
Greg Kroah-Hartman
maintainerPATCH 133/1376 ASoC: samsung: aries_audio_probe: double of_node_put due to direct assignment without of_node_get
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit fb5d1b1c5f8a920ee697545fa6dee16825085717 upstream.
In aries_audio_probe(), aries_dai[0].platforms->of_node is assigned the same pointer as aries_dai[0].cpus->of_node (from of_parse_phandle) without calling of_node_get(). When the sound card is deregistered, the ASoC framework calls of_node_put() on both cpus->of_node and platforms->of_node, causing a double put on the same node and a refcount underflow.
Add of_node_get(aries_dai[0].cpus->of_node) before the assignment.
--- sound/soc/samsung/aries_wm8994.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/samsung/aries_wm8994.c +1 -0
@@ -658,6 +658,7 @@ static int aries_audio_probe(struct plat goto out; } +of_node_get (aries_dai[0 ].cpus->of_node); aries_dai[0 ].platforms->of_node = aries_dai[0 ].cpus->of_node;/* Set CPU of_node for BT DAI */
Greg Kroah-Hartman
maintainerPATCH 134/1376 iio: adc: max34408: add missing select REGMAP_I2C to Kconfig
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
commit 947f1079074a260ba200419d5cba6b8549d5ac0c upstream.
The Kconfig entry for the MAX34408 is missing a 'select REGMAP_I2C', causing build failures.
--- drivers/iio/adc/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/iio/adc/Kconfig +1 -0
@@ -841,6 +841,7 @@ config MAX1363 config MAX34408 tristate "Maxim max34408/max344089 ADC driver" depends on I2C + select REGMAP_I2C help Say yes here to build support for Maxim max34408/max34409 current sense monitor with 8-bits ADC interface with overcurrent delay/threshold and
Greg Kroah-Hartman
maintainerPATCH 135/1376 iio: adc: pac1921: fix wrong channel used in trigger handler read
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit 3364c56b20c1c496bdb8c8df32f96a9947dbf98e upstream.
pac1921_trigger_handler() walks the enabled channels with iio_for_each_active_channel(), which yields the scan index (bit) of each active channel, while ch is a separate counter used to pack the samples contiguously into the scan buffer.
The register to read was looked up with the packing counter instead of the scan index:
ret = pac1921_read_res(priv, idev->channels[ch].address, &val);
pac1921_channels[] is ordered by scan index, so channels[bit] is the channel that is actually enabled, whereas channels[ch] is merely the ch-th array entry. These coincide only when the enabled channels form a contiguous prefix (e.g. all channels enabled). With a sparse scan mask - for example when only the power channel (scan index 3) is enabled - the handler reads the wrong register (VBUS instead of VPOWER) and pushes it to userspace as the enabled channel's data.
Index the channel array by the scan index (bit) to read the correct register, keeping ch only for contiguous packing into the scan buffer.
--- drivers/iio/adc/pac1921.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/adc/pac1921.c +1 -1
@@ -1020,7 +1020,7 @@ static irqreturn_t pac1921_trigger_handliio_for_each_active_channel (idev, bit) {u16 val; - ret =pac1921_read_res (priv, idev->channels[ch].address, &val); + ret =pac1921_read_res (priv, idev->channels[bit].address, &val);if (ret) goto done;
Greg Kroah-Hartman
maintainerPATCH 136/1376 iio: buffer: Fix potential use-after-free in anonymous buffer release
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lars-Peter Clausen <[email protected]>
commit 6288b593e76eb10329326f2cd51e32557203b9e5 upstream.
An anonymous buffer handle holds a reference to the underlying IIO device. The reference is dropped in the buffer handle's release function. If the device has been removed, either through unbind or hot-unplug, the buffer handle might hold the last reference.
The release function takes the mutex for the buffer using a guard, which means the unlock happens after all the code in the function, including iio_device_put(). If the anonymous buffer holds the last reference this might free both the IIO device and the buffer, which contains the mutex, leading to use-after-free when the mutex is unlocked.
Fix this by using a scoped guard just around the buffer dmabuf list access, making sure the mutex is unlocked before releasing the IIO device.
Version 10 of the patch that introduced this issue used this exact scheme of first unlocking and then dropping the reference [1]. During review it was suggested to use a guard instead, and version 11 made that change [2].
--- drivers/iio/industrialio-buffer.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/iio/industrialio-buffer.c +10 -6
@@ -1599,12 +1599,16 @@ static int iio_buffer_chrdev_release(strwake_up (&buffer->pollq); -guard (mutex)(&buffer->dmabufs_mutex); - -/* Close all attached DMABUFs */ -list_for_each_entry_safe (priv, tmp, &buffer->dmabufs, entry) { -list_del_init (&priv->entry); -iio_buffer_dmabuf_put (priv->attach); +/* +* The mutex must be unlocked before iio_device_put(), which might drop the +* last reference and free the buffer. +*/ + scoped_guard(mutex, &buffer->dmabufs_mutex) { +/* Close all attached DMABUFs */ +list_for_each_entry_safe (priv, tmp, &buffer->dmabufs, entry) { +list_del_init (&priv->entry); +iio_buffer_dmabuf_put (priv->attach); + } }kfree (ib);
Greg Kroah-Hartman
maintainerPATCH 137/1376 iio: buffer: Make IIO DMA fence release RCU-safe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lars-Peter Clausen <[email protected]>
commit 8662e56c31cf23b61ca3d11b516efb94c35b8026 upstream.
The dma_fence documentation states that if a custom release implementation is provided, the dma_fence object must be freed in an RCU-safe way. The current iio_dma_fence implementation uses kfree(), which might result in a use-after-free.
Remove the custom release implementation. This makes the DMA fence core fall back to dma_fence_free(), which calls kfree_rcu() on the fence. This requires that the fence be the first member of struct iio_dma_fence.
Using the default release method for extended DMA fence structures is a common pattern.
--- drivers/iio/industrialio-buffer.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
drivers/iio/industrialio-buffer.c +4 -9
@@ -57,6 +57,10 @@ struct iio_dmabuf_priv { };struct iio_dma_fence { +/* +* Must remain the first member so the default release callback can pass +* the fence directly to dma_fence_free(). +*/ struct dma_fence base;struct iio_dmabuf_priv *priv;struct work_struct work;
@@ -1811,18 +1815,9 @@ iio_buffer_dma_fence_get_driver_name(strreturn "iio" ; } -static void iio_buffer_dma_fence_release (struct dma_fence *fence) -{ -struct iio_dma_fence *iio_fence = - container_of(fence, struct iio_dma_fence, base); - -kfree (iio_fence); -} -static const struct dma_fence_ops iio_buffer_dma_fence_ops = { .get_driver_name = iio_buffer_dma_fence_get_driver_name, .get_timeline_name = iio_buffer_dma_fence_get_driver_name, - .release = iio_buffer_dma_fence_release, }; static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
Greg Kroah-Hartman
maintainerPATCH 138/1376 iio: buffer: Tie IIO dma fence lock lifetime to the fence
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lars-Peter Clausen <[email protected]>
commit f25ec4627d935dedfb5fe83bd2c2678cdcc19611 upstream.
The iio_dma_fence implementation currently uses a lock embedded in the iio_dmabuf_priv. But the iio_dma_fence can outlive the iio_dmabuf_priv, which can cause a use-after-free.
Tie the lifetime of the lock to the lifetime of the fence by embedding them in the same struct.
We can't just hold a reference to the iio_dmabuf_priv from the iio_dma_fence since iio_buffer_dmabuf_release() might sleep and the fence release callback is not allowed to sleep.
Note that the dma_fence framework now has an internal lock that gets used when the passing NULL for lock in dma_fence_init(), but in order to allow this patch to be backportable use an external lock.
--- drivers/iio/industrialio-buffer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/iio/industrialio-buffer.c +4 -5
@@ -47,9 +47,6 @@ struct iio_dmabuf_priv {u64 context; -/* Spinlock used for locking the dma_fence */ -spinlock_t lock; -struct dma_buf_attachment *attach;struct sg_table *sgt;enum dma_data_direction dir;
@@ -62,6 +59,7 @@ struct iio_dma_fence {* the fence directly to dma_fence_free(). */ struct dma_fence base; +spinlock_t lock;/* protects base */ struct iio_dmabuf_priv *priv;struct work_struct work; };
@@ -1690,7 +1688,6 @@ static int iio_buffer_attach_dmabuf(struif (!priv)return -ENOMEM ; -spin_lock_init (&priv->lock); priv->context =dma_fence_context_alloc (1 ); dmabuf =dma_buf_get (fd);
@@ -1871,6 +1868,8 @@ static int iio_buffer_enqueue_dmabuf(str goto err_attachment_put; } +spin_lock_init (&fence->lock); + fence->priv = priv; seqno =atomic_add_return (1 , &priv->seqno);
@@ -1881,7 +1880,7 @@ static int iio_buffer_enqueue_dmabuf(str* the dma_fence. */ dma_fence_init (&fence->base, &iio_buffer_dma_fence_ops, - &priv->lock, priv->context, seqno); + &fence->lock, priv->context, seqno); ret =iio_dma_resv_lock (dmabuf, nonblock);if (ret)
Greg Kroah-Hartman
maintainerPATCH 139/1376 iio: chemical: atlas-sensor: fix PM reference leak in buffer postenable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Moksh Panicker <[email protected]>
commit bcd3f72e26314edfce7eaf8d7160b3119c7b7fed upstream.
atlas_buffer_postenable() acquires a runtime PM reference with pm_runtime_resume_and_get() but returns the result of atlas_set_interrupt() directly. If atlas_set_interrupt() fails, the runtime PM reference is leaked and the device can never autosuspend.
Add pm_runtime_put_autosuspend() on the error path to balance the reference.
--- drivers/iio/chemical/atlas-sensor.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/iio/chemical/atlas-sensor.c +5 -1
@@ -414,7 +414,11 @@ static int atlas_buffer_postenable(strucif (ret)return ret; -return atlas_set_interrupt (data, true); + ret =atlas_set_interrupt (data, true); +if (ret) +pm_runtime_put_autosuspend (&data->client->dev); + +return ret; }static int atlas_buffer_predisable (struct iio_dev *indio_dev)
Greg Kroah-Hartman
maintainerPATCH 140/1376 iio: chemical: atlas-sensor: use iio_trigger_poll_nested() to fix remove UAF
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit be61c8c6252671ecf1fee0ad90f87669e0be1e20 upstream.
The atlas driver requests its hardware data-ready IRQ with devm_request_threaded_irq(); its threaded handler queues an irq_work, atlas_work_handler(), that calls iio_trigger_poll(data->trig).
The IRQ is devm-managed, so free_irq() runs from the devres unwind after atlas_remove() returns without flushing that irq_work. Once a buffer is enabled, conversion-complete IRQs keep firing and queueing it; a pending irq_work can therefore run after the unwind has freed atlas_data/indio_dev and the trigger, when atlas_work_handler() derives the atlas_data pointer via container_of() and dereferences data->trig, a use-after-free.
Call iio_trigger_poll_nested() directly from the threaded handler instead of bouncing through irq_work. free_irq() then drains the threaded handler, closing the window; other iio drivers with a threaded data-ready IRQ do the same (e.g. bmi270).
This issue was found by an in-house static analysis tool.
--- drivers/iio/chemical/atlas-sensor.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/iio/chemical/atlas-sensor.c +1 -12
@@ -13,7 +13,6 @@#include <linux/mutex.h> #include <linux/err.h> #include <linux/irq.h> -#include <linux/irq_work.h> #include <linux/i2c.h> #include <linux/mod_devicetable.h> #include <linux/regmap.h>
@@ -89,7 +88,6 @@ struct atlas_data {struct iio_trigger *trig;const struct atlas_device *chip;struct regmap *regmap; -struct irq_work work;unsigned int interrupt_enabled;/* 96-bit data + 32-bit pad + 64-bit timestamp */ __be32 buffer[6 ]__aligned(8) ;
@@ -443,13 +441,6 @@ static const struct iio_buffer_setup_ops .predisable = atlas_buffer_predisable, }; -static void atlas_work_handler (struct irq_work *work) -{ - struct atlas_data *data = container_of(work, struct atlas_data, work); - -iio_trigger_poll (data->trig); -} -static irqreturn_t atlas_trigger_handler (int irq,void *private) {struct iio_poll_func *pf = private;
@@ -475,7 +466,7 @@ static irqreturn_t atlas_interrupt_handlstruct iio_dev *indio_dev = private;struct atlas_data *data =iio_priv (indio_dev); -irq_work_queue (&data->work); +iio_trigger_poll_nested (data->trig);return IRQ_HANDLED ; }
@@ -673,8 +664,6 @@ static int atlas_probe(struct i2c_client goto unregister_trigger; } -init_irq_work (&data->work, atlas_work_handler); -if (client->irq >0 ) {/* interrupt pin toggles on new conversion */ ret = devm_request_threaded_irq(&client->dev, client->irq,
Greg Kroah-Hartman
maintainerPATCH 141/1376 iio: chemical: sgp30: Handle IAQ thread creation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 1135d6875d2dbda3f6ec718f3421a6ce4378bd63 upstream.
kthread_run() can fail and return an error pointer, but sgp_probe() stores it and returns success, so the device is registered without its IAQ thread and sgp_remove() later passes the error pointer to kthread_stop(). Return the error from probe instead.
--- drivers/iio/chemical/sgp30.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iio/chemical/sgp30.c +3 -0
@@ -548,6 +548,9 @@ static int sgp_probe(struct i2c_client * data->iaq_thread =kthread_run (sgp_iaq_threadfn, data,"%s-iaq" , data->client->name); +if (IS_ERR (data->iaq_thread)) +return dev_err_probe (dev,PTR_ERR (data->iaq_thread), +"failed to start IAQ thread\n" );return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 142/1376 iio: dac: m62332: Fix regulator reference count imbalance
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erick Henrique <[email protected]>
commit a130404ce0b69ca1438126bd81c1985d3b4d2e6f upstream.
m62332_set_value() enables the Vcc regulator on every write of a non-zero value and disables it on every write of zero, without tracking the channel's current state. Because the regulator is reference counted, changing a channel directly from one non-zero value to another enables it more than once, while a later write of zero disables it only once. The reference count never returns to zero and the regulator is left enabled indefinitely.
Only enable the regulator on the transition from zero to non-zero, and only disable it on the transition from non-zero to zero, using the previously stored channel value to detect the edge. Balance the regulator on the I2C error path so the reference count stays consistent if the write fails.
--- drivers/iio/dac/m62332.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/iio/dac/m62332.c +12 -5
@@ -32,6 +32,7 @@ static int m62332_set_value(struct iio_d {struct m62332_data *data =iio_priv (indio_dev);struct i2c_client *client = data->client; +bool enabling, disabling;u8 outbuf[2 ];int res;
@@ -43,7 +44,10 @@ static int m62332_set_value(struct iio_dmutex_lock (&data->mutex); -if (val) { + enabling = val && !data->raw[channel]; + disabling = !val && data->raw[channel]; + +if (enabling) { res =regulator_enable (data->vcc);if (res) goto out;
@@ -52,14 +56,17 @@ static int m62332_set_value(struct iio_d res =i2c_master_send (client, outbuf,ARRAY_SIZE (outbuf));if (res >=0 && res !=ARRAY_SIZE (outbuf)) res = -EIO ; -if (res <0 ) +if (res <0 ) { +if (enabling) +regulator_disable (data->vcc); goto out; + } - data->raw[channel] = val; - -if (!val) +if (disabling)regulator_disable (data->vcc); + data->raw[channel] = val; +mutex_unlock (&data->mutex);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 143/1376 iio: gyro: mpu3050: fix sign of raw angular velocity readings
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit 06fab97602fe400bea843176f485bbac07a668e2 upstream.
The MPU-3050 gyroscope output registers hold 16-bit two's complement values; the angular velocity channels are declared with .sign = 's'. When mpu3050_read_raw() handles IIO_CHAN_INFO_RAW it reads the register via a big-endian regmap_bulk_read() and assigns it with:
*val = be16_to_cpu(raw_val);
be16_to_cpu() yields an unsigned 16-bit quantity, so negative rates (bit 15 set) are reported to userspace as large positive integers (e.g. -1 becomes 65535) instead of the correct negative value.
Cast to s16 before the assignment, matching the temperature channel a few lines above which already handles the sign correctly.
--- drivers/iio/gyro/mpu3050-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/gyro/mpu3050-core.c +1 -1
@@ -356,7 +356,7 @@ static int mpu3050_read_raw(struct iio_d goto out_read_raw_unlock; } - *val =be16_to_cpu (raw_val); + *val = (s16 )be16_to_cpu (raw_val); ret =IIO_VAL_INT ; goto out_read_raw_unlock;
Greg Kroah-Hartman
maintainerPATCH 144/1376 iio: light: cm32181: return zero after writing calibscale
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Giorgi Tchankvetadze <[email protected]>
commit 8756acd30919a3e9f547ea4a1d4b7f7895f4d340 upstream.
The write_raw callback is documented to return 0 on success or a negative error code. However, the IIO_CHAN_INFO_CALIBSCALE case returns 'val' (the user-supplied value) instead of 0.
Fix it by returning 0 on success, matching the behavior of other calibscale implementations in the subsystem.
--- drivers/iio/light/cm32181.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/cm32181.c +1 -1
@@ -370,7 +370,7 @@ static int cm32181_write_raw(struct iio_switch (mask) {case IIO_CHAN_INFO_CALIBSCALE : cm32181->calibscale = val; -return val; +return 0 ;case IIO_CHAN_INFO_INT_TIME : ret =cm32181_write_als_it (cm32181, val2);return ret;
Greg Kroah-Hartman
maintainerPATCH 145/1376 iio: light: gp2ap002: Disable regulators on resume failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
commit a41000ba3a230bed1e422f283486ff8f77fe0d30 upstream.
If enabling VIO fails after VDD has been enabled, runtime resume returns without disabling VDD. Likewise, if device reinitialization fails, both supplies remain enabled. The runtime PM core keeps the device suspended when its resume callback fails, so the supplies must be restored to the suspended state.
Disable the supplies enabled by the callback before returning an error.
--- drivers/iio/light/gp2ap002.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/iio/light/gp2ap002.c +8 -2
@@ -671,7 +671,7 @@ static int gp2ap002_runtime_resume(struc ret =regulator_enable (gp2ap002->vio);if (ret) {dev_err (dev,"failed to enable VIO regulator in resume path\n" ); -return ret; + goto out_disable_vdd; }msleep (20 );
@@ -679,13 +679,19 @@ static int gp2ap002_runtime_resume(struc ret =gp2ap002_init (gp2ap002);if (ret) {dev_err (dev,"re-initialization failed\n" ); -return ret; + goto out_disable_vio; }/* Re-activate the IRQ */ enable_irq (gp2ap002->irq);return 0 ; + +out_disable_vio: +regulator_disable (gp2ap002->vio); +out_disable_vdd: +regulator_disable (gp2ap002->vdd); +return ret; } static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
Greg Kroah-Hartman
maintainerPATCH 146/1376 iio: light: ltrf216a: fix runtime PM reference leak in error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vidhu Sarwal <[email protected]>
commit c132aef0e757a39036b1d40faf0569f2e343b13e upstream.
ltrf216a_get_lux() acquires a runtime PM reference by calling ltrf216a_set_power_state(data, true). However, if ltrf216a_read_data() fails, the function returns immediately without dropping the reference.
This leaves the runtime PM usage count unbalanced, preventing the device from autosuspending after a failed read.
Fix this by releasing the runtime PM reference before returning from the error path.
--- drivers/iio/light/ltrf216a.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iio/light/ltrf216a.c +1 -2
@@ -249,11 +249,10 @@ static int ltrf216a_get_lux(struct ltrf2return ret; greendata =ltrf216a_read_data (data,LTRF216A_ALS_DATA_0 ); +ltrf216a_set_power_state (data, false);if (greendata <0 )return greendata; -ltrf216a_set_power_state (data, false); - lux = greendata * data->info->lux_multiplier *LTRF216A_WIN_FAC ;return lux;
Greg Kroah-Hartman
maintainerPATCH 147/1376 iio: pressure: dps310: fix NULL pointer dereference on ACPI probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rupesh Majhi <[email protected]>
commit 26e9213898fc949923188ef0aeea31fc87708836 upstream.
When the device is enumerated through its ACPI HID (IFX3100), i2c_client_get_device_id() returns NULL: the ACPI-derived client name does not match the driver's i2c_device_id table. dps310_probe() then dereferences that NULL pointer in "iio->name = id->name" and crashes the kernel during probe.
The IIO device name is always "dps310", so set it directly and drop the now-unused device-id lookup.
--- drivers/iio/pressure/dps310.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iio/pressure/dps310.c +1 -2
@@ -845,7 +845,6 @@ static const struct iio_info dps310_infostatic int dps310_probe (struct i2c_client *client) { -const struct i2c_device_id *id =i2c_client_get_device_id (client);struct dps310_data *data;struct iio_dev *iio;int rc;
@@ -858,7 +857,7 @@ static int dps310_probe(struct i2c_clien data->client = client;mutex_init (&data->lock); - iio->name = id->name; + iio->name =DPS310_DEV_NAME ; iio->channels = dps310_channels; iio->num_channels =ARRAY_SIZE (dps310_channels); iio->info = &dps310_info;
Greg Kroah-Hartman
maintainerPATCH 148/1376 iio: pressure: mpl115: Fix runtime PM cleanup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit 0b5e142ced4bcf20532da051934bd694d1bbd470 upstream.
mpl115_probe() enables runtime PM when a shutdown GPIO is present and then returns the result of devm_iio_device_register(). If registration fails, runtime PM remains enabled and autosuspend remains selected.
The same unmanaged runtime PM state is also left behind on driver unbind, as the IIO device registration is managed but the runtime PM setup is not.
Use devm_pm_runtime_enable() so runtime PM is disabled automatically on probe failure and driver unbind, and check pm_runtime_set_active() so setup errors are reported.
Set the autosuspend parameters before enabling runtime PM. Once probe has completed, the driver core queues an idle request for the device, so an explicit pm_runtime_get_noresume()/pm_runtime_put() pair is not needed to start autosuspend.
--- drivers/iio/pressure/mpl115.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/iio/pressure/mpl115.c +7 -4
@@ -203,9 +203,9 @@ int mpl115_probe(struct device *dev, conif (data->shutdown) {/* Enable runtime PM */ -pm_runtime_get_noresume (dev); -pm_runtime_set_active (dev); -pm_runtime_enable (dev); + ret =pm_runtime_set_active (dev); +if (ret) +return ret;/* * As the device takes 3 ms to come up with a fresh
@@ -215,7 +215,10 @@ int mpl115_probe(struct device *dev, con*/ pm_runtime_set_autosuspend_delay (dev,2000 );pm_runtime_use_autosuspend (dev); -pm_runtime_put (dev); + + ret =devm_pm_runtime_enable (dev); +if (ret) +return ret;dev_dbg (dev,"low-power mode enabled" ); }else
Greg Kroah-Hartman
maintainerPATCH 149/1376 iio: srf04: fix pm_runtime handling on probe error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit a40b2e7a17f26e38ab054363c9c7cde149588357 upstream.
When pm_runtime_set_active() fails during probe, the driver logs the error and unregisters the IIO device, but then falls through and still calls pm_runtime_enable() before returning the error.
Since probe returns an error, srf04_remove() is never called, so runtime PM is left enabled without a matching pm_runtime_disable(). This leaks the enable and triggers an "Unbalanced pm_runtime_enable!" warning on a subsequent bind of the device.
Return the error right after unregistering the IIO device so that runtime PM is not enabled on the failure path.
--- drivers/iio/proximity/srf04.c | 1 + 1 file changed, 1 insertion(+)
drivers/iio/proximity/srf04.c +1 -0
@@ -335,6 +335,7 @@ static int srf04_probe(struct platform_dif (ret) {dev_err (data->dev,"pm_runtime_set_active: %d\n" , ret);iio_device_unregister (indio_dev); +return ret; }pm_runtime_enable (data->dev);
Greg Kroah-Hartman
maintainerPATCH 150/1376 iio: temperature: hid-sensor-temperature: switch to non-devm iio_device_register()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
commit 967d066f5334740f656577bc51c381a1bb707b61 upstream.
Avoid using devm_iio_device_register(), as this driver requires explicit error handling and teardown ordering.
With devm_iio_device_register(), IIO device remains registered until the devres cleanup phase. However, driver's remove() callback removes the sensor hub callback and trigger support. This can create a race window where IIO device is still visible and read_raw() requests are issued. These requests might call sensor_hub_input_attr_get_raw_value(), which waits up to 5 seconds for a response from the sensor hub callback that has already been removed.
Add an explicit iio_device_unregister() call in the teardown path to ensure deterministic cleanup, so that userspace can no longer access the device once backend resources begin to be dismantled.
--- drivers/iio/temperature/hid-sensor-temperature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iio/temperature/hid-sensor-temperature.c +2 -1
@@ -243,7 +243,7 @@ static int hid_temperature_probe(structif (ret) goto error_remove_trigger; - ret =devm_iio_device_register (indio_dev->dev.parent, indio_dev); + ret =iio_device_register (indio_dev);if (ret) goto error_remove_callback;
@@ -263,6 +263,7 @@ static void hid_temperature_remove(strucstruct iio_dev *indio_dev =platform_get_drvdata (pdev);struct temperature_state *temp_st =iio_priv (indio_dev); +iio_device_unregister (indio_dev);sensor_hub_remove_callback (hsdev,HID_USAGE_SENSOR_TEMPERATURE );hid_sensor_remove_trigger (indio_dev, &temp_st->common_attributes); }
Greg Kroah-Hartman
maintainerPATCH 151/1376 iio: light: opt4001: Fix power down clearing bits of the wrong register
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
commit 3b2cd82c524c75a2173f2e3f874652a75f81cd1d upstream.
opt4001_power_down() intends to clear the operating mode bits in the CTRL register but reads OPT4001_DEVICE_ID instead of OPT4001_CTRL, so the value written back to CTRL contains device ID bits rather than the current configuration.
Fix and simplify this by using regmap_clear_bits() on the CTRL register directly in the devm action, and drop opt4001_power_down() which has no other users.
--- drivers/iio/light/opt4001.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-)
drivers/iio/light/opt4001.c +4 -23
@@ -222,33 +222,14 @@ static int opt4001_set_conf(struct opt40return ret; } -static int opt4001_power_down (struct opt4001_chip *chip) -{ -struct device *dev = &chip->client->dev; -int ret; -unsigned int reg; - - ret =regmap_read (chip->regmap,OPT4001_DEVICE_ID , ®); -if (ret) { -dev_err (dev,"Failed to read configuration\n" ); -return ret; - } - -/* MODE_OFF is 0x0 so just set bits to 0 */ - reg &= ~OPT4001_CTRL_OPER_MODE_MASK ; - - ret =regmap_write (chip->regmap,OPT4001_CTRL , reg); -if (ret) -dev_err (dev,"Failed to set configuration to power down\n" ); - -return ret; -} -static void opt4001_chip_off_action (void *data) {struct opt4001_chip *chip = data; +int ret; -opt4001_power_down (chip); + ret =regmap_clear_bits (chip->regmap,OPT4001_CTRL ,OPT4001_CTRL_OPER_MODE_MASK ); +if (ret) +dev_err (&chip->client->dev,"Failed to power down\n" ); }static const struct iio_chan_spec opt4001_channels[] = {
Greg Kroah-Hartman
maintainerPATCH 152/1376 iio: light: opt4001: Fix incompatible pointer type passed to div_u64_rem()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
commit afa28741c9a2cf6edb2e41e25ff146a562160bb3 upstream.
div_u64_rem() takes a u32 * for the remainder but is passed val2, which is an int *. There is no functional impact as int and u32 have the same size and representation on all supported architectures and the remainder is always smaller than the divisor, so it fits in the positive range of int. Fix the type mismatch by using a local u32 for the remainder and assigning the result to *val2.
--- drivers/iio/light/opt4001.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iio/light/opt4001.c +3 -2
@@ -173,6 +173,7 @@ static int opt4001_read_lux_value(structu8 crc;u8 calc_crc;u64 lux_raw; +u32 rem;int ret; ret =regmap_read (chip->regmap,OPT4001_LIGHT1_MSB , &light1);
@@ -199,8 +200,8 @@ static int opt4001_read_lux_value(struct lux_raw = lux_raw << exp; lux_raw = lux_raw * chip->chip_info->mul; - *val =div_u64_rem (lux_raw, chip->chip_info->div, val2); - *val2 = *val2 *100 ; + *val =div_u64_rem (lux_raw, chip->chip_info->div, &rem); + *val2 = rem *100 ;return IIO_VAL_INT_PLUS_NANO ; }
Greg Kroah-Hartman
maintainerPATCH 153/1376 iio: light: opt4001: Reject integration times with a non-zero seconds part
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
commit d0f21621f8b2b46661ea066d20705dbf7253db87 upstream.
opt4001_write_raw() only looks at val2 when setting the integration time, so a write such as 1.000600 is silently accepted as 600 us. Return -EINVAL if val is non-zero.
--- drivers/iio/light/opt4001.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iio/light/opt4001.c +3 -0
@@ -269,6 +269,9 @@ static int opt4001_write_raw(struct iio_switch (mask) {case IIO_CHAN_INFO_INT_TIME : +if (val) +return -EINVAL ; + int_time =opt4001_als_time_to_index (val2);if (int_time <0 )return int_time;
Greg Kroah-Hartman
maintainerPATCH 154/1376 iio: light: opt4001: Fix reversed GENMASK() arguments in fault count mask
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
commit d64bfd9f3352b9d9bdeca06de1a0a1c1bd47b896 upstream.
GENMASK(h, l) requires h >= l, but OPT4001_CTRL_FAULT_COUNT is defined as GENMASK(0, 1). The define is currently unused so there is no functional impact, but fix it before anyone builds on it, and add the _MASK suffix for consistency with the neighbouring definitions.
--- drivers/iio/light/opt4001.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/opt4001.c +1 -1
@@ -39,7 +39,7 @@#define OPT4001_CTRL_OPER_MODE_MASK GENMASK(5, 4)#define OPT4001_CTRL_LATCH_MASK GENMASK(3, 3)#define OPT4001_CTRL_INT_POL_MASK GENMASK(2, 2) -#define OPT4001_CTRL_FAULT_COUNT GENMASK(0, 1) +#define OPT4001_CTRL_FAULT_COUNT_MASK GENMASK(1, 0)/* OPT4001 constants */ #define OPT4001_DEVICE_ID_VAL 0x121
Greg Kroah-Hartman
maintainerPATCH 155/1376 KVM: nVMX: Always flush vpid02 on first use
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
commit f0772389413dce9657c7d6950abf3edbbd511356 upstream.
Make sure vpid02 is always flushed on first use by setting last_vpid=0 when allocating vpid02. nested_vmx_transition_tlb_flush() will always detect a VPID change on first VM-Enter after VMXON, because VPID=0 in vmcs12 is not allowed if L1 enables VPID.
This avoids using stale TLB entries from a previous lifetime of the VPID, that might have been associated with a different vCPU (or a completely different VM).
Note that last_vpid is already being initialized as 0 when the vCPU is created, but it is not reset when vpid02 is freed on VMXOFF. Hence, the problem can only occur if L1 does VMXOFF -> VMXON, runs an L2, and KVM happens to reuse a VPID that has TLB entries on the physical CPU.
--- arch/x86/kvm/vmx/nested.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/kvm/vmx/nested.c +10 -0
@@ -1235,6 +1235,9 @@ static void nested_vmx_transition_tlb_fl* is the VPID incorporated into the MMU context. I.e. KVM must assume * that the new vpid12 has never been used and thus represents a new * guest ASID that cannot have entries in the TLB. +* +* Note, last_vpid is initialized as 0, so the first nested VM-Enter +* after VMXON will always flush the TLB to avoid using stale entries. */ if (is_vmenter && vmcs12->virtual_processor_id != vmx->nested.last_vpid) { vmx->nested.last_vpid = vmcs12->virtual_processor_id;
@@ -5343,6 +5346,13 @@ static int enter_vmx_operation(struct kv vmx->nested.vpid02 =allocate_vpid (); +/* +* Clear last_vpid to ensure that the VPID is flushed on the first +* nested VM-Enter. Otherwise, stale TLB entries from a previous life of +* the VPID (e.g. different vCPU or even different VM) could be used. +*/ + vmx->nested.last_vpid =0 ; + vmx->nested.vmcs02_initialized = false; vmx->nested.vmxon = true;
Greg Kroah-Hartman
maintainerPATCH 156/1376 KVM: nVMX: Decouple INVVPID operand checks from flushing of vpid02
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 32912404b4b1ee98400744941c78f019a63d6e8f upstream.
Separate the INVVPID operand checks from the actual flushing of vpid02 so the flushing can be adjusted to do the right thing when vmcs02 was last loaded on a different pCPU, without having to duplicate the logic across multiple case-statements.
Opportunistically let the VM-Fail paths poke out past 80 chars.
No functional change intended.
--- arch/x86/kvm/vmx/nested.c | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-)
arch/x86/kvm/vmx/nested.c +13 -30
@@ -5980,7 +5980,6 @@ static int handle_invvpid(struct kvm_vcpu64 vpid;u64 gla; } operand; -u16 vpid02;int r, gpr_index; if (!(vmx->nested.msrs.secondary_ctls_high &
@@ -6015,8 +6014,15 @@ static int handle_invvpid(struct kvm_vcpreturn kvm_handle_memory_failure (vcpu, r, &e);if (operand.vpid >>16 ) -return nested_vmx_fail (vcpu, -VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID ); +return nested_vmx_fail (vcpu,VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID ); + +if (type !=VMX_VPID_EXTENT_ALL_CONTEXT && !operand.vpid) +return nested_vmx_fail (vcpu,VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID ); + +/* LAM doesn't apply to addresses that are inputs to TLB invalidation. */ +if (type ==VMX_VPID_EXTENT_INDIVIDUAL_ADDR && +is_noncanonical_invlpg_address (operand.gla, vcpu)) +return nested_vmx_fail (vcpu,VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID );/* * Always flush the effective vpid02, i.e. never flush the current VPID
@@ -6024,33 +6030,10 @@ static int handle_invvpid(struct kvm_vcp* VMCS, and so whether or not the current vmcs12 has VPID enabled is * irrelevant (and there may not be a loaded vmcs12). */ - vpid02 =nested_get_vpid02 (vcpu); -switch (type) { -case VMX_VPID_EXTENT_INDIVIDUAL_ADDR : -/* -* LAM doesn't apply to addresses that are inputs to TLB -* invalidation. -*/ -if (!operand.vpid || -is_noncanonical_invlpg_address (operand.gla, vcpu)) -return nested_vmx_fail (vcpu, -VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID ); -vpid_sync_vcpu_addr (vpid02, operand.gla); -break ; -case VMX_VPID_EXTENT_SINGLE_CONTEXT : -case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL : -if (!operand.vpid) -return nested_vmx_fail (vcpu, -VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID ); -vpid_sync_context (vpid02); -break ; -case VMX_VPID_EXTENT_ALL_CONTEXT : -vpid_sync_context (vpid02); -break ; -default : -WARN_ON_ONCE (1 ); -return kvm_skip_emulated_instruction (vcpu); - } +if (type ==VMX_VPID_EXTENT_INDIVIDUAL_ADDR ) +vpid_sync_vcpu_addr (nested_get_vpid02 (vcpu), operand.gla); +else +vpid_sync_context (nested_get_vpid02 (vcpu));/* * Sync the shadow page tables if EPT is disabled, L1 is invalidating
Greg Kroah-Hartman
maintainerPATCH 157/1376 KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 11722439fb206c88e6f31be54173efa9880b4ccb upstream.
Always check and clear KVM_REQ_GET_NESTED_STATE_PAGES when emulating a nested VM-Exit to ensure the request is cleared, even when KVM was built with CONFIG_KVM_HYPERV=n, as KVM subtly relies on the "check" to clear the flag and thus avoid double-mapping the vmcs12 pages, e.g. if KVM manages to bail from VM-Enter without processing the request, and then emulates VMLAUNCH or VMRESUME.
--- arch/x86/kvm/vmx/nested.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/nested.c +3 -2
@@ -4962,8 +4962,9 @@ void nested_vmx_vmexit(struct kvm_vcpu */* trying to cancel vmlaunch/vmresume is a bug */ WARN_ON_ONCE (vmx->nested.nested_run_pending); -#ifdef CONFIG_KVM_HYPERV +/* Note, "checking" the request also clears the request. */ if (kvm_check_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu)) { +#ifdef CONFIG_KVM_HYPERV /* * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map * Enlightened VMCS after migration and we still need to
@@ -4971,8 +4972,8 @@ void nested_vmx_vmexit(struct kvm_vcpu ** the first L2 run. */ (void )nested_get_evmcs_page (vcpu); - }#endif + }/* Service pending TLB flush requests for L2 before switching to L1. */ kvm_service_local_tlb_flush_requests (vcpu);
Greg Kroah-Hartman
maintainerPATCH 158/1376 KVM: nVMX: Service local TLB flushes on failed nested VM-Enter
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
commit 05a0b701d1089fb57beeb8982f23c3bbafe0fa8b upstream.
KVM services local TLB flushes on "full" nested VM-Exits (through __nested_vmx_vmexit()), but not if a nested VM-Enter fails (e.g. due to failed VMCS checks in nested_vmx_enter_non_root_mode()).
However, it is possible that KVM had queued TLB flushes that need to be performed, even if the nested VM-Enter was not successful. For example, if VPID is disabled for L2 (via nested_vmx_transition_tlb_flush(), or if via the MSR load lists, as the SDM says:
If any MSR is being loaded in such a way that would architecturally require a TLB flush, the TLBs are updated so that, after VM entry, the logical processor will not use any translations that were cached before the transition.
The SDM is unclear about when the TLB flush should occur, and whether or not a failed VM entry would flush the TLB, so it is safer to always do the TLB flush in this case.
More concretely, KVM also updates the last VPID L1 used for L2 in nested_vmx_transition_tlb_flush() (i.e. last_vpid), even if the VM entry ultimately fails. With the current code, KVM could miss a TLB flush if L1 changes L2's VPID, then does a failed VM entry followed by a successful one, as the failed VM entry would update last_vpid but not actually flush the TLB. Servicing local TLB flushes on failed VM entries makes sure that the TLB is always flushed when last_vpid is updated.
--- arch/x86/kvm/vmx/nested.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/kvm/vmx/nested.c +8 -0
@@ -3670,6 +3670,14 @@ enum nvmx_vmentry_status nested_vmx_ente vmentry_fail_vmexit_guest_mode:if (vmcs12->cpu_based_vm_exec_control &CPU_BASED_USE_TSC_OFFSETTING ) vcpu->arch.tsc_offset -= vmcs12->tsc_offset; + +/* +* Handle any TLB flush requests that were queued for L2 if KVM made it +* far enough along to switch to L2 context. Note, loading host state +* will generate any flushes for L1 required by VM-Exit. +*/ +kvm_service_local_tlb_flush_requests (vcpu); +leave_guest_mode (vcpu); vmentry_fail_vmexit:
Greg Kroah-Hartman
maintainerPATCH 159/1376 KVM: nVM: Ensure INVVPID is emulated on the correct physical CPU
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <[email protected]>
commit 6d00e67326d831e6e610933a3800712f4ffe6ec1 upstream.
When emulating INVVPID, KVM executes INVVPID on the physical CPU using vpid02 (instead of the L1 assigned VPID), after doing some validations on the operands. However, it is possible that the physical CPU KVM executes INVVPID on is different from the CPU L2 is running on.
For example, in the following scenario:
- L2 runs on CPU #1 and exits to L1 (vmx->nested.vmcs02.cpu=1)
- L1 migrates to CPU #2 and executes INVVPID
- KVM executes INVVPID on CPU #2
- L1 migrates back to CPU #1 and runs L2 (vmx->nested.vmcs02.cpu=1)
The TLB entries on CPU #1 are never invalidated, because INVVPID was executed on CPU #2, and vmcs02 never ran on a different pCPU (i.e. vmx_vcpu_load_vmcs() will *not* request KVM_REQ_TLB_FLUSH).
Ensure that INVVPID is being executed on the same pCPU that L2 last ran on, and if not, fallback to clearing last_vpid=0 to trigger a full VPID flush on the next nested VM-Enter (as KVM will detect L1 using a different VPID for L2). If L2 ends up running on a different pCPU, KVM will flush the TLB anyway through vmx_vcpu_load_vmcs().
--- arch/x86/kvm/vmx/nested.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx/nested.c +10 -1
@@ -5990,6 +5990,7 @@ static int handle_invvpid(struct kvm_vcpu64 gla; } operand;int r, gpr_index; +int cpu; if (!(vmx->nested.msrs.secondary_ctls_high & SECONDARY_EXEC_ENABLE_VPID) ||
@@ -6038,11 +6039,19 @@ static int handle_invvpid(struct kvm_vcp* and never explicitly flush vpid01. INVVPID targets a VPID, not a * VMCS, and so whether or not the current vmcs12 has VPID enabled is * irrelevant (and there may not be a loaded vmcs12). +* +* If vmcs02 was last loaded on a different pCPU, then defer the flush +* by invalidating the nested VPID tracking to ensure that KVM performs +* the invalidation on the correct pCPU. */ -if (type ==VMX_VPID_EXTENT_INDIVIDUAL_ADDR ) + cpu =get_cpu (); +if (cpu != vmx->nested.vmcs02.cpu) + vmx->nested.last_vpid =0 ; +else if (type ==VMX_VPID_EXTENT_INDIVIDUAL_ADDR )vpid_sync_vcpu_addr (nested_get_vpid02 (vcpu), operand.gla);else vpid_sync_context (nested_get_vpid02 (vcpu)); +put_cpu ();/* * Sync the shadow page tables if EPT is disabled, L1 is invalidating
Greg Kroah-Hartman
maintainerPATCH 160/1376 KVM: x86/mmu: Fold kvm_mmu_zap_memslot() into kvm_arch_flush_shadow_memslot()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 06d38eaa78fdac1cc889f261fa420eba8e9caa1a upstream.
Fold kvm_mmu_zap_memslot() into its sole caller so that its GFN range structure can be used to trigger guest_memfd invalidations regardless of whether KVM will do a partial or full zap of the MMU.
No functional change intended.
--- arch/x86/kvm/mmu/mmu.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-)
arch/x86/kvm/mmu/mmu.c +15 -20
@@ -7107,23 +7107,6 @@ out_flush:kvm_mmu_remote_flush_or_zap (kvm, &invalid_list, flush); } -static void kvm_mmu_zap_memslot (struct kvm *kvm, -struct kvm_memory_slot *slot) -{ -struct kvm_gfn_range range = { - .slot = slot, - .start = slot->base_gfn, - .end = slot->base_gfn + slot->npages, - .may_block = true, - }; -bool flush; - -write_lock (&kvm->mmu_lock); - flush =kvm_unmap_gfn_range (kvm, &range); -kvm_mmu_zap_memslot_pages_and_flush (kvm, slot, flush); -write_unlock (&kvm->mmu_lock); -} -static inline bool kvm_memslot_flush_zap_all (struct kvm *kvm) { return kvm->arch.vm_type == KVM_X86_DEFAULT_VM &&
@@ -7133,10 +7116,22 @@ static inline bool kvm_memslot_flush_zapvoid kvm_arch_flush_shadow_memslot (struct kvm *kvm,struct kvm_memory_slot *slot) { -if (kvm_memslot_flush_zap_all (kvm)) +struct kvm_gfn_range range = { + .slot = slot, + .start = slot->base_gfn, + .end = slot->base_gfn + slot->npages, + .may_block = true, + }; +bool flush; + +if (kvm_memslot_flush_zap_all (kvm)) {kvm_mmu_zap_all_fast (kvm); -else -kvm_mmu_zap_memslot (kvm, slot); + }else { +write_lock (&kvm->mmu_lock); + flush =kvm_unmap_gfn_range (kvm, &range); +kvm_mmu_zap_memslot_pages_and_flush (kvm, slot, flush); +write_unlock (&kvm->mmu_lock); + } }void kvm_mmu_invalidate_mmio_sptes (struct kvm *kvm,u64 gen)
Greg Kroah-Hartman
maintainerPATCH 161/1376 KVM: x86: hyper-v: Clamp stimer deadline to avoid livelock
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos López <[email protected]>
commit 0ca49fbd2883cd53d32d85b50feef17fa04d0fbf upstream.
Fix an issue where userspace or the guest can program an Hyper-V synthetic timer to have a deadline in the past via integer overflow, preventing the CPU from making progress and triggering an RCU stall.
Hyper-V's SynIC exposes 4 per-vCPU synthetic timers to the guest, which are emulated by KVM. Each is programmed through the HV_X64_MSR_STIMERi_CONFIG and HV_X64_MSR_STIMERi_COUNT MSRs. Depending on CONFIG, COUNT represents either the absolute expiration time or the period of a periodic timer, both expressed in 100ns ticks. These timers may be set both by the guest (WRMSR) and the host (KVM_SET_MSRS).
When the timer is enabled, stimer_start() translates COUNT to an absolute monotonic deadline and arms an hrtimer. If COUNT is set to a value close to U64_MAX, the deadline calculation can overflow.
ktime_add_ns(ktime_now, 100 * (stimer->exp_time - time_now))
This can result in a CPU livelock. stimer_start() arms the timer via hrtimer_start() with a deadline in the past, which causes it to immediately fire. The stimer callback then raises KVM_RQ_HV_STIMER, with the intention of causing KVM to deliver a synthetic interrupt on the next vCPU guest enter.
Then, once userspace issues KVM_RUN, vcpu_enter_guest() consumes the request, calling kvm_hv_process_stimers(). This would normally disable the timer via stimer_expiration() once the deadline is in the past. However, the deadline comparison is done between the KVM reference counter and stime->exp_time, which is a big value close to U64_MAX, so this never happens for a few thousand years.
kvm_hv_process_timers() then re-arms the timer via stimer_start(), since it was not disabled, which again fires immediately. Before entering the guest, kvm_vcpu_exit_request() checks kvm_request_pending(), which returns true due to the newly raised KVM_REQ_HV_STIMER. Then vcpu_enter_guest() aborts the guest entry, returning early into vcpu_run(), which loops back again into vcpu_enter_guest(), restarting the cycle.
Since there are no manual yields in this loop, a task with SCHED_FIFO may starve RCU grace-period kthreads, which exposes the stalls found by syzcaller:
rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: (detected by 1, t=10502 jiffies, g=14269, q=1142 ncpus=2)
rcu: All QSes seen, last rcu_preempt kthread activity 10500 (4294965239-4294954739), jiffies_till_next_fqs=1, root ->qsmask 0x0
rcu: rcu_preempt kthread starved for 10500 jiffies! g14269 f0x2 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0
rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
( ... )
Call Trace:
<IRQ>
__run_hrtimer kernel/time/hrtimer.c:1773 [inline]
__hrtimer_run_queues+0x408/0xc30 kernel/time/hrtimer.c:1841
hrtimer_interrupt+0x45b/0xaa0 kernel/time/hrtimer.c:1903
local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1045 [inline]
__sysvec_apic_timer_interrupt+0x102/0x3e0 arch/x86/kernel/apic/apic.c:1062
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1056 [inline]
sysvec_apic_timer_interrupt+0xa1/0xc0 arch/x86/kernel/apic/apic.c:1056
</IRQ>
<TASK>
asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:152 [inline]
RIP: 0010:_raw_spin_unlock_irqrestore+0xa8/0x110 kernel/locking/spinlock.c:194
Code: 74 05 e8 0b f4 5f f6 48 c7 44 24 20 00 00 00 00 9c 8f 44 24 20 f6 44 24 21 02 75 4f f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 <e8> 23 6b 27 f6 65 8b 05 7c 60 5a 07 85 c0 74 40 48 c7 04 24 0e 36
RSP: 0018:ffffc900040a7320 EFLAGS: 00000206
RAX: 5de15cb931505900 RBX: 0000000000000a06 RCX: 5de15cb931505900
RDX: 0000000000000007 RSI: ffffffff8daa9dc3 RDI: 0000000000000001
RBP: ffffc900040a73b0 R08: ffffffff8fc3d077 R09: 1ffffffff1f87a0e
R10: dffffc0000000000 R11: fffffbfff1f87a0f R12: dffffc0000000000
R13: 0000000000000000 R14: ffff8880b8628240 R15: 1ffff92000814e64
hrtimer_start include/linux/hrtimer.h:259 [inline]
stimer_start arch/x86/kvm/hyperv.c:682 [inline]
kvm_hv_process_stimers+0xd0a/0x16a0 arch/x86/kvm/hyperv.c:893
vcpu_enter_guest arch/x86/kvm/x86.c:11193 [inline]
vcpu_run+0x2240/0x76b0 arch/x86/kvm/x86.c:11639
kvm_arch_vcpu_ioctl_run+0x1148/0x1c90 arch/x86/kvm/x86.c:11984
kvm_vcpu_ioctl+0x99a/0xed0 virt/kvm/kvm_main.c:4492
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f635278f749
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f635365c038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f63529e5fa0 RCX: 00007f635278f749
RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005
RBP: 00007f6352813f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f63529e6038 R14: 00007f63529e5fa0 R15: 00007ffd5b219358
</TASK>Fix this by clamping the deadline computation to KTIME_MAX, which preserves the intent of arming a timer very far in the future. ktime_add_safe() already does this type of clamping, so use it after checking that that multiplying by the 100ns time tick also does not overflow.
--- arch/x86/kvm/hyperv.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
arch/x86/kvm/hyperv.c +18 -7
@@ -623,6 +623,18 @@ static enum hrtimer_restart stimer_timer }/* +* Translate a stimer expiry given in 100ns reference ticks into an +* an absolute deadline. Saturates on overflow. +*/ +static ktime_t stimer_add_delta (ktime_t now,u64 delta_100ns) +{ +if (delta_100ns >=KTIME_MAX /100 ) +return KTIME_MAX ; + +return ktime_add_safe (now,100 * delta_100ns); +} + +/* * stimer_start() assumptions: * a) stimer->count is not equal to 0 * b) stimer->config has HV_STIMER_ENABLE flag
@@ -631,6 +643,7 @@ static int stimer_start(struct kvm_vcpu_ {u64 time_now;ktime_t ktime_now; +ktime_t deadline; time_now =get_time_ref_counter (hv_stimer_to_vcpu (stimer)->kvm); ktime_now =ktime_get ();
@@ -653,10 +666,8 @@ static int stimer_start(struct kvm_vcpu_ stimer->index, time_now, stimer->exp_time); -hrtimer_start (&stimer->timer, -ktime_add_ns (ktime_now, -100 * (stimer->exp_time - time_now)), -HRTIMER_MODE_ABS ); + deadline =stimer_add_delta (ktime_now, stimer->exp_time - time_now); +hrtimer_start (&stimer->timer, deadline,HRTIMER_MODE_ABS );return 0 ; } stimer->exp_time = stimer->count;
@@ -675,9 +686,9 @@ static int stimer_start(struct kvm_vcpu_ stimer->index, time_now, stimer->count); -hrtimer_start (&stimer->timer, -ktime_add_ns (ktime_now,100 * (stimer->count - time_now)), -HRTIMER_MODE_ABS ); + deadline =stimer_add_delta (ktime_now, stimer->count - time_now); +hrtimer_start (&stimer->timer, deadline,HRTIMER_MODE_ABS ); +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 162/1376 KVM: x86: Serialize writes to disabled_quirks using kvm->lock
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit ba76b23ed36ab230fc2577aba24f65851114902f upstream.
Protect writes to disabled_quirks with kvm->lock to ensure KVM doesn't clobber state in the unlikely scenario that userspace disables disparate quirks from multiple tasks. More importantly, this will allow wrapping accesses with {READ,WRITE}_ONCE without "needing" to also guard the writer with a useless and confusing READ_ONCE (since the RMW wouldn't be atomic anyways).
Ideally, KVM would disallow disabling quirks once quirks are "live", but that would be a potentially breaking userspace ABI change, and while all existing quirks are fully live only after vCPUs have been created, several MMU-related quirks, IGNORE_GUEST_PAT and SLOT_ZAP_ALL, are partially live at all times. Because populating MMUs requires a vCPU, the guest-visible behavior of IGNORE_GUEST_PAT and SLOT_ZAP_ALL requires a vCPU, but for KVM itself, processing the quirk (or not) has functional impact, i.e. for all intents and purposes, KVM can't prevent those quirks from being disabled after they've been consumed.
--- arch/x86/kvm/x86.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kvm/x86.c +2 -0
@@ -6552,7 +6552,9 @@ int kvm_vm_ioctl_enable_cap(struct kvm *break ; fallthrough;case KVM_CAP_DISABLE_QUIRKS : +mutex_lock (&kvm->lock); kvm->arch.disabled_quirks |= cap->args[0 ] & kvm_caps.supported_quirks; +mutex_unlock (&kvm->lock); r =0 ;break ;case KVM_CAP_SPLIT_IRQCHIP : {
Greg Kroah-Hartman
maintainerPATCH 163/1376 KVM: x86: Ensure runtime reads of disabled_quirks are resolved once
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit ed15cb21999217e549414c128b4a0485debf6278 upstream.
Wrap the sole reader of disabled_quirks with READ_ONCE(), and wrap the post-VM-creation write to disabled_quirks with WRITE_ONCE(), to ensure checking the status of a quirk doesn't re-read disabled_quirks *if* the caller needs such a guarantee. This will allow splitting the "fast" MMU zap into front and back halves, without potentially skipping the back half if SLOT_ZAP_ALL were concurrently disabled (which would be "fine" in the current code base, but far from ideal).
--- arch/x86/kvm/x86.c | 3 ++- arch/x86/kvm/x86.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +2 -1
@@ -6553,7 +6553,8 @@ int kvm_vm_ioctl_enable_cap(struct kvm * fallthrough;case KVM_CAP_DISABLE_QUIRKS :mutex_lock (&kvm->lock); - kvm->arch.disabled_quirks |= cap->args[0 ] & kvm_caps.supported_quirks; +WRITE_ONCE (kvm->arch.disabled_quirks, + kvm->arch.disabled_quirks | (cap->args[0 ] & kvm_caps.supported_quirks));mutex_unlock (&kvm->lock); r =0 ;break ;
arch/x86/kvm/x86.h +1 -1
@@ -357,7 +357,7 @@ static inline void kvm_register_write(ststatic inline bool kvm_check_has_quirk (struct kvm *kvm,u64 quirk) { -return !(kvm->arch.disabled_quirks & quirk); +return !(READ_ONCE (kvm->arch.disabled_quirks) & quirk); }void kvm_inject_realmode_interrupt (struct kvm_vcpu *vcpu,int irq,int inc_eip);
Greg Kroah-Hartman
maintainerPATCH 164/1376 KVM: s390: Fix length check __import_wp_info()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit 4c07680a467e2f7697245bcd11691bffb2a6f0ed upstream.
struct kvm_hw_breakpoint::len is a __u64 that is fully controlled by user space. This is then assigned to wp_info->len, which is an int. The bounds check is done on the truncated value while the allocation uses the untruncated one:
wp_info->len = bp_data->len; [...] if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE) return -EINVAL; wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL_ACCOUNT);
Use the validated value for the allocation as intended. Without this fix userspace can trigger >4GB allocations which will fail and result in a WARN due to MAX_PAGE_ORDER.
Message-ID: <[email protected]>
--- arch/s390/kvm/guestdbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/guestdbg.c +1 -1
@@ -184,7 +184,7 @@ static int __import_wp_info(struct kvm_vif (wp_info->len <0 || wp_info->len >MAX_WP_SIZE )return -EINVAL ; - wp_info->old_data =kmalloc (bp_data->len,GFP_KERNEL_ACCOUNT ); + wp_info->old_data =kmalloc (wp_info->len,GFP_KERNEL_ACCOUNT );if (!wp_info->old_data)return -ENOMEM ;/* try to backup the original value */
Greg Kroah-Hartman
maintainerPATCH 165/1376 KVM: s390: Fix memory leak in guest debug handling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit 121ea1de927c8b9bfdf53c31cad27b86d5de0293 upstream.
bp_data is freed only for the error case by kfree(bp_data). Every successful KVM_SET_GUEST_DEBUG will leak bp_data.
Message-ID: <[email protected]>
--- arch/s390/kvm/guestdbg.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/kvm/guestdbg.c +1 -0
@@ -271,6 +271,7 @@ int kvm_s390_import_bp_data(struct kvm_v vcpu->arch.guestdbg.hw_bp_info = bp_info; vcpu->arch.guestdbg.nr_hw_wp = nr_wp; vcpu->arch.guestdbg.hw_wp_info = wp_info; +kfree (bp_data);return 0 ; error:kfree (bp_data);
Greg Kroah-Hartman
maintainerPATCH 166/1376 KVM: s390: Fix old_data leak in guest debug error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit aa9c8e8baf1e765fa65b93212522c636f25d846f upstream.
__import_wp_info() allocates a per-watchpoint old_data buffer to back up the original guest memory contents. If a later watchpoint of the same KVM_SET_GUEST_DEBUG request fails to import, kvm_s390_import_bp_data() jumps to the error label, which frees the wp_info array but not the old_data buffers of the entries that were imported successfully. Up to MAX_BP_COUNT - 1 buffers of up to MAX_WP_SIZE bytes are leaked per failed request, and the request can be repeated.
Create error handling for cleaning up all created old_data memory areas.
Message-ID: <[email protected]>
--- arch/s390/kvm/guestdbg.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/s390/kvm/guestdbg.c +5 -1
@@ -256,7 +256,7 @@ int kvm_s390_import_bp_data(struct kvm_v ret =__import_wp_info (vcpu, &bp_data[i], &wp_info[nr_wp]);if (ret) - goto error; + goto error_wp; nr_wp++;break ;case KVM_HW_BP :
@@ -273,6 +273,10 @@ int kvm_s390_import_bp_data(struct kvm_v vcpu->arch.guestdbg.hw_wp_info = wp_info;kfree (bp_data);return 0 ; + +error_wp: +while (nr_wp--) +kfree (wp_info[nr_wp].old_data); error:kfree (bp_data);kfree (wp_info);
Greg Kroah-Hartman
maintainerPATCH 167/1376 KVM: s390: Free guest debug data on vcpu destroy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit e7f698b09d4a7c36b299acf680fc50fe868e2bcd upstream.
kvm_s390_clear_bp_data() is only called from kvm_arch_vcpu_ioctl_set_guest_debug(), i.e. when user space changes or disables debugging. A vCPU that is destroyed while hardware breakpoints are still armed - the normal case when the VMM just exits or crashes - leaks hw_bp_info, hw_wp_info and all old_data buffers, since generic KVM frees the vCPU right after kvm_arch_vcpu_destroy().
That is bounded by MAX_BP_COUNT entries, so roughly 8 KiB per vCPU, but it is unbounded over VM lifetimes. The allocations are GFP_KERNEL_ACCOUNT, so the charge also outlives the exiting process and pins dying memcgs.
Fix by clearing the debug data on vCPU destruction. Calling it unconditionally is fine: struct kvm_vcpu is zero allocated, so for a vCPU that never enabled debugging the counters are 0 and the pointers NULL.
Message-ID: <[email protected]>
--- arch/s390/kvm/kvm-s390.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/kvm/kvm-s390.c +1 -0
@@ -3440,6 +3440,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vctrace_kvm_s390_destroy_vcpu (vcpu->vcpu_id);kvm_s390_clear_local_irqs (vcpu);kvm_clear_async_pf_completion_queue (vcpu); +kvm_s390_clear_bp_data (vcpu);if (!kvm_is_ucontrol (vcpu->kvm))sca_del_vcpu (vcpu);kvm_s390_update_topology_change_report (vcpu->kvm,1 );
Greg Kroah-Hartman
maintainerPATCH 168/1376 KVM: s390: Take srcu when importing watchpoint data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit a4e482def8533ebace517d9f67f1465841b1f982 upstream.
__import_wp_info() backs up the original guest memory contents of a watchpoint with read_guest_abs(), which is kvm_read_guest() and therefore resolves the memslot via __kvm_memslots(). That requires kvm->srcu (or kvm->slots_lock) to be held, otherwise a concurrent memslot update can free the memslots array under us once its SRCU grace period has elapsed.
As this is not fast path, following lock ordering (mutex first, then srcu) take the big hammer and hold the srcu for the full import.
Message-ID: <[email protected]>
--- arch/s390/kvm/kvm-s390.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kvm/kvm-s390.c +4 -2
@@ -4393,8 +4393,10 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(/* enforce guest PER */ kvm_s390_set_cpuflags (vcpu,CPUSTAT_P ); -if (dbg->control &KVM_GUESTDBG_USE_HW_BP ) - rc =kvm_s390_import_bp_data (vcpu, dbg); +if (dbg->control &KVM_GUESTDBG_USE_HW_BP ) { +scoped_guard (srcu, &vcpu->kvm->srcu) + rc = kvm_s390_import_bp_data(vcpu, dbg); + } }else {kvm_s390_clear_cpuflags (vcpu,CPUSTAT_P ); vcpu->arch.guestdbg.last_bp =0 ;
Greg Kroah-Hartman
maintainerPATCH 169/1376 KVM: s390: Zero initialize irq in reinject_machine_check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit b239410c7653ff6781d4cf1d63cfc52a1bb71788 upstream.
kvm_s390_reinject_machine_check() fills cr14, mcic, ext_damage_code and failing_storage_address of the on-stack struct kvm_s390_irq, but struct kvm_s390_mchk_info also has a pad word and a 16 byte fixed_logout array. struct mcck_volatile_info carries no logout data, so there is nothing to copy there and both stay whatever was on the stack.
__inject_mchk() then memcpy()s fixed_logout into the vcpu local interrupt state unconditionally. This will reach the guest during deliver and userspace during migration.
Reflecting zeroes is the correct behaviour here, as KVM has no logout data for a reinjected machine check.
This needs a host machine check while the cpu is in SIE so not trivial to trigger.
Message-ID: <[email protected]>
--- arch/s390/kvm/interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/interrupt.c +1 -1
@@ -2863,7 +2863,7 @@ void kvm_s390_reinject_machine_check(str struct mcck_volatile_info *mcck_info) {struct kvm_s390_interrupt_info inti; -struct kvm_s390_irq irq; +struct kvm_s390_irq irq = {};struct kvm_s390_mchk_info *mchk;union mci mci;__u64 cr14 =0 ;/* upper bits are not used */
Greg Kroah-Hartman
maintainerPATCH 170/1376 KVM: s390: pv: Fix rc/rrc offset for PVM_DUMP
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit 1e3c8e7b3465fb8a49d3623d2d0f449c0b5b48f3 upstream.
The rc/rrc value is copied to the cmd location of the cmd in the kvm_pv_cmd structure. Fix the offset.
Message-ID: <[email protected]>
--- arch/s390/kvm/kvm-s390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kvm/kvm-s390.c +1 -1
@@ -5718,7 +5718,7 @@ long kvm_arch_vcpu_ioctl(struct file *fi r =kvm_s390_handle_pv_vcpu_dump (vcpu, &cmd);/* Always copy over UV rc / rrc data */ -if (copy_to_user ((__u8 __user *)argp, &cmd.rc, +if (copy_to_user (argp + offsetof(struct kvm_pv_cmd , rc), &cmd.rc,sizeof (cmd.rc) +sizeof (cmd.rrc))) r = -EFAULT ;break ;
Greg Kroah-Hartman
maintainerPATCH 171/1376 KVM: s390: Restore sigset on error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <[email protected]>
commit c44d36d8e6501c4934412d9014e5e02da9efdb8f upstream.
kvm_sigset_activate() installs vcpu->sigset via sigprocmask() and stashes the caller's mask in current->real_blocked; only kvm_sigset_deactivate() restores it.
For KVM_RUN on a STOPPED vcpu the error path will not restore the userspace mask. Re-arrange the error handling to also restore the signal mask.
Message-ID: <[email protected]>
--- arch/s390/kvm/kvm-s390.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kvm/kvm-s390.c +4 -2
@@ -5067,7 +5067,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vpr_err_ratelimited ("can't run stopped vcpu %d\n" , vcpu->vcpu_id); rc = -EINVAL ; - goto out; + goto out_sigset; }kernel_fpu_begin (&fpu,KERNEL_FPC |KERNEL_VXR );
@@ -5096,9 +5096,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vstore_regs (vcpu);kernel_fpu_end (&fpu,KERNEL_FPC |KERNEL_VXR ); + vcpu->stat.exit_userspace++; + +out_sigset:kvm_sigset_deactivate (vcpu); - vcpu->stat.exit_userspace++; out:vcpu_put (vcpu);return rc;
Greg Kroah-Hartman
maintainerPATCH 172/1376 LoongArch: KVM: Fix TOCTOU race on pv_features
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <[email protected]>
commit 9296375902579f9b0e456bbb76e5cf179e5a4e0b upstream.
In kvm_loongarch_cpucfg_set_attr() the check-then-set on kvm->arch.pv_features is lockless, so two vCPUs can race past the validation and set different values. Add a spinlock to protect it.
--- arch/loongarch/include/asm/kvm_host.h | 1 + arch/loongarch/kvm/vcpu.c | 6 +++++- arch/loongarch/kvm/vm.c | 1 + 3 files changed, 7 insertions(+), 1 deletion(-)
arch/loongarch/include/asm/kvm_host.h +1 -0
@@ -110,6 +110,7 @@ struct kvm_arch {unsigned int pte_shifts[MAX_PGTABLE_LEVELS ];unsigned int root_level;spinlock_t phyid_map_lock; +spinlock_t pv_setting_lock;struct kvm_phyid_map *phyid_map;/* Enabled PV features */ unsigned long pv_features;
arch/loongarch/kvm/vcpu.c +5 -1
@@ -1088,10 +1088,14 @@ static int kvm_loongarch_cpucfg_set_attrreturn -EINVAL ;/* All vCPUs need set the same PV features */ +spin_lock (&kvm->arch.pv_setting_lock);if ((kvm->arch.pv_features &LOONGARCH_PV_FEAT_UPDATED ) - && ((kvm->arch.pv_features & valid) != val)) + && ((kvm->arch.pv_features & valid) != val)) { +spin_unlock (&kvm->arch.pv_setting_lock);return -EINVAL ; + } kvm->arch.pv_features = val |LOONGARCH_PV_FEAT_UPDATED ; +spin_unlock (&kvm->arch.pv_setting_lock);return 0 ;default :return -ENXIO ;
arch/loongarch/kvm/vm.c +1 -0
@@ -38,6 +38,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unreturn -ENOMEM ; }spin_lock_init (&kvm->arch.phyid_map_lock); +spin_lock_init (&kvm->arch.pv_setting_lock);kvm_init_vmcs (kvm);
Greg Kroah-Hartman
maintainerPATCH 173/1376 LoongArch: KVM: Free init resources if kvm_init() fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chaithanya Lagisetty <[email protected]>
commit f7a1064cce3b100b54780c68529176232d8eb01e upstream.
kvm_loongarch_init() calls kvm_loongarch_env_init() to allocate the per-CPU kvm_context (vmcs) and kvm_loongarch_ops and to register the perf callbacks, and then calls kvm_init(). If kvm_init() fails its result is returned directly, but since module_init() does not run the module_exit() stuff on failure, so kvm_loongarch_env_exit() is never called and those resources are leaked.
So call kvm_loongarch_env_exit() when kvm_init() fails, matching the teardown-on-failure pattern used by riscv_kvm_init().
--- arch/loongarch/kvm/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/loongarch/kvm/main.c +5 -1
@@ -377,7 +377,11 @@ static int kvm_loongarch_init(void)if (r)return r; -return kvm_init (sizeof (struct kvm_vcpu ),0 ,THIS_MODULE ); + r =kvm_init (sizeof (struct kvm_vcpu ),0 ,THIS_MODULE ); +if (r) +kvm_loongarch_env_exit (); + +return r; }static void kvm_loongarch_exit (void )
Greg Kroah-Hartman
maintainerPATCH 174/1376 LoongArch: KVM: Preserve memslot arch flags on KVM_MR_FLAGS_ONLY
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zeng Chi <[email protected]>
commit 27a9bfee3bbcb3cabb77797354f07e0e44e49831 upstream.
kvm_arch_prepare_memory_region() computes new->arch.flags, i.e. whether a memslot is KVM_MEM_HUGEPAGE_CAPABLE or KVM_MEM_HUGEPAGE_INCAPABLE, only for KVM_MR_CREATE and KVM_MR_MOVE, and returns early for every other change. But the generic code allocates a zeroed memslot for every change and never copies old->arch, so after a KVM_MR_FLAGS_ONLY update, e.g. toggling KVM_MEM_LOG_DIRTY_PAGES for live migration, the active memslot has arch.flags == 0.
With both flags clear, fault_supports_huge_mapping() falls through to the alignment check on the HVA range alone, which no longer verifies that the GPA and HVA have the same offset within a PMD. A memslot that was marked KVM_MEM_HUGEPAGE_INCAPABLE because of a GPA/HVA offset mismatch can then be mapped with PMD entries on read faults, and since kvm_map_page() aligns the gfn and the pfn independently, the guest ends up accessing the wrong host pages, exactly the "d -> f, e -> g" case described in the comment above the check.
Carry the arch flags over from the old memslot for KVM_MR_FLAGS_ONLY, as the GPA, HVA and size are guaranteed to be unchanged for that case.
--- arch/loongarch/kvm/mmu.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/loongarch/kvm/mmu.c +10 -0
@@ -383,6 +383,16 @@ int kvm_arch_prepare_memory_region(struchva_t hva_start;size_t size, gpa_offset, hva_offset; +/* +* The generic code allocates a fresh, zeroed memslot for every change, +* so the arch flags computed below must be carried over when only the +* userspace flags change, e.g. when dirty logging is toggled. +*/ +if (change ==KVM_MR_FLAGS_ONLY ) { + new->arch = old->arch; +return 0 ; + } +if ((change !=KVM_MR_MOVE ) && (change !=KVM_MR_CREATE ))return 0 ;/*
Greg Kroah-Hartman
maintainerPATCH 175/1376 LoongArch: Fix acpi_package_ids[] array overflow
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bibo Mao <[email protected]>
commit 2a2367d46d7a4ee4122b7a86e57125542dbbe963 upstream.
With LoongArch virt machine, a typical setting is one core per socket, there will max 256 sockets (packages) on one VM. With PPTT acpi table, array acpi_package_ids[] will be overflowed.
Here change the array size of acpi_package_ids[] with the max value of MAX_PACKAGES and KVM_MAX_VCPUS.
--- arch/loongarch/kernel/acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/loongarch/kernel/acpi.c +2 -1
@@ -12,6 +12,7 @@#include <linux/efi-bgrt.h> #include <linux/irq.h> #include <linux/irqdomain.h> +#include <linux/kvm_host.h> #include <linux/memblock.h> #include <linux/of_fdt.h> #include <linux/serial_core.h>
@@ -201,7 +202,7 @@ static void __init acpi_process_madt(voiint pptt_enabled;static int acpi_nr_packages; -static int acpi_package_ids[MAX_PACKAGES ]; +static int acpi_package_ids[MAX (MAX_PACKAGES ,KVM_MAX_VCPUS )];int __init parse_acpi_topology (void ) {
Greg Kroah-Hartman
maintainerPATCH 176/1376 LoongArch: Do not select HAVE_RUST when KASAN is enabled
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit 63b6a48c951d63bf39d44603ada48a987ccf66eb upstream.
After commit 2625480a1bf7 ("hardening: Default randstruct off with rust for better allmodconfig support"), which allows Rust to be enabled for allmodconfig, ARCH=loongarch allmodconfig starts failing with:
error: kernel-address sanitizer is not supported for this target
error: aborting due to 1 previous error
make[4]: *** [rust/Makefile:741: rust/core.o] Error 1
For the same reason as the commit 84a0f7caafc679f7 ("ARM: Do not select HAVE_RUST when KASAN is enabled"), do not select HAVE_RUST when KASAN is enabled until the loongarch64-unknown-none-softfloat target in rustc supports KASAN.
--- arch/loongarch/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/loongarch/Kconfig +1 -1
@@ -161,7 +161,7 @@ config LOONGARCH select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC select HAVE_RETHOOK select HAVE_RSEQ - select HAVE_RUST + select HAVE_RUST if !KASAN select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_SETUP_PER_CPU_AREA if NUMA
Greg Kroah-Hartman
maintainerPATCH 177/1376 LoongArch: Do not save/restore percpu base register in rethook trampoline
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
commit c3f2feace5e4f4b01b68b9f947b19adb4155c32e upstream.
The rethook trampoline saves $r21 ($u0), the percpu base, into its frame at entry and restores it at exit. Inbetween rethook_trampoline_handler() may schedule via preempt_enable_notrace().
If the task migrates to another CPU, the frame's $r21 holds the old CPU's percpu base, and restoring it poisons $r21 on the new CPU. Until the next user->kernel transition heals $r21, all this_cpu_*() accesses (runqueues, RCU per-CPU data, timer tick programming, FPU ownership) hit the wrong CPU's percpu area.
Under kretprobe-heavy preemptible load this can corrupt scheduler and timer state: scheduling-while-atomic splats, wrong-CPU RCU warnings, WARN_ON_ONCE(rq != this_rq()) in nohz_balance_exit_idle(), and CPUs parking in the idle loop with the constant timer never re-armed (hard lockup). Reproduces on a Loongson-3A6000 with kretprobes on VFS paths plus heavy file churn (OS install / unsquashfs).
By convention $r21 always holds the current CPU's percpu base in kernel
mode: SAVE_SOME() at exception entry reloads it only when coming from user mode, and RESTORE_SOME() restores it only when returning to user mode; the context-switch path never writes it. Therefore the live $r21 at trampoline exit is already correct, and nothing inbetween can change it legitimately (kernel C code cannot write a global register variable). The same flaw existed even in the pre-rethook kretprobe trampoline since v6.3; it was carried over when rethook replaced it. Drop both the save and the restore here. Drop the restore is enough to solve the issue, and drop the save is to keep the code tidy and no need to clear it.
--- arch/loongarch/kernel/rethook_trampoline.S | 2 -- 1 file changed, 2 deletions(-)
arch/loongarch/kernel/rethook_trampoline.S +0 -2
@@ -24,7 +24,6 @@ cfi_st t6, PT_R18 cfi_st t7, PT_R19 cfi_st t8, PT_R20 - cfi_st u0, PT_R21 cfi_st fp, PT_R22 cfi_st s0, PT_R23 cfi_st s1, PT_R24
@@ -59,7 +58,6 @@ cfi_ld t6, PT_R18 cfi_ld t7, PT_R19 cfi_ld t8, PT_R20 - cfi_ld u0, PT_R21 cfi_ld fp, PT_R22 cfi_ld s0, PT_R23 cfi_ld s1, PT_R24
Greg Kroah-Hartman
maintainerPATCH 178/1376 LoongArch: Avoid preempt count underflow without probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
commit 72ce4b24676e8b3b75376c4c559dd81c1ac52d5a upstream.
LoongArch uses break 11 for the breakpoint placed after an instruction that Kprobes executes out of line. Since userspace can issue the same break instruction, do_bp() can reach kprobe_singlestep_handler() when there is no current probe.
The handler actually returns false in this case, but it first calls preempt_enable_no_resched(). The corresponding preempt_disable() is done by kprobe_breakpoint_handler() on a real Kprobe hit, so it has not run here. As a result, an ordinary userspace breakpoint (code 11) underflows the current task's preempt count.
This also makes in_interrupt() return true until the task schedules. One visible consequence is the socket cgroup attribution: cgroup_sk_alloc() treats the allocation as interrupt context and assigns the socket to the root cgroup. A socket opened from the SIGTRAP handler can then avoid a BPF_CGROUP_INET_SOCK_CREATE policy attached to the task's own cgroup.
Return as soon as kprobe_running() reports no active probe.
The same check has appeared in [PATCH v10 2/4] of the original LoongArch Kprobes series, but was dropped before the feature reached mainline.
--- arch/loongarch/kernel/kprobes.c | 3 +++ 1 file changed, 3 insertions(+)
arch/loongarch/kernel/kprobes.c +3 -0
@@ -273,6 +273,9 @@ bool kprobe_singlestep_handler(struct ptstruct kprobe_ctlblk *kcb =get_kprobe_ctlblk ();unsigned long addr =instruction_pointer (regs); +if (!cur) +return false; +if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS |KPROBE_REENTER )) && ((unsigned long )&cur->ainsn.insn[1 ] == addr)) {restore_local_irqflag (kcb, regs);
Greg Kroah-Hartman
maintainerPATCH 179/1376 media: airspy: use vb2_video_unregister_device() on disconnect to fix NULL deref
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit 2f378dc45e685fc825d2dd08e7864666d6fcc009 upstream.
airspy_disconnect() clears s->udev under v4l2_lock, but airspy_stop_streaming() unconditionally calls airspy_ctrl_msg() and airspy_free_stream_bufs() afterwards. If a streaming user closes the device after disconnect, stop_streaming() runs and dereferences the NULL s->udev:
airspy_stop_streaming()
airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0)
usb_sndctrlpipe(s->udev, 0) /* NULL deref */
airspy_free_stream_bufs(s)
usb_free_coherent(s->udev, ...) /* NULL deref */The airspy driver uses vb2_fop_release() in its file_operations, so replace video_unregister_device(&s->vdev) with vb2_video_unregister_device(&s->vdev) and move it before clearing s->udev. vb2_video_unregister_device() releases the vb2 queue, which synchronously runs airspy_stop_streaming() if streaming is active, so the URBs, coherent DMA stream buffers and the hardware stop control message all execute while s->udev is still valid.
vb2_video_unregister_device() locks vdev->queue->lock (vb_queue_lock) internally, and stop_streaming() locks v4l2_lock, so the previous outer mutex_lock(&s->vb_queue_lock) / mutex_lock(&s->v4l2_lock) pair around the unregister sequence would self-deadlock and has been removed. A short v4l2_lock critical section around s->udev = NULL remains so any ioctl path that still holds the file descriptor sees coherent state.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
--- drivers/media/usb/airspy/airspy.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/media/usb/airspy/airspy.c +12 -5
@@ -464,14 +464,21 @@ static void airspy_disconnect(struct usbdev_dbg (s->dev,"\n" ); -mutex_lock (&s->vb_queue_lock); +/* +* vb2_video_unregister_device() releases the vb2 queue, which +* triggers airspy_stop_streaming() if streaming is active. +* stop_streaming() dereferences s->udev via airspy_ctrl_msg() and +* airspy_free_stream_bufs(), so it must run before s->udev is +* cleared. vb2_video_unregister_device() locks vb_queue_lock +* internally and stop_streaming() locks v4l2_lock, so neither may +* be held by the caller. +*/ +v4l2_device_disconnect (&s->v4l2_dev); +vb2_video_unregister_device (&s->vdev); +mutex_lock (&s->v4l2_lock); -/* No need to keep the urbs around after disconnection */ s->udev =NULL ; -v4l2_device_disconnect (&s->v4l2_dev); -video_unregister_device (&s->vdev);mutex_unlock (&s->v4l2_lock); -mutex_unlock (&s->vb_queue_lock);v4l2_device_put (&s->v4l2_dev); }
Greg Kroah-Hartman
maintainerPATCH 180/1376 media: amphion: Remove obsolete frame_count check in venc_start_session
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <[email protected]>
commit 2be6ee86385badab95b1bace984735bde6e0fec0 upstream.
The dev_err() log warning about no input when starting was originally meaningful when min_queued_buffers was set, as it indicated an abnormal condition. However, since commit 5633ec763a2a ("media: amphion: Drop min_queued_buffers assignment") removed the min_queued_buffers assignment, having frame_count == 0 at start is a normal condition.
Remove this misleading log that no longer serves any purpose.
--- drivers/media/platform/amphion/venc.c | 2 -- 1 file changed, 2 deletions(-)
drivers/media/platform/amphion/venc.c +0 -2
@@ -967,8 +967,6 @@ static int venc_start_session(struct vpu venc->ready_count =0 ; venc->stopped = false;vpu_process_output_buffer (inst); -if (venc->frame_count ==0 ) -dev_err (inst->dev,"[%d] there is no input when starting\n" , inst->id);return 0 ; error:
Greg Kroah-Hartman
maintainerPATCH 181/1376 media: cec: core: Fix kmemleak due to missed rc_free_device() call
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonas Karlman <[email protected]>
commit a24ba0653f7154e671dc8d2bf64682ab2d042792 upstream.
The commit dccc0c3ddf8f ("media: rc: fix race between unregister and urb/irq callbacks") removed the implicit call to rc_free_device() from rc_unregister_device(). However, the commit missed to remove the NULL assignment of adap->rc that is now causing rc_free_device() to never be called on an allocated rc device.
kmemleak reports following after e.g. dw-hdmi unbind:
unreferenced object 0xffff00010ac10000 (size 4096):
comm "kworker/u16:1", pid 39, jiffies 4294897739 hex dump (first 32 bytes):
20 23 4b 0a 01 00 ff ff 08 00 c1 0a 01 00 ff ff #K.............
08 00 c1 0a 01 00 ff ff 00 00 00 00 00 00 00 00 ................
backtrace (crc e11baccc):
kmemleak_alloc+0x38/0x44
__kmalloc_cache_noprof+0x4a8/0x5e0
rc_allocate_device+0x48/0x2a0
cec_allocate_adapter+0x3ac/0x800
dw_hdmi_cec_probe+0x264/0x634
platform_probe+0xc0/0x188
really_probe+0x4a4/0x8e0
__driver_probe_device+0x2f8/0x440
driver_probe_device+0x60/0x160
__device_attach_driver+0x1a0/0x2a0
bus_for_each_drv+0x100/0x1a0
__device_attach+0x174/0x350
device_initial_probe+0x90/0xb0
bus_probe_device+0x4c/0x120
device_add+0xdec/0x116c
platform_device_add+0x354/0x598Remove the assignment of adap->rc to NULL to let cec_delete_adapter() free the allocated rc device after last user of the cec device exits to fix the kmemleak.
--- drivers/media/cec/core/cec-core.c | 2 -- 1 file changed, 2 deletions(-)
drivers/media/cec/core/cec-core.c +0 -2
@@ -370,9 +370,7 @@ void cec_unregister_adapter(struct cec_areturn ;#ifdef CONFIG_MEDIA_CEC_RC -/* Note: rc_unregister also calls rc_free */ rc_unregister_device (adap->rc); - adap->rc =NULL ;#endif debugfs_remove_recursive (adap->cec_dir);#ifdef CONFIG_CEC_NOTIFIER
Greg Kroah-Hartman
maintainerPATCH 182/1376 media: cec: disable delayed work before freeing an interrupted transmit
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biren Pandya <[email protected]>
commit 0fbd5c2327020858c45b2d1c65775d64cdeca523 upstream.
cec_transmit_msg_fh() drops adap->lock to wait for a blocking transmit in wait_for_completion_killable(). If that wait is interrupted by a signal, cancel_delayed_work_sync() can run before the CEC kthread arms the reply timeout via schedule_delayed_work(&data->work) in cec_transmit_done_ts(). The work is then armed after the cancel, and the data is freed with its delayed_work still pending:
ODEBUG: free active (active state 0) object: ... hint: cec_wait_timeout
Use disable_delayed_work_sync(): it cancels the work and disables it, so the later schedule_delayed_work() becomes a no-op and the work cannot be re-armed. The data is freed right after, so it need not be re-enabled.
--- drivers/media/cec/core/cec-adap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/cec/core/cec-adap.c +1 -1
@@ -964,7 +964,7 @@ int cec_transmit_msg_fh(struct cec_adapt*/ mutex_unlock (&adap->lock); err =wait_for_completion_killable (&data->c); -cancel_delayed_work_sync (&data->work); +disable_delayed_work_sync (&data->work);mutex_lock (&adap->lock);if (err)
Greg Kroah-Hartman
maintainerPATCH 183/1376 media: cec: extron-da-hd-4k-plus: add sanity check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans Verkuil <[email protected]>
commit abac9820b26b5cfcb01eb79efe2abdd0ac7e07c3 upstream.
Add check to prevent overflowing msg.msg[] in case the incoming data is malformed.
--- drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +2 -1
@@ -656,7 +656,8 @@ static void extron_process_received(struif (!port || port->disconnected)return ; -if (len <5 || (len -2 ) %3 || data[len -2 ] !='*' ) +if (len <5 || ((len -2 ) /3 >sizeof (msg.msg)) || + (len -2 ) %3 || data[len -2 ] !='*' ) goto malformed;while (*data !='*' ) {
Greg Kroah-Hartman
maintainerPATCH 184/1376 media: cec: meson: ao-cec-g12a: name the CEC core regmap to avoid debugfs clash
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yi Ding <[email protected]>
commit 172c5a7d81deb922ddedd1bc920751c7fed6c43c upstream.
The driver registers two regmaps on the same platform device: an MMIO regmap for the AO CEC registers, and an indirect regmap (using reg_read()/reg_write() callbacks) for the CEC controller core registers. Neither regmap_config sets a .name, so both default their debugfs directory to the device name and collide:
debugfs: 'ff800280.cec' already exists in 'regmap'
Because of the clash the second regmap's debugfs directory fails to register, so its registers can no longer be inspected via debugfs.
Give the indirect CEC core regmap a distinct name. The two debugfs directories then become "<dev>.cec" and "<dev>.cec-core". This only affects debugfs naming; register access is unchanged.
Tested on an ODROID-N2 (Amlogic S922X): the warning is gone and both /sys/kernel/debug/regmap/ff800280.cec and ff800280.cec-core are present.
--- drivers/media/cec/platform/meson/ao-cec-g12a.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/cec/platform/meson/ao-cec-g12a.c +1 -0
@@ -405,6 +405,7 @@ static int meson_ao_cec_g12a_write(void }static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { + .name ="core" , .reg_bits =8 , .val_bits =8 , .reg_read = meson_ao_cec_g12a_read,
Greg Kroah-Hartman
maintainerPATCH 185/1376 media: cec: Serialize exclusive follower delivery
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit 1924d0788caa6c66fd320dd4704fae99487fd2c7 upstream.
cec_receive_notify() reads the exclusive follower pointer without the adapter lock. Serialize the no-follower check and message delivery against mode changes and release.
--- drivers/media/cec/core/cec-adap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/media/cec/core/cec-adap.c +7 -1
@@ -2209,9 +2209,13 @@ static int cec_receive_notify(struct cec* Unprocessed messages are aborted if userspace isn't doing * any processing either. */ +mutex_lock (&adap->lock);if (!is_broadcast && !is_reply && !adap->follower_cnt && - !adap->cec_follower && msg->msg[1 ] !=CEC_MSG_FEATURE_ABORT ) + !adap->cec_follower && msg->msg[1 ] !=CEC_MSG_FEATURE_ABORT ) { +mutex_unlock (&adap->lock);return cec_feature_abort (adap, msg); + } +mutex_unlock (&adap->lock);break ; }
@@ -2224,10 +2228,12 @@ skip_processing:* Send to the exclusive follower if there is one, otherwise send * to all followers. */ +mutex_lock (&adap->lock);if (adap->cec_follower)cec_queue_msg_fh (adap->cec_follower, msg);else cec_queue_msg_followers (adap, msg); +mutex_unlock (&adap->lock);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 186/1376 media: cedrus: fix memory leak in cedrus_init_ctrls()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 9df2fbe563194da1967a5db083442186c1323efe upstream.
In cedrus_init_ctrls(), the V4L2 control handler is initialized before allocating memory for ctx->ctrls. If this allocation fails, the function returns -ENOMEM without freeing the previously allocated handler resources, leading to a memory leak.
Fix this by calling v4l2_ctrl_handler_free() on the ctx->ctrls allocation failure path.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an Allwinner SoC or board with a Cedrus VPU available to test with, no runtime testing was able to be performed.
--- drivers/staging/media/sunxi/cedrus/cedrus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/media/sunxi/cedrus/cedrus.c +3 -1
@@ -285,8 +285,10 @@ static int cedrus_init_ctrls(struct cedr ctrl_size =sizeof (ctrl) *CEDRUS_CONTROLS_COUNT +1 ; ctx->ctrls =kzalloc (ctrl_size,GFP_KERNEL ); -if (!ctx->ctrls) +if (!ctx->ctrls) { +v4l2_ctrl_handler_free (hdl);return -ENOMEM ; + } j =0 ;for (i =0 ; i <CEDRUS_CONTROLS_COUNT ; i++) {
Greg Kroah-Hartman
maintainerPATCH 187/1376 media: cobalt: Avoid freeing ALSA private data twice
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit 3a7d6b9c4cb5ac18cbd3f1c7f8c7b159c42ba0b1 upstream.
snd_cobalt_card_create() stores cobsc in sc->private_data and installs snd_cobalt_card_private_free() as sc->private_free. From that point, snd_card_free(sc) releases cobsc through the ALSA card cleanup path.
If cobalt_alsa_init() fails after snd_cobalt_card_create(), the err_exit_free path calls snd_card_free(sc) and then kfree(cobsc). That second free releases the same object again.
Remove the explicit kfree(cobsc) and leave ownership with the ALSA card.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/media/pci/cobalt/cobalt-alsa-main.c | 1 - 1 file changed, 1 deletion(-)
drivers/media/pci/cobalt/cobalt-alsa-main.c +0 -1
@@ -135,7 +135,6 @@ int cobalt_alsa_init(struct cobalt_strea err_exit_free:if (sc !=NULL )snd_card_free (sc); -kfree (cobsc); err_exit:return ret; }
Greg Kroah-Hartman
maintainerPATCH 188/1376 media: cx231xx: reject geometry changes while the VBI queue is busy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 627a121c15fe05a541f44d86016294b80bada75d upstream.
vidioc_s_fmt_vid_cap() and vidioc_s_std() change the device-wide dev->width / dev->norm but only refuse the change when the *video* queue (dev->vidq) is busy. The VBI queue (dev->vbiq) shares that same geometry:cx231xx_init_vbi_isoc() latches dma_q->lines_per_field from dev->norm, the VBI videobuf2 plane is sized from dev->width / dev->norm in vbi_queue_setup() and vbi_buf_prepare(), and cx231xx_do_vbi_copy() then recomputes the destination offset from the *live* dev->width and the latched lines_per_field on every URB completion:
offset = lines_completed * (dev->width << 1) + ...; if (dma_q->current_field == 2) offset += dev->width * 2 * dma_q->lines_per_field; memcpy(plane + offset, p_buffer, lencopy);
Because the VBI node shares video_ioctl_ops with the video node, an application can size a small VBI plane (REQBUFS/QBUF with a small width, or with the NTSC standard), then enlarge dev->width (or switch dev->norm to PAL) through the video node while the VBI stream is running -- the change is allowed because only dev->vidq is checked -- and let the device deliver a field-2 VBI payload. cx231xx_do_vbi_copy() now computes the offset with the larger geometry and memcpy()s past the end of the smaller plane that was already allocated, a heap out-of-bounds write whose offset is attacker-chosen and whose contents come from the device. The per-field guard in cx231xx_copy_vbi_line() does not help: it bounds the copy against the latched lines_per_field, not the plane's real capacity, and vb2 does not re-run buf_prepare() for an already prepared buffer.
Refuse the format/standard change when the VBI queue is busy as well, so the geometry cannot change underneath an allocated VBI buffer.
--- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/usb/cx231xx/cx231xx-video.c +2 -2
@@ -900,7 +900,7 @@ static int vidioc_s_fmt_vid_cap(struct fif (rc)return rc; -if (vb2_is_busy (&dev->vidq)) { +if (vb2_is_busy (&dev->vidq) ||vb2_is_busy (&dev->vbiq)) {dev_err (dev->dev,"%s: queue busy\n" , __func__);return -EBUSY ; }
@@ -935,7 +935,7 @@ static int vidioc_s_std(struct file *filif (dev->norm == norm)return 0 ; -if (vb2_is_busy (&dev->vidq)) +if (vb2_is_busy (&dev->vidq) ||vb2_is_busy (&dev->vbiq))return -EBUSY ; dev->norm = norm;
Greg Kroah-Hartman
maintainerPATCH 189/1376 media: cx23885: cancel NetUP CI work before teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 4e143d662ca94888b494b2427fc9e34494eb933a upstream.
netup_ci_exit() frees a netup_ci_state while its work item, netup_read_ci_status(), may still be pending or running on the system workqueue. The worker obtains the state with container_of() and dereferences it, so it must not outlive the state.
netup_ci_init() queues the initial status read, and CI GPIO interrupts subsequently queue the same work from netup_ci_slot_status(). During remove, cx23885_finidev() calls free_irq() before the CI device is unregistered. free_irq() prevents further IRQ handlers from running, but does not drain work queued previously, so the worker can run after netup_ci_exit() frees the state.
Call cancel_work_sync() before dvb_ca_en50221_release() and kfree().
This issue was found by an in-house static analysis tool.
--- drivers/media/pci/cx23885/cimax2.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/pci/cx23885/cimax2.c +1 -0
@@ -528,6 +528,7 @@ void netup_ci_exit(struct cx23885_tsportif (NULL == state->ca.data)return ; +cancel_work_sync (&state->work);dvb_ca_en50221_release (&state->ca);kfree (state); }
Greg Kroah-Hartman
maintainerPATCH 190/1376 media: em28xx: defer audio-only extension registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Diego Fernando Mancera Gomez <[email protected]>
commit 95f76f51937fdfb0fc1e14cae606b1ef574a56f3 upstream.
The audio-only path registers extensions while probing the primary device. For a dual-TS board, this happens before dev_next is created. The duplicate device inherits is_audio_only and is then independently inserted into em28xx_devlist.
The list is intended to contain only primary devices: extension operations reach the secondary device through dev_next. The independently linked secondary can be freed during disconnect while its list node remains reachable, resulting in a use-after-free.
Defer audio-only extension registration to the module-request work item. It runs only after probing has completed construction of the optional secondary device, so only the primary is registered and extension callbacks reach the secondary through dev_next.
--- drivers/media/usb/em28xx/em28xx-cards.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/media/usb/em28xx/em28xx-cards.c +1 -2
@@ -3448,6 +3448,7 @@ static void request_module_async(struct* intf. Don't register extensions twice on those devices. */ if (dev->is_audio_only) { +em28xx_init_extension (dev);#if defined(CONFIG_MODULES ) && defined(MODULE )request_module ("em28xx-alsa" );#endif
@@ -3676,8 +3677,6 @@ static int em28xx_init_dev(struct em28xx retval = -ENODEV ; goto err_deinit_media; } -em28xx_init_extension (dev); -return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 191/1376 media: em28xx: fix use-after-free of dev_next->devlist on disconnect
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangong.Han <[email protected]>
commit 826915b6b65e2d3251e7248ea54289a22d748c84 upstream.
When a device with has_dual_ts=1 is probed and the is_audio_only path is taken, both dev and dev->dev_next are added to the global em28xx_devlist via em28xx_init_extension(). However, during disconnect, em28xx_close_extension(dev) only calls list_del(&dev->devlist), leaving dev->dev_next->devlist still linked in the global list. When dev_next is subsequently freed via kref_put(), its devlist entry becomes a dangling pointer in em28xx_devlist. The next device probe that calls em28xx_init_extension() triggers a list corruption BUG when list_add_tail detects the freed node.
This bug was exposed by commit a368ecde8a50 ("USB: core: Fix duplicate endpoint bug by clearing reserved bits in the descriptor") which clears reserved bits in bEndpointAddress during endpoint parsing. This causes fuzzed endpoint addresses like 0xf3 to be normalized to 0x83, which em28xx interprets as a vendor audio endpoint, enabling the is_audio_only + has_dual_ts code path that was previously unreachable with such descriptors.
Fix this by removing dev->dev_next->devlist from the global list in em28xx_close_extension() before the device is freed.
--- drivers/media/usb/em28xx/em28xx-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/usb/em28xx/em28xx-core.c +2 -0
@@ -1134,6 +1134,8 @@ void em28xx_close_extension(struct em28x ops->fini (dev); } } +if (dev->dev_next) +list_del (&dev->dev_next->devlist);list_del (&dev->devlist);mutex_unlock (&em28xx_devlist_mutex); }
Re: [PATCH 6.12 0191/1376] media: em28xx: fix use-after-free of dev_next->devlist on disconnect
Hi Greg/Sasha,
Quoted 43 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangong.Han <[email protected]>
commit
826915b6b65e2d3251e7248ea54289a22d748c84upstream.When a device with has_dual_ts=1 is probed and the
is_audio_onlypath is taken, both dev anddev->dev_nextare added to the globalem28xx_devlistviaem28xx_init_extension(). However, during disconnect,em28xx_close_extension(dev)only callslist_del(&dev->devlist), leavingdev->dev_next->devliststill linked in the global list. Whendev_nextis subsequently freed viakref_put(), its devlist entry becomes a dangling pointer inem28xx_devlist. The next device probe that callsem28xx_init_extension()triggers a list corruption BUG whenlist_add_taildetects the freed node.This bug was exposed by commit
a368ecde8a50("USB: core: Fix duplicate endpoint bug by clearing reserved bits in the descriptor") which clears reserved bits in bEndpointAddress during endpoint parsing. This causes fuzzed endpoint addresses like0xf3to be normalized to0x83, which em28xx interprets as a vendor audio endpoint, enabling theis_audio_only+has_dual_tscode path that was previously unreachable with such descriptors.Fix this by removing
dev->dev_next->devlistfrom the global list inem28xx_close_extension()before the device is freed.Fixes f410b4093fdd ("media: em28xx: split up em28xx_dvb_init to reduce stack size")Reported-by [email protected]Signed-off-by Jiangong.Han <[email protected]>Signed-off-by Hans Verkuil <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/media/usb/em28xx/em28xx-core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/usb/em28xx/em28xx-core.c void em28xx_close_extension(struct em28x · line 1138
Quoted 5 lines
drivers/media/usb/em28xx/em28xx-core.c +2
-0@@ -1134,6 +1134,8 @@ void em28xx_close_extension(struct em28x ops->fini (dev); } } +if (dev->dev_next) +list_del (&dev->dev_next->devlist);
I ran an AI-assisted backport review and have checked the report.
Upstream removes dev_next->devlist because that secondary node could be
on the global em28xx list. In 6.12, however, the immediately preceding
stable patch "[PATCH 6.12 0190/1376] media: em28xx: defer audio-only extension registration" already changed registration so only the primary device is linked. The secondary is reached through dev_next, and
its list node is never initialized or added.
Upstream source code:
if (dev->dev_next)
list_del(&dev->dev_next->devlist);Downstream 6.12.y registration code:
list_add_tail(&dev->devlist, &em28xx_devlist);
The new unconditional list_del(&dev->dev_next->devlist) can consequently operate on zero next and prev pointers during disconnect, causing a NULL deref ?
Let us revert this ?
thanks,
Harshit
Quoted 6 lines
drivers/media/usb/em28xx/em28xx-core.c +0
-0list_del (&dev->devlist);mutex_unlock (&em28xx_devlist_mutex); }
Sasha Levin
maintainerRe: [PATCH 6.12 0191/1376] media: em28xx: fix use-after-free of dev_next->devlist on disconnect
Quoted 5 lines
The new unconditional
list_del(&dev->dev_next->devlist)can consequently operate on zero next and prev pointers during disconnect, causing a NULL deref ?Let us revert this ?
The analysis holds, but mainline has the same defect, so a stable only revert would diverge from it and regress anyone moving to 7.3.
826915b6b65e ("media: em28xx: fix use-after-free of dev_next->devlist on disconnect") wants an upstream revert with Cc: stable on it, and then it reaches all seven trees the usual way. Hans, Jiangong, could one of you take that through linux-media?
Signature · 2 lines
Thanks, Sasha
Re: [PATCH 6.12 0191/1376] media: em28xx: fix use-after-free of dev_next->devlist on disconnect
Hi Sasha,
Quoted 9 lines · Sasha Levin
Quoted 5 lines
The new unconditional
list_del(&dev->dev_next->devlist)can consequently operate on zero next and prev pointers during disconnect, causing a NULL deref ?Let us revert this ?
The analysis holds, but mainline has the same defect, so a stable only revert would diverge from it and regress anyone moving to 7.3.
Agreed.
Quoted 4 lines
826915b6b65e("media: em28xx: fix use-after-free ofdev_next->devliston disconnect") wants an upstream revert with Cc: stable on it, and then it reaches all seven trees the usual way. Hans, Jiangong, could one of you take that through linux-media?
Should I send the revert ?
thanks,
Harshit>
Greg Kroah-Hartman
maintainerPATCH 192/1376 media: go7007: defer the ALSA v4l2 put until card release
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit 1bd456afeb8a515137e567967069fce6f8fcd23e upstream.
go7007_snd_init() already takes a v4l2_device reference for the ALSA side, but go7007_snd_remove() drops it immediately after calling snd_card_free_when_closed().
That is too early when a userspace process still has the capture PCM open. The ALSA card and its PCM callbacks remain alive until the last file is closed, so the release path can still reach struct go7007 through pcm->private_data and call go7007_snd_hw_free() after the V4L2 release path has freed the object.
Move the matching v4l2_device_put() to the ALSA card private_free callback so the existing ALSA reference covers the whole deferred card lifetime.
--- drivers/media/usb/go7007/snd-go7007.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/media/usb/go7007/snd-go7007.c +9 -1
@@ -195,6 +195,13 @@ static const struct snd_device_ops go700 .dev_free = go7007_snd_free, }; +static void go7007_snd_card_free (struct snd_card *card) +{ +struct go7007 *go = card->private_data; + +v4l2_device_put (&go->v4l2_dev); +} +int go7007_snd_init (struct go7007 *go) {static int dev;
@@ -245,6 +252,8 @@ int go7007_snd_init(struct go7007 *go) gosnd->substream =NULL ; go->snd_context = gosnd;v4l2_device_get (&go->v4l2_dev); + gosnd->card->private_data = go; + gosnd->card->private_free = go7007_snd_card_free; ++dev;return 0 ;
@@ -263,7 +272,6 @@ int go7007_snd_remove(struct go7007 *go)snd_card_disconnect (gosnd->card);snd_card_free_when_closed (gosnd->card); -v4l2_device_put (&go->v4l2_dev);return 0 ; }EXPORT_SYMBOL (go7007_snd_remove);
Greg Kroah-Hartman
maintainerPATCH 193/1376 media: i2c: alvium: Fix: Correct name of register in alvium_set_ctrl_auto_exposure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Hecht <[email protected]>
commit 58ca8a0bff9e78841a39863474b96e59ef60da19 upstream.
Write value for auto-exposure into correct register REG_BCRM_EXPOSURE_AUTO_RW instead of wrong register REG_BCRM_WHITE_BALANCE_AUTO_RW.
--- drivers/media/i2c/alvium-csi2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/alvium-csi2.c +1 -1
@@ -1291,7 +1291,7 @@ static int alvium_set_ctrl_auto_exposurestruct device *dev = &alvium->i2c_client->dev;int ret; - ret =alvium_write_hshake (alvium,REG_BCRM_WHITE_BALANCE_AUTO_RW , + ret =alvium_write_hshake (alvium,REG_BCRM_EXPOSURE_AUTO_RW , on ?0x02 :0x00 );if (ret) {dev_err (dev,"Fail to set autoexposure reg\n" );
Greg Kroah-Hartman
maintainerPATCH 194/1376 media: i2c: imx415: Return test pattern write errors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Narasimharao Vadlamudi <[email protected]>
commit 8cd5735b88d76dda80b089031747b6f18ee0bca2 upstream.
imx415_set_testpattern() accumulates failures from cci_write(), but drops the value and always returns success. Return the accumulated error so V4L2 reports failures to userspace.
--- drivers/media/i2c/imx415.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/i2c/imx415.c +1 -1
@@ -721,7 +721,7 @@ static int imx415_set_testpattern(structcci_write (sensor->regmap,IMX415_DIG_CLP_MODE ,0x01 , &ret);cci_write (sensor->regmap,IMX415_WRJ_OPEN ,0x01 , &ret); } -return 0 ; +return ret; }static int imx415_s_ctrl (struct v4l2_ctrl *ctrl)
Greg Kroah-Hartman
maintainerPATCH 195/1376 media: i2c: ov02a10: fix endpoint parsing use-after-free
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biren Pandya <[email protected]>
commit 94971ba0592ca77ec99b292226a4b398763315b8 upstream.
The ov02a10_check_hwcfg() function calls fwnode_handle_put(ep) immediately after allocating and parsing the endpoint. However, it subsequently calls fwnode_property_read_u32() using the same 'ep' handle, leading to a potential use-after-free.
Additionally, reading the optional 'ovti,mipi-clock-voltage' property used to overwrite the 'ret' variable. If the property was missing, 'ret' would become negative, and this failure code would be incorrectly returned at the end of the function, causing probe to fail entirely.
Fix the use-after-free by moving fwnode_property_read_u32() before the endpoint is parsed and freed. Avoid the error leak by not assigning the result of fwnode_property_read_u32() to 'ret'.
--- drivers/media/i2c/ov02a10.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
drivers/media/i2c/ov02a10.c +5 -7
@@ -822,18 +822,16 @@ static int ov02a10_check_hwcfg(struct deif (!ep)return -ENXIO ; +/* Optional indication of MIPI clock voltage unit */ +if (!fwnode_property_read_u32 (ep,"ovti,mipi-clock-voltage" , + &clk_volt)) + ov02a10->mipi_clock_voltage = clk_volt; + ret =v4l2_fwnode_endpoint_alloc_parse (ep, &bus_cfg);fwnode_handle_put (ep);if (ret)return ret; -/* Optional indication of MIPI clock voltage unit */ - ret =fwnode_property_read_u32 (ep,"ovti,mipi-clock-voltage" , - &clk_volt); - -if (!ret) - ov02a10->mipi_clock_voltage = clk_volt; -for (i =0 ; i <ARRAY_SIZE (link_freq_menu_items); i++) {for (j =0 ; j < bus_cfg.nr_of_link_frequencies; j++) { if (link_freq_menu_items[i] ==
Greg Kroah-Hartman
maintainerPATCH 196/1376 media: i2c: ov7740: fix use-after-destroy in remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biren Pandya <[email protected]>
commit 5d1b3dea5a44124bab6c14a2d71b977dabed54e7 upstream.
The ov7740_remove() function had a severe teardown order bug where it destroyed the driver's mutex before freeing the V4L2 control handler which relies on that mutex, leading to a use-after-destroy kernel panic. Furthermore, the driver explicitly called v4l2_ctrl_handler_free() and mutex_destroy() sequentially, but then called ov7740_free_controls() which invokes both of them a second time, resulting in a double-free.
This patch fixes the issue by unregistering the subdevice first, and relying exclusively on ov7740_free_controls() to safely tear down the mutex and control handler in the correct order.
--- drivers/media/i2c/ov7740.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/media/i2c/ov7740.c +1 -3
@@ -1119,10 +1119,8 @@ static void ov7740_remove(struct i2c_clistruct v4l2_subdev *sd =i2c_get_clientdata (client); struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); -mutex_destroy (&ov7740->mutex); -v4l2_ctrl_handler_free (ov7740->subdev.ctrl_handler); -media_entity_cleanup (&ov7740->subdev.entity);v4l2_async_unregister_subdev (sd); +media_entity_cleanup (&ov7740->subdev.entity);ov7740_free_controls (ov7740);pm_runtime_get_sync (&client->dev);
Greg Kroah-Hartman
maintainerPATCH 197/1376 media: intel/ipu6: fix async notifier cleanup leak on parse error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit abb1f808ceab5a3275f8a6b4e37cff17f9f781c1 upstream.
isys_notifier_init() calls v4l2_async_nf_init() and then adds fwnode remote subdevs in a loop with v4l2_async_nf_add_fwnode_remote(). If an endpoint parse or add fails partway through the loop, it jumps to err_parse and returns without calling v4l2_async_nf_cleanup(), leaking every v4l2_async_connection already added to the notifier's waiting list.
The register-failure path just below already cleans up correctly, and the caller only tears the notifier down (isys_notifier_cleanup()) once isys_notifier_init() has returned success. Clean up the notifier on the parse error path too.
--- drivers/media/pci/intel/ipu6/ipu6-isys.c | 1 + 1 file changed, 1 insertion(+)
drivers/media/pci/intel/ipu6/ipu6-isys.c +1 -0
@@ -761,6 +761,7 @@ static int isys_notifier_init(struct ipu err_parse:fwnode_handle_put (ep); +v4l2_async_nf_cleanup (&isys->notifier);return ret; }
Greg Kroah-Hartman
maintainerPATCH 198/1376 media: meson: vdec: fix NULL pointer deref in vdec_try_fmt_common
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Hewitt <[email protected]>
commit 20aa934ace6917262ff579a73ec018d06a7bad1c upstream.
When VIDIOC_TRY_FMT is called with an unsupported pixel format on the OUTPUT queue, vdec_try_fmt_common() falls back to V4L2_PIX_FMT_MPEG2. However, if a distro has locally patched MPEG2 support out (as it has been broken for some time) the platform format table does not contain MPEG2 so find_format() returns NULL and the subsequent dereference of fmt_out->max_width triggers a NULL pointer dereference.
Fix this by falling back to the first format in the platform's format array instead of hardcoding V4L2_PIX_FMT_MPEG2. This is always valid since every platform defines at least one format.
--- drivers/staging/media/meson/vdec/vdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/media/meson/vdec/vdec.c +2 -2
@@ -506,8 +506,8 @@ vdec_try_fmt_common(struct amvdec_sessiocase V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : fmt_out =find_format (fmts, size, pixmp->pixelformat);if (!fmt_out) { - pixmp->pixelformat =V4L2_PIX_FMT_MPEG2 ; - fmt_out =find_format (fmts, size, pixmp->pixelformat); + pixmp->pixelformat = fmts[0 ].pixfmt; + fmt_out = &fmts[0 ]; }break ;case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
Greg Kroah-Hartman
maintainerPATCH 199/1376 media: platform: mtk-mdp3: Fix SCP device refcounting
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 55793e4665b7f15151e6f5ab51ca980e73abed5d upstream.
mdp_probe() first tries to get the SCP handle with scp_get(). When that fails, it falls back to looking up the SCP platform device with __get_pdev_by_id() and then reads its driver data.
The fallback lookup returns the platform device with a reference, just like scp_get() does. However, the fallback path currently drops that reference immediately after platform_get_drvdata(). The driver later still calls scp_put(mdp->scp) unconditionally from the probe error path and from mdp_video_device_release(), which drops the SCP device reference again.
Keep the fallback reference until the existing scp_put() call, so that the fallback path follows the same ownership rules as the scp_get() path.
--- drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 1 - 1 file changed, 1 deletion(-)
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +0 -1
@@ -311,7 +311,6 @@ static int mdp_probe(struct platform_dev goto err_destroy_clock_wq; } mdp->scp =platform_get_drvdata (mm_pdev); -put_device (&mm_pdev->dev); } mdp->rproc_handle =scp_get_rproc (mdp->scp);
Greg Kroah-Hartman
maintainerPATCH 200/1376 media: platform: mtk-mdp3: fix NULL deref on failed SCP lookup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 90368323fb244da0504e3da37a182f8e89bcc3b9 upstream.
Add the missing sanity check after looking up the SCP to avoid dereferencing a NULL-pointer in case its driver has not yet been bound.
--- drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +5 -0
@@ -313,6 +313,11 @@ static int mdp_probe(struct platform_dev mdp->scp =platform_get_drvdata (mm_pdev); } +if (!mdp->scp) { + ret = -EPROBE_DEFER ; + goto err_destroy_clock_wq; + } + mdp->rproc_handle =scp_get_rproc (mdp->scp);dev_dbg (&pdev->dev,"MDP rproc_handle: %pK" , mdp->rproc_handle);
Greg Kroah-Hartman
maintainerPATCH 201/1376 media: nxp: imx8-isi: Fix stream ID validation bypass in crossbar routing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <[email protected]>
commit 795bd2863591f2fee33fab8f10cf9c383c94342e upstream.
The crossbar routing validation has a critical bug where it validates the wrong routing table, allowing userspace to bypass validation entirely.
The __mxc_isi_crossbar_set_routing() function is called to validate and apply a new routing table from userspace. However, the validation loop iterates over state->routing (the currently active routing table) instead of the routing parameter (the new table being validated):
for_each_active_route(&state->routing, route) {This means userspace can submit any invalid routing configuration and it will pass validation as long as the currently active routing is valid. This is a security issue as it allows userspace to configure routes that violate hardware constraints, potentially causing undefined hardware behavior.
Fix by validating the routing table that will actually be applied.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +1 -1
@@ -107,7 +107,7 @@ static int __mxc_isi_crossbar_set_routinreturn ret;/* The memory input can be routed to the first pipeline only. */ -for_each_active_route (&state->routing, route) { +for_each_active_route (routing, route) {if (route->sink_pad == xbar->num_sinks -1 && route->source_pad != xbar->num_sinks) { dev_dbg(xbar->isi->dev,
Greg Kroah-Hartman
maintainerPATCH 202/1376 media: nxp: imx8-isi: Correct color map between V4L2 and ISI
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <[email protected]>
commit 4640ec1cb0121473867e7a6850c7449340dcd428 upstream.
Fix the ISI input format for the color map V4L2_PIX_FMT_XBGR32 in memory-to-memory mode.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +1 -1
@@ -151,7 +151,7 @@ static const struct mxc_isi_format_info .fourcc = V4L2_PIX_FMT_XBGR32, .type =MXC_ISI_VIDEO_CAP |MXC_ISI_VIDEO_M2M_OUT | MXC_ISI_VIDEO_M2M_CAP, - .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8, .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888, .mem_planes = 1, .color_planes = 1,
Greg Kroah-Hartman
maintainerPATCH 203/1376 media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <[email protected]>
commit 77e60a2c5d824ad2d493f53dc17137ae065753fe upstream.
Use BIT_ULL() instead of BIT() for u64 stream masks to avoid incorrect results on 32-bit architectures when stream IDs are 32 or greater.
--- drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +2 -2
@@ -145,10 +145,10 @@ mxc_isi_crossbar_xlate_streams(struct mx*/ for_each_active_route (&state->routing, route) {if (route->source_pad != source_pad || - !(source_streams &BIT (route->source_stream))) + !(source_streams &BIT_ULL (route->source_stream)))continue ; - sink_streams |=BIT (route->sink_stream); + sink_streams |=BIT_ULL (route->sink_stream); sink_pad = route->sink_pad; }
Greg Kroah-Hartman
maintainerPATCH 204/1376 media: rc: sunxi-cir: Unregister rc device on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 479aa6fa8c50f1052f1451326ef7d4d586d340c3 upstream.
After rc_register_device() succeeds, later probe failures must undo the registration with rc_unregister_device(). The current error path jumps to the allocation cleanup label and only calls rc_free_device(), leaving the rc device registration and resources created by rc_register_device() behind.
Add a registered-device unwind label for the IRQ lookup, IRQ request, and hardware initialization failure paths. Keep rc_free_device() for failures before rc_register_device() succeeds.
--- drivers/media/rc/sunxi-cir.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/media/rc/sunxi-cir.c +6 -3
@@ -344,22 +344,25 @@ static int sunxi_ir_probe(struct platfor ir->irq =platform_get_irq (pdev,0 );if (ir->irq <0 ) { ret = ir->irq; - goto exit_free_dev; + goto exit_unregister_dev; } ret =devm_request_irq (dev, ir->irq, sunxi_ir_irq,0 ,SUNXI_IR_DEV , ir);if (ret) {dev_err (dev,"failed request irq\n" ); - goto exit_free_dev; + goto exit_unregister_dev; } ret =sunxi_ir_hw_init (dev);if (ret) - goto exit_free_dev; + goto exit_unregister_dev;dev_info (dev,"initialized sunXi IR driver\n" );return 0 ; +exit_unregister_dev: +rc_unregister_device (ir->rc); + exit_free_dev:rc_free_device (ir->rc);
Greg Kroah-Hartman
maintainerPATCH 205/1376 media: rtl2832_sdr: use vb2_video_unregister_device() on remove to fix DMA leak
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit dabb047c62668f280998e29117c55e41aabac336 upstream.
rtl2832_sdr_remove() runs on USB disconnect and clears dev->udev to NULL before any pending streaming teardown has run. When user space later closes its file descriptor, vb2 calls rtl2832_sdr_stop_streaming() which in turn calls rtl2832_sdr_free_stream_bufs(). That helper releases each coherent buffer with:
usb_free_coherent(dev->udev, dev->buf_size,
dev->buf_list[dev->buf_num],
dev->dma_addr[dev->buf_num]);usb_free_coherent() returns immediately when its dev argument is NULL, so every DMA stream buffer that was live at disconnect is silently leaked. The URBs allocated in rtl2832_sdr_alloc_urbs() outlive the device for the same reason.
The rtl2832_sdr driver uses vb2_fop_release() in its file_operations, so replace video_unregister_device(&dev->vdev) with vb2_video_unregister_device(&dev->vdev) and move it before clearing dev->udev. vb2_video_unregister_device() releases the vb2 queue, which synchronously runs rtl2832_sdr_stop_streaming() if streaming is active, so URBs and coherent DMA stream buffers are freed while dev->udev is still valid.
vb2_video_unregister_device() locks vdev->queue->lock (vb_queue_lock) internally, and stop_streaming() locks v4l2_lock, so the previous outer mutex_lock(&dev->vb_queue_lock) / mutex_lock(&dev->v4l2_lock) pair around the unregister sequence would self-deadlock and has been removed. A short v4l2_lock critical section around dev->udev = NULL remains so any ioctl path that still holds the file descriptor sees coherent state.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
--- drivers/media/dvb-frontends/rtl2832_sdr.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
drivers/media/dvb-frontends/rtl2832_sdr.c +13 -5
@@ -1479,14 +1479,22 @@ static void rtl2832_sdr_remove(struct pldev_dbg (&pdev->dev,"\n" ); -mutex_lock (&dev->vb_queue_lock); +/* +* vb2_video_unregister_device() releases the vb2 queue, which +* triggers rtl2832_sdr_stop_streaming() if streaming is active. +* stop_streaming() uses dev->udev to free URBs and coherent DMA +* stream buffers via usb_free_coherent(), so it must run before +* dev->udev is cleared. vb2_video_unregister_device() locks +* vb_queue_lock internally and stop_streaming() locks v4l2_lock, +* so neither may be held by the caller. +*/ +v4l2_device_disconnect (&dev->v4l2_dev); +vb2_video_unregister_device (&dev->vdev); +mutex_lock (&dev->v4l2_lock); -/* No need to keep the urbs around after disconnection */ dev->udev =NULL ; -v4l2_device_disconnect (&dev->v4l2_dev); -video_unregister_device (&dev->vdev);mutex_unlock (&dev->v4l2_lock); -mutex_unlock (&dev->vb_queue_lock); +v4l2_device_put (&dev->v4l2_dev);module_put (pdev->dev.parent->driver->owner); }
Greg Kroah-Hartman
maintainerPATCH 206/1376 media: rtl2832_sdr: release URBs and stream buffers on start_streaming() failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <[email protected]>
commit fe50cdaebf12cd32ff9a44d92bfd6fbc2300dbd4 upstream.
rtl2832_sdr_start_streaming() calls rtl2832_sdr_alloc_stream_bufs(), rtl2832_sdr_alloc_urbs() and rtl2832_sdr_submit_urbs() in sequence and shares a single err: label that only unlocks the mutex and returns. When alloc_urbs() succeeds but submit_urbs() fails, or when alloc_urbs() itself returns -ENOMEM after alloc_stream_bufs() has already succeeded, the URBs and/or the coherent DMA stream buffers stay allocated while streaming reports failure to vb2. Two latent defects follow on the next VIDIOC_STREAMON:
1) rtl2832_sdr_alloc_stream_bufs() unconditionally resets dev->buf_num to 0 and overwrites dev->buf_list[]/dev->dma_addr[], permanently leaking the coherent DMA memory allocated by the previous attempt.
2) rtl2832_sdr_alloc_urbs() never resets dev->urbs_initialized and only increments it. After a second successful pass urbs_initialized can exceed MAX_BULK_BUFS, so the subsequent rtl2832_sdr_free_urbs() walks from urbs_initialized - 1 down to 0 and reads past the end of dev->urb_list[], passing garbage pointers to usb_free_urb().
Mirror the teardown that stop_streaming() already performs: on the error path call rtl2832_sdr_free_urbs() and rtl2832_sdr_free_stream_bufs() before unlocking. Both helpers are idempotent (free_urbs kills and zeros urbs_initialized; free_stream_bufs is gated on URB_BUF and clears the buf_num counter), so partial-failure paths and the no-allocation paths remain safe.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
--- drivers/media/dvb-frontends/rtl2832_sdr.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/media/dvb-frontends/rtl2832_sdr.c +3 -0
@@ -906,9 +906,12 @@ static int rtl2832_sdr_start_streaming(s goto err;mutex_unlock (&dev->v4l2_lock); +return 0 ; err: +rtl2832_sdr_free_urbs (dev); +rtl2832_sdr_free_stream_bufs (dev);rtl2832_sdr_cleanup_queued_bufs (dev,VB2_BUF_STATE_QUEUED );mutex_unlock (&dev->v4l2_lock);
Greg Kroah-Hartman
maintainerPATCH 207/1376 media: s2255: bound JPEG frame size before copying into the buffer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit e504cc888f42999dd76b6a43788c422610f2aad2 upstream.
s2255_fillbuff() memcpy()s vc->jpg_size bytes of a captured JPEG/MJPEG frame into the vb2 plane. vc->jpg_size is taken verbatim from the S2255_MARKER_FRAME header the device sends (pdword[4] in save_frame()) and, unlike the frame payload length just above it, is never bounded:
payload = le32_to_cpu(pdword[3]); if (payload > vc->req_image_size) /* payload is checked ... */ return -EINVAL; vc->pkt_size = payload; vc->jpg_size = le32_to_cpu(pdword[4]); /* ... jpg_size is not */
A malicious or malfunctioning device can therefore report a jpg_size larger than the destination vb2 plane, and the memcpy() writes past it. jpg_size is a signed int, so a value with the top bit set also turns into a huge length.
Reject a frame whose jpg_size is negative or exceeds the plane size before copying it.
--- drivers/media/usb/s2255/s2255drv.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/media/usb/s2255/s2255drv.c +6 -0
@@ -617,6 +617,12 @@ static void s2255_fillbuff(struct s2255_break ;case V4L2_PIX_FMT_JPEG :case V4L2_PIX_FMT_MJPEG : +if (jpgsize <0 || + jpgsize >vb2_plane_size (&buf->vb.vb2_buf,0 )) { +dprintk (dev,1 ,"bad JPEG frame size %d\n" , + jpgsize); +break ; + }vb2_set_plane_payload (&buf->vb.vb2_buf,0 , jpgsize);memcpy (vbuf, tmpbuf, jpgsize);break ;
Greg Kroah-Hartman
maintainerPATCH 208/1376 media: s2255: check firmware size before reading trailing marker
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lei Huang <[email protected]>
commit 330f2936ab768c7215322a476f033143e8891d28 upstream.
s2255_probe() reads a 4-byte marker and version from the last 8 bytes of the firmware blob (fw->data[fw_size - 8] and [fw_size - 4]). If the firmware file is shorter than 8 bytes, fw_size - 8 underflows and the access reads out of bounds. Validate the firmware size before indexing.
--- drivers/media/usb/s2255/s2255drv.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/media/usb/s2255/s2255drv.c +5 -0
@@ -2289,6 +2289,11 @@ static int s2255_probe(struct usb_interf }/* check the firmware is valid */ fw_size = dev->fw_data->fw->size; +if (fw_size <8 ) { +dev_err (&interface->dev,"Firmware invalid: too small.\n" ); + retval = -ENODEV ; + goto errorFWMARKER; + } pdata = (__le32 *) &dev->fw_data->fw->data[fw_size -8 ];if (*pdata !=S2255_FW_MARKER ) {
Greg Kroah-Hartman
maintainerPATCH 209/1376 media: saa7164: fix cleanup on resource allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 28e84c6e2e6753ed238ea097b2842a32a6a6879b upstream.
saa7164_dev_setup() adds the device to the global saa7164_devlist before requesting the PCI BAR memory regions.
If get_resources() fails, saa7164_dev_setup() decrements the device count and returns an error, but leaves the device on saa7164_devlist. The probe error path then frees the device, leaving a dangling entry on the global list.
Reuse the existing MMIO mapping error path to remove the device from saa7164_devlist and decrement the device count before returning.
Also release BAR0 if it was successfully requested but the BAR2 request fails.
--- drivers/media/pci/saa7164/saa7164-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/media/pci/saa7164/saa7164-core.c +5 -3
@@ -878,6 +878,9 @@ static int get_resources(struct saa7164_if (request_mem_region (pci_resource_start (dev->pci,2 ),pci_resource_len (dev->pci,2 ), dev->name))return 0 ; + +release_mem_region (pci_resource_start (dev->pci,0 ), +pci_resource_len (dev->pci,0 )); } printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n",
@@ -1000,8 +1003,7 @@ static int saa7164_dev_setup(struct saa7 dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); - saa7164_devcount--; -return -ENODEV ; + goto err_devlist; }/* PCI/e allocations */
@@ -1039,7 +1041,7 @@ err_ioremap_bar2:iounmap (dev->lmmio); err_ioremap_bar0:release_resources (dev); - +err_devlist: scoped_guard(mutex, &devlist) {list_del (&dev->devlist); }
Greg Kroah-Hartman
maintainerPATCH 210/1376 media: tda18250: fix possible integer overflow
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Krutskih <[email protected]>
commit 6dd8e257f7cafda7fbf10d81b3c55c9bba4825f4 upstream.
Integer overflow may occur, when variable exp equals to zero. Result of shift 1 << (exp - 1) may then leads to undefined behavior.
--- drivers/media/tuners/tda18250.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/tuners/tda18250.c +2 -2
@@ -440,8 +440,8 @@ static int tda18250_pll_calc(struct dvb_ goto err; exp = (uval &0x70 ) >>4 ; -if (exp >5 ) - exp =0 ; +if (exp ==0 || exp >5 ) + exp =1 ; lopd =1 << (exp -1 ); scale = uval &0x0f ; fvco = lopd * scale * ((c->frequency /1000 ) + dev->if_frequency);
Greg Kroah-Hartman
maintainerPATCH 211/1376 media: v4l2-async: avoid deleting unlinked ASC entry on link error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 47d82b605351c0e04f6365e42c8ffe2fcfdba615 upstream.
v4l2_async_match_notify() creates ancillary media links before adding asc->asc_subdev_entry to sd->asc_list.
If ancillary link creation fails, the function jumps to err_call_unbind while asc_subdev_entry has not been linked yet. Async connections are zero-allocated, so the list entry still has NULL next and prev pointers on this path. Calling list_del() on it can therefore dereference NULL instead of returning the original link creation error.
Do not delete asc_subdev_entry from err_call_unbind. There is no list insertion to undo on this path; the bound callback and sub-device registration are the operations that need to be rolled back.
--- drivers/media/v4l2-core/v4l2-async.c | 1 - 1 file changed, 1 deletion(-)
drivers/media/v4l2-core/v4l2-async.c +0 -1
@@ -392,7 +392,6 @@ static int v4l2_async_match_notify(struc err_call_unbind:v4l2_async_nf_call_unbind (notifier, sd, asc); -list_del (&asc->asc_subdev_entry); err_unregister_subdev:if (registered)
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.12.110-rc1-g5915db8cc000 #1 SMP PREEMPT_DYNAMIC Sat Sep 12 11:43:58 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Greg Kroah-Hartman
maintainerPATCH 212/1376 media: v4l2-ctrls: Allow unknown HDR10 white point and luminance
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <[email protected]>
commit 49af0c7cad889f7dabe5cf080b019392066122a3 upstream.
SMPTE ST 2086 defines the nominal ranges for mastering display chromaticity and luminance values. Its Annex A also documents that CTA 861-G uses zero maximum and minimum luminance values to signal that the corresponding values are unknown, and the xy chromaticity coordinate (0, 0) to signal that the white point chromaticity is unknown.
The V4L2 HDR10 mastering display compound control currently rejects these values. Consequently, an unknown white point or luminance value prevents the entire compound control from being updated, making the other valid mastering display metadata unavailable to userspace.
Accept (0, 0) as an unknown white point and zero as an unknown maximum or minimum mastering luminance. Continue to reject partially zero white point coordinates and non-zero values outside the nominal ranges. Display primary validation remains unchanged.
Document the newly accepted unknown values in the V4L2 userspace API.
--- Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst | 12 ++ drivers/media/v4l2-core/v4l2-ctrls-core.c | 49 ++++++---- 2 files changed, 44 insertions(+), 17 deletions(-)
Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst +11 -1
@@ -79,15 +79,25 @@ Colorimetry Control IDs - ``white_point_x`` - Specifies the normalized x chromaticity coordinate of the white point of the mastering display in increments of 0.00002. + When both ``white_point_x`` and ``white_point_y`` are zero, + the white point chromaticity is unknown. If either coordinate is + non-zero, both coordinates shall be within their valid ranges. * - __u16 - ``white_point_y`` - Specifies the normalized y chromaticity coordinate of the white point of the mastering display in increments of 0.00002. + When both ``white_point_x`` and ``white_point_y`` are zero, + the white point chromaticity is unknown. If either coordinate is + non-zero, both coordinates shall be within their valid ranges. * - __u32 - ``max_luminance`` - Specifies the nominal maximum display luminance of the mastering display in units of 0.0001 cd/m\ :sup:`2`. + A value of zero indicates that the nominal maximum display + luminance is unknown. * - __u32 - ``min_luminance`` - - specifies the nominal minimum display luminance of the mastering + - Specifies the nominal minimum display luminance of the mastering display in units of 0.0001 cd/m\ :sup:`2`. + A value of zero indicates that the nominal minimum display + luminance is unknown.
drivers/media/v4l2-core/v4l2-ctrls-core.c +33 -16
57 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 213/1376 media: v4l2-fwnode: Fix fwnode leak in v4l2_fwnode_parse_link
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biren Pandya <[email protected]>
commit a6e86efd7f85e519bf48417f41923f8bd51f1597 upstream.
In v4l2_fwnode_parse_link(), the remote endpoint fwnode reference is acquired using fwnode_graph_get_remote_endpoint(). This reference is properly released in the error paths, but it is leaked on the success path.
Add the missing fwnode_handle_put() before returning 0 to prevent the reference leak.
--- drivers/media/v4l2-core/v4l2-fwnode.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/v4l2-core/v4l2-fwnode.c +2 -0
@@ -582,6 +582,8 @@ int v4l2_fwnode_parse_link(struct fwnodeif (!link->remote_node) goto err_put_remote_endpoint; +fwnode_handle_put (fwnode); +return 0 ; err_put_remote_endpoint:
Greg Kroah-Hartman
maintainerPATCH 214/1376 media: venus: fix payload size returned by parse_caps() and parse_alloc_mode()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohammed EL Kadiri <[email protected]>
commit a51cea23e409278f6e2ea072280aba93cc1dd75e upstream.
parse_caps() and parse_alloc_mode() return only the size of their fixed header fields, excluding the flexible array payload. hfi_parser() uses this return value to advance through the firmware response buffer, so underreporting causes parser desynchronization.
Return the full consumed size (header + entries), matching the correct pattern used by parse_profile_level().
--- drivers/media/platform/qcom/venus/hfi_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/platform/qcom/venus/hfi_parser.c +2 -2
@@ -85,7 +85,7 @@ parse_alloc_mode(struct venus_core *core type++; } -return sizeof (*mode); +return mode->num_entries *sizeof (u32) +sizeof (*mode); } static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
@@ -146,7 +146,7 @@ parse_caps(struct venus_core *core, u32for_each_codec (core->caps,ARRAY_SIZE (core->caps), codecs, domain, fill_caps, caps_arr, num_caps); -return sizeof (*caps); +return num_caps *sizeof (*cap) +sizeof (u32); } static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
Greg Kroah-Hartman
maintainerPATCH 215/1376 media: venus: fix payload size calculation in parse_raw_formats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohammed EL Kadiri <[email protected]>
commit bd595b745eb770e80347c31ffc25351046935305 upstream.
The consumed size is computed after the loop using the num_planes value from the last iteration for all entries. When entries have different plane counts, this produces an incorrect total.
Accumulate the actual size during the loop instead.
--- drivers/media/platform/qcom/venus/hfi_parser.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/media/platform/qcom/venus/hfi_parser.c +2 -3
@@ -171,7 +171,7 @@ parse_raw_formats(struct venus_core *coru32 entries = fmt->format_entries;unsigned int i =0 ;u32 num_planes =0 ; -u32 size; +u32 size =2 *sizeof (u32);while (entries) { num_planes = pinfo->num_planes;
@@ -186,6 +186,7 @@ parse_raw_formats(struct venus_core *corif (pinfo->num_planes >MAX_PLANES )break ; + size +=sizeof (*constr) * num_planes +2 *sizeof (u32); pinfo = (void *)pinfo +sizeof (*constr) * num_planes +2 *sizeof (u32); entries--;
@@ -193,8 +194,6 @@ parse_raw_formats(struct venus_core *corfor_each_codec (core->caps,ARRAY_SIZE (core->caps), codecs, domain, fill_raw_fmts, rawfmts, i); - size = fmt->format_entries * (sizeof (*constr) * num_planes +2 *sizeof (u32)) - +2 *sizeof (u32);return size; }
Greg Kroah-Hartman
maintainerPATCH 216/1376 media: video-i2c: fix kthread error pointer left in kthread_vid_cap on failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
commit 76e379754ba618989f6215be608d5c04774a611d upstream.
kthread_run() returns an ERR_PTR on failure, not NULL. When start_streaming() fails, data->kthread_vid_cap is left holding this error pointer instead of being cleared.
This causes two subsequent bugs:
1. A future call to start_streaming() sees a non-NULL kthread_vid_cap and returns 0 (success) immediately, without actually starting the capture thread.
2. A call to stop_streaming() checks 'kthread_vid_cap == NULL' which is false for an error pointer, and proceeds to call kthread_stop() on the error pointer, leading to a kernel crash.
Fix this by resetting kthread_vid_cap to NULL on failure before jumping to the error path.
--- drivers/media/i2c/video-i2c.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/media/i2c/video-i2c.c +6 -2
@@ -533,8 +533,12 @@ static int start_streaming(struct vb2_qu data->kthread_vid_cap =kthread_run (video_i2c_thread_vid_cap, data,"%s-vid-cap" , data->v4l2_dev.name); ret =PTR_ERR_OR_ZERO (data->kthread_vid_cap); -if (!ret) -return 0 ; +if (ret) { + data->kthread_vid_cap =NULL ; + goto error_rpm_put; + } + +return 0 ; error_rpm_put:pm_runtime_mark_last_busy (dev);
Greg Kroah-Hartman
maintainerPATCH 217/1376 media: vimc: fix pixel format lookup in enum_framesizes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arash Golgol <[email protected]>
commit ad4c65fa30cfb00e2e06adae9a8eb407086eaa66 upstream.
vimc_capture_enum_framesizes() looks up the requested format using vimc_pix_map_by_code(), which searches the pix map table by media bus code (MEDIA_BUS_FMT_*).
However, v4l2_frmsizeenum::pixel_format holds a V4L2 pixel format (V4L2_PIX_FMT_*), not a media bus code, so valid pixel formats end up being rejected with -EINVAL.
Fix this by using vimc_pix_map_by_pixelformat() instead, which performs the lookup by pixel format as the ioctl expects.
--- drivers/media/test-drivers/vimc/vimc-capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/media/test-drivers/vimc/vimc-capture.c +2 -2
@@ -177,8 +177,8 @@ static int vimc_capture_enum_framesizes(if (fsize->index)return -EINVAL ; -/* Only accept code in the pix map table */ - vpix =vimc_pix_map_by_code (fsize->pixel_format); +/* Only accept pixel_format in the pix map table */ + vpix =vimc_pix_map_by_pixelformat (fsize->pixel_format);if (!vpix)return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 218/1376 media: zoran: Avoid freeing a registered video_device twice
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit 0735e0b5a96761a9ce277a238e834008ad92a0a5 upstream.
zoran_init_video_device() installs zoran_vdev_release() as the video_device release callback through zoran_template. After video_register_device() succeeds, video_unregister_device() drops the registered video_device reference and the V4L2 core eventually invokes that release callback, which kfree()s the video_device.
zoran_exit_video_devices() called video_unregister_device() and then kfree(zr->video_dev), so device teardown could free the same video_device twice.
Remove the direct kfree() and clear the cached pointer after unregistering. The pre-registration failure path keeps its manual free because the video_device was not registered there.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/media/pci/zoran/zoran_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/pci/zoran/zoran_card.c +1 -1
@@ -889,7 +889,7 @@ static int zoran_init_video_device(strucstatic void zoran_exit_video_devices (struct zoran *zr) {video_unregister_device (zr->video_dev); -kfree (zr->video_dev); + zr->video_dev =NULL ; }static int zoran_init_video_devices (struct zoran *zr)
Greg Kroah-Hartman
maintainerPATCH 219/1376 media: chips-media: wave5: Guard bit depth check with initial_info_obtained
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jackson Lee <[email protected]>
commit 1551386934ad43d934c3bb7317929207e1edcd6a upstream.
When CAPTURE STREAMON is called before the VPU has completed sequence initialization (initial_info_obtained == false), the initial_info fields contain uninitialized data. The driver checksluma_bitdepth and rejects anything other than 8-bit, so garbage values (e.g. 15) cause STREAMON to fail spuriously.
This is reproducible with the following multi-threaded test scenario:
1. Allocate 2 CAPTURE buffers.
2. Call STREAMON on the CAPTURE queue.
3. Call DQBUF, which blocks waiting for a decoded frame.
4. A second thread calls STREAMOFF on the CAPTURE queue.
5. The blocked DQBUF should be released, allowing graceful termination.
At step 2, STREAMON reads uninitialized luma_bitdepth and rejects the stream, causing the test to fail.
Fix this by checking initial_info_obtained before accessing the bit depth fields, so the validation is only performed when the sequence info has actually been parsed by the VPU.
--- drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +2 -1
@@ -1430,6 +1430,7 @@ static int wave5_vpu_dec_start_streaming }else if (q->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ) {struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info; +struct dec_info *p_dec_info = &inst->codec_info->dec_info;if (inst->state ==VPU_INST_STATE_STOP ) ret =switch_state (inst,VPU_INST_STATE_INIT_SEQ );
@@ -1437,6 +1438,7 @@ static int wave5_vpu_dec_start_streaming goto return_buffers;if (inst->state ==VPU_INST_STATE_INIT_SEQ && + p_dec_info->initial_info_obtained && inst->dev->product_code ==WAVE521C_CODE ) {if (initial_info->luma_bitdepth !=8 ) { dev_info(inst->dev->dev, "%s: no support for %d bit depth",
@@ -1445,7 +1447,6 @@ static int wave5_vpu_dec_start_streaming goto return_buffers; } } - }return ret;
Greg Kroah-Hartman
maintainerPATCH 220/1376 scsi: qla2xxx: Zero SFP DMA buffer in FRU/I2C bsg handlers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit b47d4a1547d9ef21b2e9d1a739fe2204d4be05dc upstream.
The FRU and I2C bsg handlers stage their transfer in a DMA_POOL_SIZE (256-byte) bounce buffer obtained from dma_pool_alloc(), which does not zero the allocation. They initialize only a few leading bytes before handing the buffer to qla2x00_write_sfp().
qla2x00_write_sfp() can override the transfer length with a user-supplied value:
if (len == 1) opt |= BIT_0; if (opt & BIT_0) len = *sfp;
*sfp is the first byte of the (user-controlled) payload, so len can grow up to 255. The device then DMA-reads len bytes from the 256-byte pool buffer. Since only a small prefix was written
(e.g. MAX_FRU_SIZE == 36 bytes for a FRU version, one byte for a FRU status register), the hardware reads past the initialized region and writes up to ~219 bytes of stale DMA-pool heap memory to the device flash.
Allocate the buffer with dma_pool_zalloc() in all five FRU/I2C handlers so any bytes beyond the initialized data are zero rather than stale heap contents.
--- drivers/scsi/qla2xxx/qla_bsg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/scsi/qla2xxx/qla_bsg.c +5 -5
@@ -1565,7 +1565,7 @@ qla2x00_update_fru_versions(struct bsg_jstruct qla_image_version *image;uint32_t count;dma_addr_t sfp_dma; -void *sfp =dma_pool_alloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma); +void *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
@@ -1616,7 +1616,7 @@ qla2x00_read_fru_status(struct bsg_job *uint8_t bsg[DMA_POOL_SIZE ];struct qla_status_reg *sr = (void *)bsg;dma_addr_t sfp_dma; -uint8_t *sfp =dma_pool_alloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma); +uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
@@ -1667,7 +1667,7 @@ qla2x00_write_fru_status(struct bsg_jobuint8_t bsg[DMA_POOL_SIZE ];struct qla_status_reg *sr = (void *)bsg;dma_addr_t sfp_dma; -uint8_t *sfp =dma_pool_alloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma); +uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
@@ -1714,7 +1714,7 @@ qla2x00_write_i2c(struct bsg_job *bsg_jouint8_t bsg[DMA_POOL_SIZE ];struct qla_i2c_access *i2c = (void *)bsg;dma_addr_t sfp_dma; -uint8_t *sfp =dma_pool_alloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma); +uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
@@ -1760,7 +1760,7 @@ qla2x00_read_i2c(struct bsg_job *bsg_jobuint8_t bsg[DMA_POOL_SIZE ];struct qla_i2c_access *i2c = (void *)bsg;dma_addr_t sfp_dma; -uint8_t *sfp =dma_pool_alloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma); +uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
Greg Kroah-Hartman
maintainerPATCH 221/1376 scsi: qla2xxx: Bound i2c->length in I2C bsg handlers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 0918ee2c0eeb4d7f45b82b3dc11e65c2d9b7ad59 upstream.
struct qla_i2c_access carries a 16-bit length field alongside a fixed 64-byte buffer:
struct qla_i2c_access {
uint16_t device, offset, option, length;
uint8_t buffer[0x40];
} __packed;qla2x00_write_i2c() and qla2x00_read_i2c() use the user-supplied i2c->length without any bounds check. i2c is overlaid on a 256-byte on-stack buffer and sfp is a 256-byte DMA-pool buffer, so a length up to 65535 overruns both:
- write: memcpy(sfp, i2c->buffer, i2c->length) over-reads the stack and over-writes the sfp heap buffer, and qla2x00_write_sfp() then DMAs i2c->length bytes out of the 256-byte buffer.
- read: qla2x00_read_sfp() DMAs i2c->length bytes into the 256-byte sfp, then memcpy(i2c->buffer, sfp, i2c->length) overflows the 64-byte buffer inside the on-stack array.
A caller holding CAP_SYS_RAWIO can use this to corrupt the heap and the kernel stack. Reject requests whose length exceeds the buffer before any copy or DMA transfer in both handlers.
--- drivers/scsi/qla2xxx/qla_bsg.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/scsi/qla2xxx/qla_bsg.c +12 -0
@@ -1725,6 +1725,12 @@ qla2x00_write_i2c(struct bsg_job *bsg_josg_copy_to_buffer (bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, i2c,sizeof (*i2c)); +if (i2c->length >sizeof (i2c->buffer)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0 ] = +EXT_STATUS_INVALID_PARAM ; + goto dealloc; + } +memcpy (sfp, i2c->buffer, i2c->length); rval =qla2x00_write_sfp (vha, sfp_dma, sfp, i2c->device, i2c->offset, i2c->length, i2c->option);
@@ -1771,6 +1777,12 @@ qla2x00_read_i2c(struct bsg_job *bsg_jobsg_copy_to_buffer (bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, i2c,sizeof (*i2c)); +if (i2c->length >sizeof (i2c->buffer)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0 ] = +EXT_STATUS_INVALID_PARAM ; + goto dealloc; + } + rval =qla2x00_read_sfp (vha, sfp_dma, sfp, i2c->device, i2c->offset, i2c->length, i2c->option);
Greg Kroah-Hartman
maintainerPATCH 222/1376 scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit c20ee380ca59c5a8646750c4849969a815924e2e upstream.
qla_chk_edif_rx_sa_delete_pending() obtains the SCSI command via GET_CMD_SP(sp) and immediately dereferences cmd->sc_data_direction. That command pointer can be NULL: the firmware may post a status completion for a command that has already been returned or aborted. The caller qla2x00_status_entry() acknowledges this on the very same status path, re-fetching GET_CMD_SP(sp) and bailing out with the "Command already returned" message when it is NULL -- but that check runs only after qla_chk_edif_rx_sa_delete_pending() has already dereferenced the pointer, so a NULL cmd crashes the kernel in interrupt context.
Return early when cmd is NULL, before touching cmd->sc_data_direction.
--- drivers/scsi/qla2xxx/qla_edif.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/qla2xxx/qla_edif.c +3 -0
@@ -3491,6 +3491,9 @@ void qla_chk_edif_rx_sa_delete_pending(sstruct scsi_cmnd *cmd =GET_CMD_SP (sp);uint32_t handle; +if (!cmd) +return ; + handle = (uint32_t )LSW (sts24->handle);/* find out if this status iosb is for a scsi read */
Greg Kroah-Hartman
maintainerPATCH 223/1376 scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit eb137255fd7aa834c4d639ae7b5e9e8ecf3a4fb2 upstream.
In the CS_PORT_LOGGED_OUT case of qla2x00_chk_ms_status(), the FWI2-capable branch compared ms_pkt->loop_id.extended against NPH_SNS to decide whether the Name Server had logged out. On FWI2 and later adapters the response is a ct_entry_24xx / ct_entry_24xx_ext, where loop_id.extended (via the legacy ms_iocb_entry_t view) aliases offset 8, which is comp_status, not nport_handle (offset 10). As this code runs under CS_PORT_LOGGED_OUT, the field read back 0x29 (CS_PORT_LOGGED_OUT) and the comparison against NPH_SNS (0x7fc) was always false.
As a result the driver never recognized a Name Server logout on FWI2/ 29xx adapters: it returned the generic QLA_FUNCTION_FAILED instead of QLA_NOT_LOGGED_IN and skipped setting LOOP_RESYNC_NEEDED / LOCAL_LOOP_UPDATE, so the fabric rediscovery triggered by an SNS logout did not happen.
Read nport_handle from the ct_entry_24xx layout (offset 10) instead. nport_handle is at the same offset in ct_entry_24xx and ct_entry_24xx_ext, so a single cast covers 24xx-class and 29xx. The non-FWI2 branch keeps using loop_id.extended, which is correct for the ms_iocb_entry_t response on those adapters.
--- drivers/scsi/qla2xxx/qla_gs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_gs.c +2 -2
@@ -157,8 +157,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vbreak ;case CS_PORT_LOGGED_OUT :if (IS_FWI2_CAPABLE (ha)) { -if (le16_to_cpu (ms_pkt->loop_id.extended) == -NPH_SNS ) +if (le16_to_cpu (((struct ct_entry_24xx *) + ms_pkt)->nport_handle) ==NPH_SNS ) lid_is_sns = true; }else { if (le16_to_cpu(ms_pkt->loop_id.extended) ==
Greg Kroah-Hartman
maintainerPATCH 224/1376 scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 793cedee296fd819bfadc2a7ec4d52faf9c09a0a upstream.
In the format 1 path, the virtual port is located on ha->vp_list while holding vport_slock, but the lock is dropped before vp is used:qla_update_host_map() is called and VP_IDX_ACQUIRED/REGISTER_FC4_NEEDED/ REGISTER_FDMI_NEEDED are set on vp. No reference is taken across that window, so a concurrent qla24xx_deallocate_vp_id() can tear the vport down and free it, leading to a use-after-free.
Take a vport reference (vref_count) under vport_slock when the matching vp is found, and drop it after the last use of
vp. qla24xx_deallocate_vp_id() waits for vref_count to reach zero before unlinking and freeing the vport, so the pointer stays valid. This matches the reference idiom already used by the other ha->vp_list traversals.
--- drivers/scsi/qla2xxx/qla_mbx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +3 -0
@@ -4146,6 +4146,7 @@ qla24xx_report_id_acquisition(scsi_qla_hlist_for_each_entry (vp, &ha->vp_list, list) {if (rptid_entry->vp_idx == vp->vp_idx) { found =1 ; +atomic_inc (&vp->vref_count);break ; } }
@@ -4163,6 +4164,8 @@ qla24xx_report_id_acquisition(scsi_qla_hset_bit (VP_IDX_ACQUIRED , &vp->vp_flags);set_bit (REGISTER_FC4_NEEDED , &vp->dpc_flags);set_bit (REGISTER_FDMI_NEEDED , &vp->dpc_flags); + +atomic_dec (&vp->vref_count); }set_bit (VP_DPC_NEEDED , &vha->dpc_flags);qla2xxx_wake_dpc (vha);
Greg Kroah-Hartman
maintainerPATCH 225/1376 scsi: qla2xxx: Initialize NVMe abort_work once at submission
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 7e85f6dbc85616de2172bce8eaf84b387a723cd1 upstream.
qla_nvme_fcp_abort() and qla_nvme_ls_abort() ran INIT_WORK() on priv->abort_work immediately before schedule_work(). INIT_WORK() reinitializes the work_struct, resetting its list head and clearing the pending bit. If an abort is issued more than once for the same command (for example, concurrent transport teardown and a timeout-driven abort), the second INIT_WORK() reinitializes a work item that is already queued, which can corrupt the workqueue list and lead to crashes or a looping worker.
Initialize priv->abort_work once at command submission, next to the existing per-command spin_lock_init(&priv->cmd_lock), and leave only schedule_work() in the abort paths. schedule_work() already does nothing when the work item is still pending, so a repeated abort no longer disturbs an in-flight work item. The command is not returned to the transport until the final kref_put()/release callback runs after abort_work has completed, so the work item is idle before priv is reused and the single submission-time INIT_WORK() is safe.
--- drivers/scsi/qla2xxx/qla_nvme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_nvme.c +2 -2
@@ -463,7 +463,6 @@ static void qla_nvme_ls_abort(struct nvm }spin_unlock_irqrestore (&priv->cmd_lock, flags); -INIT_WORK (&priv->abort_work, qla_nvme_abort_work);schedule_work (&priv->abort_work); }
@@ -501,6 +500,7 @@ static int qla_nvme_ls_req(struct nvme_f priv->sp = sp;kref_init (&sp->cmd_kref);spin_lock_init (&priv->cmd_lock); +INIT_WORK (&priv->abort_work, qla_nvme_abort_work); nvme = &sp->u.iocb_cmd; priv->fd = fd; nvme->u.nvme.desc = fd;
@@ -545,7 +545,6 @@ static void qla_nvme_fcp_abort(struct nv }spin_unlock_irqrestore (&priv->cmd_lock, flags); -INIT_WORK (&priv->abort_work, qla_nvme_abort_work);schedule_work (&priv->abort_work); }
@@ -811,6 +810,7 @@ static int qla_nvme_post_cmd(struct nvmekref_init (&sp->cmd_kref);spin_lock_init (&priv->cmd_lock); +INIT_WORK (&priv->abort_work, qla_nvme_abort_work); sp->priv = priv; priv->sp = sp; sp->type =SRB_NVME_CMD ;
Greg Kroah-Hartman
maintainerPATCH 226/1376 scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 9101c51649f5b6773a97bf5271785c948589ea1d upstream.
The Modify VP Config completion handler labelled its first error branch "error status" but tested vpmod->comp_status instead of vpmod->entry_status. Because CS_COMPLETE is 0, the following "comp_status != CS_COMPLETE" branch duplicated that test and was dead code, and entry_status was never examined at all.
When firmware rejects the IOCB early it sets entry_status while leaving comp_status zero. As the IOCB is allocated with dma_pool_zalloc(), both comp_status branches evaluate false and the handler falls through to the success path, calling fc_vport_set_state(FC_VPORT_INITIALIZING) for a configuration the firmware never accepted. This can leave the virtual port enabled on top of an invalid config and surface later as login timeouts or follow-on firmware errors.
Test entry_status in the first branch, matching qla_ctrlvp_completed() and the login/logout/abort/reset IOCB handlers; the comp_status branch then becomes the live completion-status check.
--- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +2 -2
@@ -4276,10 +4276,10 @@ qla24xx_modify_vp_config(scsi_qla_host_tif (rval !=QLA_SUCCESS ) {ql_dbg (ql_dbg_mbx, vha,0x10bd ,"Failed to issue VP config IOCB (%x).\n" , rval); - }else if (vpmod->comp_status !=0 ) { + }else if (vpmod->entry_status !=0 ) {ql_dbg (ql_dbg_mbx, vha,0x10be ,"Failed to complete IOCB -- error status (%x).\n" , - vpmod->comp_status); + vpmod->entry_status); rval =QLA_FUNCTION_FAILED ; }else if (vpmod->comp_status !=cpu_to_le16 (CS_COMPLETE )) { ql_dbg(ql_dbg_mbx, vha, 0x10bf,
Greg Kroah-Hartman
maintainerPATCH 227/1376 scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit de62cf265dbe309f34f144a6cdbca9240317727e upstream.
qla2x00_update_fru_versions() copies the user-supplied BSG request into a fixed 256-byte stack buffer (bsg[DMA_POOL_SIZE]) and then iterates list->count times over the qla_image_version array embedded in that buffer, advancing the image pointer each iteration. count is taken directly from user input with no upper bound, while only (DMA_POOL_SIZE
- sizeof(list->count)) / sizeof(struct qla_image_version) = 6 entries actually fit. A larger count walks the image pointer off the end of the stack buffer, reading adjacent kernel stack memory and sending it to the device via qla2x00_write_sfp().
Reject requests whose declared count does not fit in the buffer.
--- drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/scsi/qla2xxx/qla_bsg.c +7 -0
@@ -1578,6 +1578,13 @@ qla2x00_update_fru_versions(struct bsg_j image = list->version; count = list->count; + +if (struct_size (list, version, count) >sizeof (bsg)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0 ] = +EXT_STATUS_INVALID_PARAM ; + goto dealloc; + } +while (count--) {memcpy (sfp, &image->field_info,sizeof (image->field_info)); rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
Greg Kroah-Hartman
maintainerPATCH 228/1376 scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit f743488e4a203049f27ec5d8cd0caccc483af01e upstream.
qla_nvme_ls_reject_iocb() allocates from and advances the request ring through __qla2x00_alloc_iocbs() (which assumes the hardware_lock is held) and qla2x00_start_iocbs() (which advances the ring and rings the request-in doorbell), but takes no lock itself. Two of its callers invoke it without the producer lock held:
- qla_nvme_xmt_ls_rsp(), the NVMe-FC .xmt_ls_rsp transport callback, on its error path, and
- qla2xxx_process_purls_pkt(), run from the purex work/DPC context.
Both use ha->base_qpair, whose qp_lock_ptr is hardware_lock, so they can run concurrently with normal I/O submission on the base ring and corrupt the ring producer state, leading to duplicated or dropped commands. The third caller, qla2xxx_process_purls_iocb(), runs inside qla24xx_process_response_queue() with the qpair lock already held and is safe; that is also why the lock cannot be taken inside the helper itself (it would recursively re-acquire hardware_lock on the response path).
Take qp_lock_ptr around the two unlocked callers and document the helper as caller-locked. Both run in process context, so spin_lock_irqsave() is used and nothing in the locked region sleeps.
--- drivers/scsi/qla2xxx/qla_nvme.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/scsi/qla2xxx/qla_nvme.c +10 -0
@@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvsrb_t *sp;int rval =QLA_FUNCTION_FAILED ;uint8_t cnt =0 ; +unsigned long flags;if (!fcport || fcport->deleted) goto out;
@@ -440,7 +441,9 @@ out: a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; +spin_lock_irqsave (ha->base_qpair->qp_lock_ptr, flags);qla_nvme_ls_reject_iocb (vha, ha->base_qpair, &a, true); +spin_unlock_irqrestore (ha->base_qpair->qp_lock_ptr, flags);kfree (uctx);return rval; }
@@ -1127,6 +1130,10 @@ static void qla_nvme_lsrjt_pt_iocb(struc lsrjt_iocb->rx_byte_count =0 ; } +/* +* Allocates from and advances the request ring, so the caller must hold +* qp->qp_lock_ptr (the response-queue caller already holds it). +*/ static int qla_nvme_ls_reject_iocb (struct scsi_qla_host *vha,struct qla_qpair *qp,struct qla_nvme_lsrjt_pt_arg *a,bool is_xchg_terminate)
@@ -1183,6 +1190,7 @@ qla2xxx_process_purls_pkt(struct scsi_ql {struct qla_nvme_unsol_ctx *uctx = item->purls_context;struct qla_nvme_lsrjt_pt_arg a; +unsigned long flags;int ret =1 ;#if (IS_ENABLED (CONFIG_NVME_FC ))
@@ -1195,7 +1203,9 @@ qla2xxx_process_purls_pkt(struct scsi_ql a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; +spin_lock_irqsave (vha->hw->base_qpair->qp_lock_ptr, flags);qla_nvme_ls_reject_iocb (vha, vha->hw->base_qpair, &a, true); +spin_unlock_irqrestore (vha->hw->base_qpair->qp_lock_ptr, flags);list_del (&uctx->elem);kfree (uctx); }
Greg Kroah-Hartman
maintainerPATCH 229/1376 scsi: qla2xxx: Clamp MSI-X derived queue counts to avoid truncation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit ebfd35c64433821bd5619a6d07ccc2df8b5b1de3 upstream.
ha->msix_count is u16, but ha->max_req_queues, ha->max_rsp_queues and ha->max_qpairs are u8. Deriving the queue count as "ha->max_req_queues = ha->msix_count - 1" therefore truncates: a board (or a misconfigured/malicious hot-plugged device) advertising 257 MSI-X vectors yields msix_count - 1 == 256, which truncates to 0. An MSI-X count of 1 zeroes it as well, and in target mode the subsequent "ha->max_req_queues--" then underflows 0 to 255.
When the count is 0, qla2x00_alloc_queues() calls kzalloc_objs(struct req_que *, 0), which returns ZERO_SIZE_PTR. That is not NULL, so the allocation check passes and the following "ha->req_q_map[0] = req" dereferences ZERO_SIZE_PTR, corrupting memory or crashing the kernel.
Add qla_calc_queue_count() to clamp the derived value into [1, QLA_MAX_QUEUES - 1] so it always fits in u8 and is never zero, and use it at all three derivation sites (qla25xx_iospace_config(), qla83xx_iospace_config() and qla24xx_enable_msix()). Also guard the target-mode decrement so it cannot reintroduce a zero (which would in turn underflow max_qpairs).
--- drivers/scsi/qla2xxx/qla_inline.h | 13 +++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 4 ++-- drivers/scsi/qla2xxx/qla_os.c | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-)
drivers/scsi/qla2xxx/qla_inline.h +13 -0
@@ -54,6 +54,19 @@ qla2x00_debounce_register(volatile __le1return (first); } +static inline u8 +qla_calc_queue_count (u16 msix_count) +{ +/* +* Request/response queues are bounded by the MSI-X vector count less +* the mailbox vector. These counters are u8, so a board advertising +* e.g. 257 vectors would truncate msix_count - 1 (256) to 0 and hand +* kzalloc_objs() a zero count (ZERO_SIZE_PTR), faulting on the first +* ha->req_q_map[0] store. Clamp into [1, QLA_MAX_QUEUES - 1]. +*/ +return clamp_t (u16, msix_count -1 ,1 ,QLA_MAX_QUEUES -1 ); +} +static inline void qla2x00_poll (struct rsp_que *rsp) {
drivers/scsi/qla2xxx/qla_isr.c +2 -2
@@ -4548,10 +4548,10 @@ qla24xx_enable_msix(struct qla_hw_data * ha->msix_count = ret;/* Recalculate queue values */ if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) { - ha->max_req_queues = ha->msix_count -1 ; + ha->max_req_queues =qla_calc_queue_count (ha->msix_count);/* ATIOQ needs 1 vector. That's 1 less QPair */ -if (QLA_TGT_MODE_ENABLED ()) +if (QLA_TGT_MODE_ENABLED () && ha->max_req_queues >1 ) ha->max_req_queues--; ha->max_rsp_queues = ha->max_req_queues;
drivers/scsi/qla2xxx/qla_os.c +3 -3
@@ -2123,7 +2123,7 @@ skip_pio: ha->msix_count = msix +1 ;/* Max queues are bounded by available msix vectors */ /* MB interrupt uses 1 vector */ - ha->max_req_queues = ha->msix_count -1 ; + ha->max_req_queues =qla_calc_queue_count (ha->msix_count); ha->max_rsp_queues = ha->max_req_queues;/* Queue pairs is the max value minus the base queue pair */ ha->max_qpairs = ha->max_rsp_queues -1 ;
@@ -2209,10 +2209,10 @@ qla83xx_iospace_config(struct qla_hw_dat*/ if (ql2xmqsupport || ql2xnvmeenable) {/* MB interrupt uses 1 vector */ - ha->max_req_queues = ha->msix_count -1 ; + ha->max_req_queues =qla_calc_queue_count (ha->msix_count);/* ATIOQ needs 1 vector. That's 1 less QPair */ -if (QLA_TGT_MODE_ENABLED ()) +if (QLA_TGT_MODE_ENABLED () && ha->max_req_queues >1 ) ha->max_req_queues--; ha->max_rsp_queues = ha->max_req_queues;
Greg Kroah-Hartman
maintainerPATCH 230/1376 scsi: qla2xxx: Serialize flash version read in reset handler
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit f606ed93de0c4f1e7e3618779e9fad731455314a upstream.
The "update cache versions without reset" sysfs reset operation (0x20261) calls get_flash_version(), which reads hardware flash registers, without holding ha->optrom_mutex. The VPD update path serializes the same call under optrom_mutex, so this reset path can interleave its flash register accesses with a concurrent VPD or optrom flash operation and corrupt the reads.
Hold ha->optrom_mutex across the get_flash_version() call to match the VPD update path.
--- drivers/scsi/qla2xxx/qla_attr.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_attr.c +2 -0
@@ -816,7 +816,9 @@ qla2x00_sysfs_write_reset(struct file *f "Unable to allocate memory for VPD information update.\n");return -ENOMEM ; } +mutex_lock (&ha->optrom_mutex); ha->isp_ops->get_flash_version (vha, tmp_data); +mutex_unlock (&ha->optrom_mutex);vfree (tmp_data);break ; }
Greg Kroah-Hartman
maintainerPATCH 231/1376 scsi: qla2xxx: Fix cs84xx use-after-free on host teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 33d102102d925357c5fd172dd6672a27d74b3215 upstream.
qla84xx_put_chip() drops the last reference to ha->cs84xx and frees it via __qla84xx_chip_release() without clearing ha->cs84xx. During teardown it ran before scsi_remove_host(), which is what removes the 84xx_fw_version host sysfs attribute. A concurrent read of that attribute in the window between the two calls executes qla24xx_84xx_fw_version_show(), which dereferences the freed ha->cs84xx, resulting in a use-after-free.
Move qla84xx_put_chip() to after scsi_remove_host() in both qla2x00_remove_one() and qla2x00_disable_board_on_pci_error(). Once scsi_remove_host() returns, the sysfs attribute is gone and kernfs has drained any in-flight show(), so no reader can touch cs84xx; the put still runs before the host and ha are freed.
--- drivers/scsi/qla2xxx/qla_os.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_os.c +4 -4
@@ -3929,8 +3929,6 @@ qla2x00_remove_one(struct pci_dev *pdev)qla2x00_dfs_remove (base_vha); -qla84xx_put_chip (base_vha); -/* Disable timer */ if (base_vha->timer_active)qla2x00_stop_timer (base_vha);
@@ -3955,6 +3953,8 @@ qla2x00_remove_one(struct pci_dev *pdev)scsi_remove_host (base_vha->host); +qla84xx_put_chip (base_vha); +qla2x00_free_device (base_vha);qla2x00_clear_drv_active (ha);
@@ -6826,8 +6826,6 @@ qla2x00_disable_board_on_pci_error(strucqla2x00_dfs_remove (base_vha); -qla84xx_put_chip (base_vha); -if (base_vha->timer_active)qla2x00_stop_timer (base_vha);
@@ -6845,6 +6843,8 @@ qla2x00_disable_board_on_pci_error(strucscsi_remove_host (base_vha->host); +qla84xx_put_chip (base_vha); + base_vha->flags.init_done =0 ;qla25xx_delete_queues (base_vha);qla2x00_free_fcports (base_vha);
Greg Kroah-Hartman
maintainerPATCH 232/1376 scsi: qla2xxx: Fix FCE trace use-after-free during firmware dump
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 53298efcbbb0f0438366d45cb7ed7e6d93dd5531 upstream.
qla2x00_free_fce_trace() freed and cleared ha->fce while holding only fce_mutex. The firmware-dump consumers qla27xx_fwdt_entry_t264() and qla25xx_copy_fce() read ha->fce (NULL check followed by a copy of the buffer) under hardware_lock and never take fce_mutex. A debugfs FCE disable could therefore free the DMA buffer between a dump's NULL check and its copy, resulting in a use-after-free.
Unpublish ha->fce under hardware_lock, then release the lock and free the DMA buffer (dma_free_coherent() may sleep). A concurrent dump either completes its check and copy with the buffer still valid, or observes ha->fce == NULL and skips it.
--- drivers/scsi/qla2xxx/qla_init.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_init.c +18 -2
@@ -3764,11 +3764,27 @@ int qla2x00_alloc_fce_trace(scsi_qla_hosvoid qla2x00_free_fce_trace (struct qla_hw_data *ha) { -if (!ha->fce) +void *fce; +dma_addr_t fce_dma; +unsigned long flags; + +/* +* Unpublish ha->fce under hardware_lock so a firmware dump in +* progress (which reads ha->fce under the same lock) cannot race +* with the buffer being freed. +*/ +spin_lock_irqsave (&ha->hardware_lock, flags); +if (!ha->fce) { +spin_unlock_irqrestore (&ha->hardware_lock, flags);return ; -dma_free_coherent (&ha->pdev->dev,FCE_SIZE , ha->fce, ha->fce_dma); + } + fce = ha->fce; + fce_dma = ha->fce_dma; ha->fce =NULL ; ha->fce_dma =0 ; +spin_unlock_irqrestore (&ha->hardware_lock, flags); + +dma_free_coherent (&ha->pdev->dev,FCE_SIZE , fce, fce_dma); } static void
Greg Kroah-Hartman
maintainerPATCH 233/1376 scsi: qla2xxx: Zero mailbox struct in qla2x00_get_firmware_state()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 9efaa782845b4d5fb3e01242be0d06ebc7428d8f upstream.
The mbx_cmd_t is allocated on the stack but left uninitialized. qla2x00_mailbox_command() has several early-return paths (PCI permanent failure, device failed, EEH busy, ISP abort pending, mailbox access timeout, purge mbox) that return without writing the input mailbox registers back into mcp->mb[]. qla2x00_get_firmware_state() then unconditionally copies mcp->mb[1..6] (and mb[12]) into the caller's states[] array regardless of the return value.
On such a failure the copied values are uninitialized kernel stack memory, which is then exposed to userspace via the fw_state and mpi_fw_state sysfs handlers. Zero the mailbox struct so a failed query yields deterministic zeroed state instead of leaking stack contents.
--- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -2214,6 +2214,8 @@ qla2x00_get_firmware_state(scsi_qla_hostif (!ha->flags.fw_started)return QLA_FUNCTION_FAILED ; +memset (&mc,0 ,sizeof (mc)); + mcp->mb[0 ] =MBC_GET_FIRMWARE_STATE ; mcp->out_mb =MBX_0 ;if (IS_FWI2_CAPABLE (vha->hw))
Greg Kroah-Hartman
maintainerPATCH 234/1376 scsi: qla2xxx: Fix FCE trace enable parsing in debugfs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit b7368687e3d11f51392d3c4774ec0263d5fbf31f upstream.
qla2x00_dfs_fce_write() called kstrtoul() with a NULL result pointer, so a successful parse would dereference NULL and oops. Worse, the int return value (0 on success, negative errno on failure) was assigned to the unsigned long enable flag, inverting the intended logic: a valid number was treated as "disable" while a parse failure enabled FCE.
Parse the value into enable and propagate parse errors to userspace.
--- drivers/scsi/qla2xxx/qla_dfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_dfs.c +3 -1
@@ -518,7 +518,9 @@ qla2x00_dfs_fce_write(struct file *file,return PTR_ERR (buf); } - enable =kstrtoul (buf,0 ,0 ); + rc =kstrtoul (buf,0 , &enable); +if (rc) + goto out_free; rc = count;mutex_lock (&ha->fce_mutex);
Greg Kroah-Hartman
maintainerPATCH 235/1376 scsi: qla2xxx: Dont query firmware state while chip is down
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit e0cebe20dcffbed9c078fe30e2d18cd5046d9eff upstream.
qla2x00_fw_state_show() initializes rval to QLA_FUNCTION_FAILED and jumps to the out: label when the chip is down or EEH is busy. The out: block then re-issued qla2x00_get_firmware_state() because rval != QLA_SUCCESS, defeating the chip-down/EEH-busy guards and issuing a mailbox command (outside optrom_mutex) during ISP reset or PCI error recovery, which can hang the adapter. It also turned a normal in-lock mailbox failure into a second unsynchronized mailbox attempt.
Make the out: fallback only mark the firmware state as unknown. The mailbox is now issued at most once, inside optrom_mutex, and only when the chip is up and not EEH-busy.
--- drivers/scsi/qla2xxx/qla_attr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +1 -3
@@ -1662,10 +1662,8 @@ qla2x00_fw_state_show(struct device *dev rval =qla2x00_get_firmware_state (vha, state);mutex_unlock (&vha->hw->optrom_mutex); out: -if (rval !=QLA_SUCCESS ) { +if (rval !=QLA_SUCCESS )memset (state,-1 ,sizeof (state)); - rval =qla2x00_get_firmware_state (vha, state); - }return scnprintf (buf,PAGE_SIZE ,"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n" , state[0 ], state[1 ], state[2 ], state[3 ], state[4 ], state[5 ]);
Greg Kroah-Hartman
maintainerPATCH 236/1376 scsi: qla2xxx: Reject non-SCSI SRB on status IOCB fast path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 0f41d07d72f2245208c45374ca8d0a1846cad667 upstream.
qla2x00_status_entry() filters out non-TYPE_SRB entries and the SRB_NVME_CMD, SRB_BIDI_CMD and SRB_TM_CMD types, then falls through to a SCSI fast path that assumes the command is an SRB_SCSI_CMD. The first thing on that path, qla_chk_edif_rx_sa_delete_pending(), and the subsequent handling both evaluate GET_CMD_SP(sp), i.e. sp->u.scmd.cmd.
The srb u union overlays the SCSI command pointer with other command layouts (bsg_job, iocb_cmd). If firmware delivers an unexpected STATUS_TYPE IOCB for a non-SCSI handle, sp->u.scmd.cmd can read as a non-NULL garbage pointer, bypassing the NULL checks in qla_chk_edif_rx_sa_delete_pending() and at the cp == NULL test, and leading to a wild pointer dereference.
Reject any SRB whose type is not SRB_SCSI_CMD before entering the fast path. The outstanding_cmds slot is left untouched so a genuinely non-SCSI command still completes through its proper handler.
--- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_dbg.c +1 -1
@@ -16,7 +16,7 @@* | | | 0x2127-0x2128 | * | Queue Command and IO tracing | 0x3074 | 0x300b | * | | | 0x3027-0x3028 | -* | | | 0x303d-0x3041 | +* | | | 0x303e-0x3041 | * | | | 0x302e,0x3033 | * | | | 0x3036,0x3038 | * | | | 0x303a |
drivers/scsi/qla2xxx/qla_isr.c +8 -0
@@ -3406,6 +3406,14 @@ qla2x00_status_entry(scsi_qla_host_t *vhreturn ; } +/* Everything below is the SCSI fast path; reject other SRB types. */ +if (sp->type !=SRB_SCSI_CMD ) { +ql_dbg (ql_dbg_io, vha,0x303d , +"Unexpected SRB type %x for status IOCB, sp %p.\n" , + sp->type, sp); +return ; + } +/* Fast path completion. */ qla_chk_edif_rx_sa_delete_pending (vha, sp, sts24); sp->qpair->cmd_completion_cnt++;
Greg Kroah-Hartman
maintainerPATCH 237/1376 scsi: qla2xxx: Fix response queue over-consumption in __qla_consume_iocb()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 3ba019bdd89d931499d9476456b5d9c7ab7fa753 upstream.
qla24xx_process_response_queue() advances ring_ptr past the head IOCB before dispatching, so by the time __qla_consume_iocb() runs, ring_ptr already points at the first continuation IOCB. The function however looped purex->entry_count times starting at ring_ptr. As entry_count includes the head, this consumed one entry too many: it stamped RESPONSE_PROCESSED on the next, unrelated IOCB and advanced the ring past it, silently dropping a legitimate firmware response. The head IOCB's signature was also never marked.
Mark the head processed and account for it, then consume only the entry_count - 1 continuation IOCBs, matching __qla_copy_purex_to_buffer().
--- drivers/scsi/qla2xxx/qla_isr.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/scsi/qla2xxx/qla_isr.c +11 -0
@@ -205,6 +205,17 @@ void __qla_consume_iocb(struct scsi_qla_struct purex_entry_24xx *purex = *pkt; entry_count_remaining = purex->entry_count; + +/* +* The caller already advanced ring_ptr past the head IOCB, so mark +* the head processed and account for it here, then consume only the +* continuation IOCBs that follow. +*/ + ((response_t *)purex)->signature =RESPONSE_PROCESSED ; +/* flush signature */ +wmb (); + --entry_count_remaining; +while (entry_count_remaining >0 ) { new_pkt = rsp_q->ring_ptr; *pkt = new_pkt;
Greg Kroah-Hartman
maintainerPATCH 238/1376 scsi: qla2xxx: Quiesce response IRQ before freeing request queue
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 505753ec2594c6af09a601f0dd60be7d840c1d2d upstream.
qla2xxx_delete_qpair() deletes the request queue before the response queue. qla25xx_delete_req_que() frees the request queue memory (kfree(req) in qla25xx_free_req_que()), but the response-queue MSI-X is only released later, in qla25xx_free_rsp_que(). In that window the response interrupt can still fire, qla2xxx_msix_rsp_q() queues qpair->q_work, and qla_do_work() -> qla24xx_process_response_queue() dereferences the now-freed rsp->req (LOGINOUT/CT/ELS entries and the status path), a use-after-free.
The cancel_work_sync() added for the qpair teardown lives in the response free path, which runs after the request queue is already freed, so it does not protect rsp->req.
Release the response-queue interrupt and flush qpair->q_work before deleting the request queue, so no late completion can reach the freed request queue. Clearing have_irq makes the subsequent qla25xx_free_rsp_que() skip its free_irq(), and the firmware queue-delete order (request then response) is preserved; the request-delete mailbox completes on the default vector and is unaffected by dropping the qpair response interrupt early.
--- drivers/scsi/qla2xxx/qla_init.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/scsi/qla2xxx/qla_init.c +17 -0
@@ -9853,11 +9853,28 @@ int qla2xxx_delete_qpair(struct scsi_qla {int ret =QLA_FUNCTION_FAILED ;struct qla_hw_data *ha = qpair->hw; +struct rsp_que *rsp = qpair->rsp; qpair->delete_in_progress =1 ;qla_free_buf_pool (qpair); +/* +* The response-queue interrupt schedules qla_do_work(), which +* dereferences qpair->rsp->req. Release the interrupt and flush +* any pending work before the request queue is freed below so a +* late completion cannot touch the freed request queue. The +* firmware queue-delete order (request then response) is kept. +*/ +if (rsp && rsp->msix && rsp->msix->have_irq) { +free_irq (rsp->msix->vector, rsp->msix->handle); + rsp->msix->have_irq =0 ; + rsp->msix->in_use =0 ; + rsp->msix->handle =NULL ; + } +if (rsp && ha->wq) +cancel_work_sync (&qpair->q_work); + ret =qla25xx_delete_req_que (vha, qpair->req);if (ret !=QLA_SUCCESS ) goto fail;
Greg Kroah-Hartman
maintainerPATCH 239/1376 scsi: qla2xxx: Avoid double completion in async IOCB timeout
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit bb45bc4bd53c95a7bf6f782577b5ede94c0f8aa8 upstream.
qla2x00_async_iocb_timeout() tries to abort a timed-out async IOCB. When qla24xx_async_abort_cmd() fails, both the SRB_LOGIN_CMD path and the SRB_CTRL_VP/default path scan outstanding_cmds[] for the SRB and then call sp->done(sp, QLA_FUNCTION_TIMEOUT) unconditionally, without checking whether the SRB was actually found and removed.
If the response ISR completes the same handle first, it removes the SRB under qp_lock_ptr and runs sp->done() -> complete(sp->comp). The submitter qla24xx_control_vp() wakes from wait_for_completion(), clears sp->comp, drops its reference and returns, reclaiming the on-stack completion. The timer reference keeps the SRB alive across the timeout handler, but not the submitter's stack. The timeout then issues a second sp->done() -> qla_ctrlvp_sp_done(), which evaluates "if (sp->comp) complete(sp->comp)"; with the pointer loaded before the submitter's NULL store, complete() writes into the freed stack frame, a use-after-free.
Track whether this path removed the SRB from outstanding_cmds and only call sp->done() when it did, so the command is completed exactly once by whichever path owns it. This mirrors the sp_found guard already used in qla24xx_abort_iocb_timeout().
--- drivers/scsi/qla2xxx/qla_init.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
drivers/scsi/qla2xxx/qla_init.c +21 -3
@@ -228,7 +228,7 @@ qla2x00_async_iocb_timeout(void *data)srb_t *sp = data;fc_port_t *fcport = sp->fcport;struct srb_iocb *lio = &sp->u.iocb_cmd; -int rc, h; +int rc, h, found;unsigned long flags;if (fcport) {
@@ -251,6 +251,7 @@ qla2x00_async_iocb_timeout(void *data) lio->u.logio.data[1 ] = lio->u.logio.flags &SRB_LOGIN_RETRIED ?QLA_LOGIO_LOGIN_RETRIED :0 ; + found =0 ;spin_lock_irqsave (sp->qpair->qp_lock_ptr, flags);for (h =1 ; h < sp->qpair->req->num_outstanding_cmds; h++) {
@@ -258,11 +259,19 @@ qla2x00_async_iocb_timeout(void *data) sp) { sp->qpair->req->outstanding_cmds[h] =NULL ; + found =1 ;break ; } }spin_unlock_irqrestore (sp->qpair->qp_lock_ptr, flags); - sp->done (sp,QLA_FUNCTION_TIMEOUT ); +/* +* Only complete the command if this path removed it +* from outstanding_cmds. Otherwise the ISR already +* completed it and a second sp->done() would race the +* submitter's freeing of the on-stack completion. +*/ +if (found) + sp->done (sp,QLA_FUNCTION_TIMEOUT ); }break ;case SRB_LOGOUT_CMD :
@@ -275,6 +284,7 @@ qla2x00_async_iocb_timeout(void *data)default : rc =qla24xx_async_abort_cmd (sp, false);if (rc) { + found =0 ;spin_lock_irqsave (sp->qpair->qp_lock_ptr, flags);for (h =1 ; h < sp->qpair->req->num_outstanding_cmds; h++) {
@@ -282,11 +292,19 @@ qla2x00_async_iocb_timeout(void *data) sp) { sp->qpair->req->outstanding_cmds[h] =NULL ; + found =1 ;break ; } }spin_unlock_irqrestore (sp->qpair->qp_lock_ptr, flags); - sp->done (sp,QLA_FUNCTION_TIMEOUT ); +/* +* Only complete the command if this path removed it +* from outstanding_cmds. Otherwise the ISR already +* completed it and a second sp->done() would race the +* submitter's freeing of the on-stack completion. +*/ +if (found) + sp->done (sp,QLA_FUNCTION_TIMEOUT ); }break ; }
Greg Kroah-Hartman
maintainerPATCH 240/1376 scsi: qla2xxx: Bound rsp_info_len to avoid OOB sense-data read
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit ca6d880d6c70cb7946e7b3e05d7285f271b6d99e upstream.
In qla2x00_status_entry(), the FWI2 status path advances sense_data and shrinks par_sense_len by rsp_info_len:
if (IS_FWI2_CAPABLE(ha)) {
sense_data += rsp_info_len;
par_sense_len -= rsp_info_len;
}rsp_info_len is a 32-bit value taken directly from the target's FCP response (sf.rsp_data_len), while par_sense_len is the IOCB data area size (28 bytes for 24xx, 60 bytes for 29xx). A hostile or buggy target reporting an rsp_info_len larger than par_sense_len makes the unsigned subtraction underflow to a huge value and advances sense_data out of bounds.
The underflowed par_sense_len then defeats the cap in qla2x00_handle_sense():
if (sense_len > par_sense_len) sense_len = par_sense_len; memcpy(cp->sense_buffer, sense_data, sense_len);
so the memcpy reads up to SCSI_SENSE_BUFFERSIZE bytes from the out-of-bounds sense_data pointer, leaking adjacent response-ring/heap memory into the command's sense buffer.
Clamp rsp_info_len to par_sense_len before the subtraction so par_sense_len can never underflow and sense_data stays within the IOCB data area. The fix sits before the comp_status switch, covering both qla2x00_handle_sense() call sites.
--- drivers/scsi/qla2xxx/qla_isr.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/scsi/qla2xxx/qla_isr.c +12 -0
@@ -3482,6 +3482,18 @@ qla2x00_status_entry(scsi_qla_host_t *vhif (scsi_status &SS_RESPONSE_INFO_LEN_VALID ) {/* Sense data lies beyond any FCP RESPONSE data. */ if (IS_FWI2_CAPABLE (ha)) { +/* +* A hostile or buggy target may report an +* rsp_info_len larger than the IOCB data area. +* Clamp it so the par_sense_len subtraction cannot +* underflow and walk sense_data out of bounds. +*/ +if (rsp_info_len > par_sense_len) { +ql_log (ql_log_warn, fcport->vha,0x3107 , +"Truncating bogus rsp_info_len 0x%x to 0x%x.\n" , + rsp_info_len, par_sense_len); + rsp_info_len = par_sense_len; + } sense_data += rsp_info_len; par_sense_len -= rsp_info_len; }
Greg Kroah-Hartman
maintainerPATCH 241/1376 scsi: qla2xxx: Avoid req_q_map double-read in qla2x00_error_entry()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit deb8abde83a799d2501f3977f6d6051000253f5e upstream.
qla2x00_error_entry() reads ha->req_q_map[que] twice: once for the NULL check and again when assigning it to req. The map slot is cleared by qla25xx_free_req_que() (ha->req_q_map[que_id] = NULL under mq_lock) during queue teardown, while the response-queue interrupt that drives qla2x00_error_entry() is still registered (the IRQ is released later in qla25xx_free_rsp_que()). If the slot is set to NULL between the two reads, req becomes NULL and is dereferenced.
Read the slot once into req and NULL-check the local before use. mq_lock is a mutex and cannot be taken from interrupt context, so the single read plus local check is the appropriate fix for the reported NULL dereference.
--- drivers/scsi/qla2xxx/qla_isr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_isr.c +3 -1
@@ -3809,10 +3809,12 @@ qla2x00_error_entry(scsi_qla_host_t *vha"iocb type %xh with error status %xh, handle %xh, rspq id %d\n" , pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id); -if (que >= ha->max_req_queues || !ha->req_q_map[que]) +if (que >= ha->max_req_queues) goto fatal; req = ha->req_q_map[que]; +if (!req) + goto fatal;if (pkt->entry_status &RF_BUSY ) res =DID_BUS_BUSY <<16 ;
Greg Kroah-Hartman
maintainerPATCH 242/1376 scsi: qla2xxx: Fix NVMe abort reference leak on repeated abort
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 06b5b2a5d499323f1c3256ead35798e8e3d15e60 upstream.
qla_nvme_ls_abort() and qla_nvme_fcp_abort() take a command reference with kref_get_unless_zero() and then call schedule_work() on priv->abort_work, ignoring its return value. qla_nvme_abort_work() runs once and drops exactly one reference via kref_put(&sp->cmd_kref, sp->put_fn).
Since the per-abort INIT_WORK() was moved to submission time, schedule_work() now returns false when the work is already pending, for example on a concurrent transport teardown and timeout-driven abort of the same command. In that case the reference taken for the second abort is never released because the work still executes only once, leaking a reference. The command is then never returned to the NVMe-FC transport, which can hang the port.
Drop the reference when schedule_work() returns false, so each kref_get_unless_zero() is balanced regardless of whether the work was newly queued. The held reference keeps priv->sp valid for the put.
--- drivers/scsi/qla2xxx/qla_nvme.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_nvme.c +4 -2
@@ -466,7 +466,8 @@ static void qla_nvme_ls_abort(struct nvm }spin_unlock_irqrestore (&priv->cmd_lock, flags); -schedule_work (&priv->abort_work); +if (!schedule_work (&priv->abort_work)) +kref_put (&priv->sp->cmd_kref, priv->sp->put_fn); } static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
@@ -548,7 +549,8 @@ static void qla_nvme_fcp_abort(struct nv }spin_unlock_irqrestore (&priv->cmd_lock, flags); -schedule_work (&priv->abort_work); +if (!schedule_work (&priv->abort_work)) +kref_put (&priv->sp->cmd_kref, priv->sp->put_fn); }static inline int qla2x00_start_nvme_mq (srb_t *sp)
Greg Kroah-Hartman
maintainerPATCH 243/1376 scsi: qla2xxx: Drop vport reference under lock in report ID acquisition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 1154b16439ffc562f9461494c4508c63446eb684 upstream.
qla24xx_report_id_acquisition() format-1 handling takes the vport reference under vport_slock but drops it outside the lock, after setting vp->vp_flags and vp->dpc_flags:
set_bit(VP_IDX_ACQUIRED, &vp->vp_flags); set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags); set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags); atomic_dec(&vp->vref_count);
Neither set_bit() nor atomic_dec() imply a memory barrier, so on a weakly ordered architecture the decrement can become visible before the flag stores. qla24xx_deallocate_vp_id() polls vref_count under vport_slock and unlinks the vport once it reads zero, after which qla24xx_vport_delete() frees it via scsi_host_put(). The poller could therefore observe vref_count == 0 early and tear the vport down while the pending vp_flags/ dpc_flags stores land on freed memory.
Drop the reference under vport_slock, as is done for the matching increment and by every other vref_count user. The unlock release pairs with the deallocate poller's lock acquire so the flag stores are ordered before vref_count == 0 can be observed.
--- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -4167,7 +4167,9 @@ qla24xx_report_id_acquisition(scsi_qla_hset_bit (REGISTER_FC4_NEEDED , &vp->dpc_flags);set_bit (REGISTER_FDMI_NEEDED , &vp->dpc_flags); +spin_lock_irqsave (&ha->vport_slock, flags);atomic_dec (&vp->vref_count); +spin_unlock_irqrestore (&ha->vport_slock, flags); }set_bit (VP_DPC_NEEDED , &vha->dpc_flags);qla2xxx_wake_dpc (vha);
Greg Kroah-Hartman
maintainerPATCH 244/1376 scsi: qla2xxx: Hold vport_slock for host map update in report ID acquisition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 7944039ba9cb5c3a935d17c91004e3b8649ff58e upstream.
qla24xx_report_id_acquisition() format-1 handling drops vport_slock after taking the vport reference and then calls qla_update_host_map() without the lock. That reaches qla_update_vp_map(), which mutates the ha->host_map btree via btree_insert32()/btree_update32()/btree_remove32() and is documented to require vport_slock to be held by the caller. Running it unlocked can race concurrent host_map updates and corrupt the btree.
The format-2 path in the same function already wraps its host_map update (SET_AL_PA) in vport_slock; the format-1 path is the lone outlier.
Hold vport_slock across the format-1 qla_update_host_map() call to honor the documented locking contract. The vref_count taken in the loop keeps the vport valid, so this only adds the missing host_map serialization.
--- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -4157,7 +4157,9 @@ qla24xx_report_id_acquisition(scsi_qla_hif (!found)return ; +spin_lock_irqsave (&ha->vport_slock, flags);qla_update_host_map (vp, id); +spin_unlock_irqrestore (&ha->vport_slock, flags);/* * Cannot configure here as we are still sitting on the
Greg Kroah-Hartman
maintainerPATCH 245/1376 scsi: qla2xxx: Use coherent DMA buffer for D_Port diagnostics
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit 7c4f3f50d83af4545efaa99b3d0d46fb8d52031e upstream.
qla26xx_dport_diagnostics() streaming-maps the caller's result buffer with dma_map_single(). The bsg path passes &dd->buf from the __packed struct qla_dport_diag, where buf lands at a 2-byte offset and shares cachelines with the surrounding options/unused fields. Mapping such a misaligned sub-buffer violates the DMA API requirement that streaming buffers be cacheline aligned and not share a cacheline with other data, and can corrupt data on non-DMA-coherent architectures.
Allocate a dedicated DMA-coherent buffer inside qla26xx_dport_diagnostics() for the mailbox command and copy the result back into the caller's buffer. This removes the streaming map of the misaligned sub-buffer entirely; the caller's buffer is now only a plain CPU buffer, so its packing no longer matters.
--- drivers/scsi/qla2xxx/qla_mbx.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +7 -8
@@ -6442,6 +6442,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_mbx_cmd_t mc;mbx_cmd_t *mcp = &mc;dma_addr_t dd_dma; +void *dd;if (!IS_QLA83XX (vha->hw) && !IS_QLA27XX (vha->hw) && !IS_QLA28XX (vha->hw))
@@ -6450,15 +6451,12 @@ qla26xx_dport_diagnostics(scsi_qla_host_ql_dbg (ql_dbg_mbx + ql_dbg_verbose, vha,0x119f ,"Entered %s.\n" , __func__); - dd_dma =dma_map_single (&vha->hw->pdev->dev, - dd_buf, size,DMA_FROM_DEVICE ); -if (dma_mapping_error (&vha->hw->pdev->dev, dd_dma)) { -ql_log (ql_log_warn, vha,0x1194 ,"Failed to map dma buffer.\n" ); + dd =dma_alloc_coherent (&vha->hw->pdev->dev, size, &dd_dma,GFP_KERNEL ); +if (!dd) { +ql_log (ql_log_warn, vha,0x1194 ,"Failed to allocate dma buffer.\n" );return QLA_MEMORY_ALLOC_FAILED ; } -memset (dd_buf,0 , size); - mcp->mb[0 ] =MBC_DPORT_DIAGNOSTICS ; mcp->mb[1 ] = options; mcp->mb[2 ] =MSW (LSD (dd_dma));
@@ -6480,8 +6478,9 @@ qla26xx_dport_diagnostics(scsi_qla_host_ "Done %s.\n", __func__); } -dma_unmap_single (&vha->hw->pdev->dev, dd_dma, - size,DMA_FROM_DEVICE ); +memcpy (dd_buf, dd, size); + +dma_free_coherent (&vha->hw->pdev->dev, size, dd, dd_dma);return rval; }
Greg Kroah-Hartman
maintainerPATCH 246/1376 scsi: qla2xxx: Zero-init bsg stack buffers to avoid info leak
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit b93d3bb3afe1b44489927de1eb4e66e8536a5935 upstream.
Several bsg handlers stage their request/reply in an uninitialized 256-byte on-stack buffer (uint8_t bsg[DMA_POOL_SIZE]) and fill it via sg_copy_to_buffer(), which only copies as many bytes as the user-supplied request payload. When the request is shorter than the structure, the remainder of the buffer is left holding stale stack data.
qla2x00_read_fru_status() and qla2x00_read_i2c() then copy the full structure back to the reply payload with sg_copy_from_buffer(), leaking the uninitialized stack bytes to user space. The write/update paths do not copy the buffer back, but can feed uninitialized fields to the device.
Zero the stack buffer at declaration in all five handlers, mirroring the heap kzalloc() approach, so short requests can no longer expose stale memory.
--- drivers/scsi/qla2xxx/qla_bsg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/scsi/qla2xxx/qla_bsg.c +5 -5
@@ -1560,7 +1560,7 @@ qla2x00_update_fru_versions(struct bsg_jscsi_qla_host_t *vha =shost_priv (host);struct qla_hw_data *ha = vha->hw;int rval =0 ; -uint8_t bsg[DMA_POOL_SIZE ]; +uint8_t bsg[DMA_POOL_SIZE ] = {};struct qla_image_version_list *list = (void *)bsg;struct qla_image_version *image;uint32_t count;
@@ -1620,7 +1620,7 @@ qla2x00_read_fru_status(struct bsg_job *scsi_qla_host_t *vha =shost_priv (host);struct qla_hw_data *ha = vha->hw;int rval =0 ; -uint8_t bsg[DMA_POOL_SIZE ]; +uint8_t bsg[DMA_POOL_SIZE ] = {};struct qla_status_reg *sr = (void *)bsg;dma_addr_t sfp_dma;uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);
@@ -1671,7 +1671,7 @@ qla2x00_write_fru_status(struct bsg_jobscsi_qla_host_t *vha =shost_priv (host);struct qla_hw_data *ha = vha->hw;int rval =0 ; -uint8_t bsg[DMA_POOL_SIZE ]; +uint8_t bsg[DMA_POOL_SIZE ] = {};struct qla_status_reg *sr = (void *)bsg;dma_addr_t sfp_dma;uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);
@@ -1718,7 +1718,7 @@ qla2x00_write_i2c(struct bsg_job *bsg_joscsi_qla_host_t *vha =shost_priv (host);struct qla_hw_data *ha = vha->hw;int rval =0 ; -uint8_t bsg[DMA_POOL_SIZE ]; +uint8_t bsg[DMA_POOL_SIZE ] = {};struct qla_i2c_access *i2c = (void *)bsg;dma_addr_t sfp_dma;uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);
@@ -1770,7 +1770,7 @@ qla2x00_read_i2c(struct bsg_job *bsg_jobscsi_qla_host_t *vha =shost_priv (host);struct qla_hw_data *ha = vha->hw;int rval =0 ; -uint8_t bsg[DMA_POOL_SIZE ]; +uint8_t bsg[DMA_POOL_SIZE ] = {};struct qla_i2c_access *i2c = (void *)bsg;dma_addr_t sfp_dma;uint8_t *sfp =dma_pool_zalloc (ha->s_dma_pool,GFP_KERNEL , &sfp_dma);
Greg Kroah-Hartman
maintainerPATCH 247/1376 scsi: qla2xxx: Skip NVMe LS reject IOCB when FW not started
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nilesh Javali <[email protected]>
commit f7e46ebffc5781aab3f1f5a5d4350addbb5833f4 upstream.
qla_nvme_xmt_ls_rsp() bails out to the out: label when firmware is not started (!ha->flags.fw_started), but the out: path unconditionally calls qla_nvme_ls_reject_iocb(), which ends in qla2x00_start_iocbs() and an unconditional doorbell write to the request queue in-pointer register. This rings the firmware doorbell and queues an IOCB that stopped or resetting firmware cannot consume, and touches MMIO during the reset/EEH window where fw_started is also clear.
Only emit the LS reject IOCB (and ring the doorbell) when fw_started is set; otherwise just clean up and return. The post-allocation failure cases (SRB alloc / qla2x00_start_sp() failure) run with firmware started and still send the reject. Apply the same guard to the reject emission in qla2xxx_process_purls_pkt().
--- drivers/scsi/qla2xxx/qla_nvme.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/scsi/qla2xxx/qla_nvme.c +13 -6
@@ -441,9 +441,11 @@ out: a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; -spin_lock_irqsave (ha->base_qpair->qp_lock_ptr, flags); -qla_nvme_ls_reject_iocb (vha, ha->base_qpair, &a, true); -spin_unlock_irqrestore (ha->base_qpair->qp_lock_ptr, flags); +if (ha->flags.fw_started) { +spin_lock_irqsave (ha->base_qpair->qp_lock_ptr, flags); +qla_nvme_ls_reject_iocb (vha, ha->base_qpair, &a, true); +spin_unlock_irqrestore (ha->base_qpair->qp_lock_ptr, flags); + }kfree (uctx);return rval; }
@@ -1205,9 +1207,14 @@ qla2xxx_process_purls_pkt(struct scsi_ql a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; -spin_lock_irqsave (vha->hw->base_qpair->qp_lock_ptr, flags); -qla_nvme_ls_reject_iocb (vha, vha->hw->base_qpair, &a, true); -spin_unlock_irqrestore (vha->hw->base_qpair->qp_lock_ptr, flags); +if (vha->hw->flags.fw_started) { +spin_lock_irqsave (vha->hw->base_qpair->qp_lock_ptr, + flags); +qla_nvme_ls_reject_iocb (vha, vha->hw->base_qpair, &a, + true); +spin_unlock_irqrestore (vha->hw->base_qpair->qp_lock_ptr, + flags); + }list_del (&uctx->elem);kfree (uctx); }
Greg Kroah-Hartman
maintainerPATCH 248/1376 f2fs: return symlink writeback errors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
commit a2c73a7a677afdaa8b16d775188f9ef5cfbfd8b2 upstream.
F2FS writes long symlink data with page_symlink() and then flushes the symlink mapping to reduce the chance of exposing a broken symlink.
That flush result is currently ignored. If the writeback fails, symlink() still returns success even though the symlink is not durable and the same operation can already surface -EIO through syncfs().
Return the writeback error to userspace and skip the dirsync flush once the symlink data flush has failed.
--- fs/f2fs/namei.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
fs/f2fs/namei.c +6 -5
@@ -672,15 +672,16 @@ err_out:* performance regression. */ if (!err) { -filemap_write_and_wait_range (inode->i_mapping,0 , - disk_link.len -1 ); + err =filemap_write_and_wait_range (inode->i_mapping,0 , + disk_link.len -1 ); -if (IS_DIRSYNC (dir)) +if (!err &&IS_DIRSYNC (dir))f2fs_sync_fs (sbi->sb,1 ); - }else { -f2fs_unlink (dir, dentry); } +if (err) +f2fs_unlink (dir, dentry); +f2fs_balance_fs (sbi, true); goto out_free_encrypted_link;
Greg Kroah-Hartman
maintainerPATCH 249/1376 f2fs: reject overlapping move range after len expansion
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hao-Qun Huang <[email protected]>
commit 28c1ef094e7c86977d9bf570dc0362fc54e36437 upstream.
F2FS_IOC_MOVE_RANGE treats a zero length as a request to move data from pos_in to EOF. However, the same-file overlap check runs before that expansion, so a request with len == 0 bypasses the overlap rejection added for same-file moves.
For example, with a four-block file, moving from block 0 to block 1 with len == 0 is accepted by the old check because pos_in + len is still pos_in at that point. The code then expands len to cover the rest of the file and calls __exchange_data_block() on overlapping source and destination ranges in the same inode, which is the data-corruption case the overlap check was meant to reject.
Move the overlap check after the source range has been validated and len == 0 has been expanded, so it sees the effective length. This is a no-op for non-zero len (the value is unchanged there) and keeps the existing early return for identical positions.
--- fs/f2fs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/f2fs/file.c +2 -2
@@ -3053,8 +3053,6 @@ static int f2fs_move_file_range(struct fif (src == dst) {if (pos_in == pos_out)return 0 ; -if (pos_out > pos_in && pos_out < pos_in + len) -return -EINVAL ; }inode_lock (src);
@@ -3080,6 +3078,8 @@ static int f2fs_move_file_range(struct f goto out_unlock;if (len ==0 ) olen = len = src->i_size - pos_in; +if (src == dst && pos_out > pos_in && pos_out < pos_in + len) + goto out_unlock;if (pos_in + len == src->i_size) len =ALIGN (src->i_size,F2FS_BLKSIZE ) - pos_in;if (len ==0 ) {
Greg Kroah-Hartman
maintainerPATCH 250/1376 f2fs: use the mount idmap for the owner check in f2fs_xattr_advise_set()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit a54ffce4637acb0db8e695188a6c7f99f14c3576 upstream.
f2fs_xattr_advise_set() calls inode_owner_or_capable() with &nop_mnt_idmap before allowing the "system.advise" xattr to be set, instead of the idmap that the VFS passes to the ->set() handler.
f2fs supports idmapped mounts, so on such a mount this checks the caller's fsuid against the unmapped on-disk owner rather than the mapped owner: the actual owner can be wrongly denied with -EPERM and an unrelated caller wrongly allowed. Pass the handler's idmap instead.
--- fs/f2fs/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/f2fs/xattr.c +1 -1
@@ -118,7 +118,7 @@ static int f2fs_xattr_advise_set(const sunsigned char old_advise =F2FS_I (inode)->i_advise;unsigned char new_advise; -if (!inode_owner_or_capable (&nop_mnt_idmap, inode)) +if (!inode_owner_or_capable (idmap, inode))return -EPERM ;if (value ==NULL )return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 251/1376 f2fs: return writeback error from collapse range
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
commit f8a4108800254d6f7b2755515fbbd9d0caac561e upstream.
f2fs_collapse_range() writes back pages moved by f2fs_do_collapse(), but ignores the return value. If writeback fails, the ioctl can still truncate page cache, shrink blocks, and report success.
Return the error before truncating page cache or updating the file size.
--- fs/f2fs/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/f2fs/file.c +4 -1
@@ -1542,11 +1542,14 @@ static int f2fs_collapse_range(struct in/* write out all moved pages, if possible */ filemap_invalidate_lock (inode->i_mapping); -filemap_write_and_wait_range (inode->i_mapping, offset,LLONG_MAX ); + ret =filemap_write_and_wait_range (inode->i_mapping, offset,LLONG_MAX ); +if (ret) + goto out_unlock;truncate_pagecache (inode, offset); new_size =i_size_read (inode) - len; ret =f2fs_truncate_blocks (inode, new_size, true); +out_unlock:filemap_invalidate_unlock (inode->i_mapping);if (!ret)f2fs_i_size_write (inode, new_size);
Greg Kroah-Hartman
maintainerPATCH 252/1376 f2fs: avoid NULL checkpoint thread access in sysfs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wenjie Qi <[email protected]>
commit 5cb33b00c8fbb6e8f1fa3d281c3036d5f7c7c41f upstream.
checkpoint_merge can be enabled even when no checkpoint merge thread is running. A read-only mount is one case: f2fs does not start f2fs_issue_ckpt there, but ckpt_thread_ioprio is still writable through sysfs.
The ckpt_thread_ioprio store path updates the saved ioprio value and, when checkpoint_merge is enabled, calls set_task_ioprio() for the checkpoint thread. If cprc->f2fs_issue_ckpt is NULL, that dereferences a NULL task pointer.
Protect ckpt_thread_ioprio sysfs writes with s_umount as well, so the checkpoint thread cannot disappear under the store path while updating its ioprio.
--- fs/f2fs/sysfs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
fs/f2fs/sysfs.c +4 -3
@@ -528,7 +528,7 @@ out:return -EINVAL ; cprc->ckpt_thread_ioprio =IOPRIO_PRIO_VALUE (class, level); -if (test_opt (sbi,MERGE_CHECKPOINT )) { +if (cprc->f2fs_issue_ckpt) { ret =set_task_ioprio (cprc->f2fs_issue_ckpt, cprc->ckpt_thread_ioprio);if (ret)
@@ -924,13 +924,14 @@ static ssize_t f2fs_sbi_store(struct f2fssize_t ret;bool gc_entry = (!strcmp (a->attr.name,"gc_urgent" ) || a->struct_type ==GC_THREAD ); +bool thread_entry = !strcmp (a->attr.name,"ckpt_thread_ioprio" ); -if (gc_entry) { +if (gc_entry || thread_entry) {if (!down_read_trylock (&sbi->sb->s_umount))return -EAGAIN ; } ret =__sbi_store (a, sbi, buf, count); -if (gc_entry) +if (gc_entry || thread_entry)up_read (&sbi->sb->s_umount);return ret;
Greg Kroah-Hartman
maintainerPATCH 253/1376 f2fs: fix to migrate all curseg types during free_segment_range
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daeho Jeong <[email protected]>
commit 8ec06f50ddd8d201bd7e55b896ae28ed9d4cb7d1 upstream.
In free_segment_range(), the curseg evacuation loop only iterates up to NR_CURSEG_PERSIST_TYPE (0..5), missing non-persistent in-memory curseg types such as CURSEG_COLD_DATA_PINNED and CURSEG_ALL_DATA_ATGC.
Even though these in-memory curseg types are not saved in the on-disk checkpoint header, they still occupy active physical segments at runtime. If an active in-memory curseg happens to be allocated within the segment range being truncated during filesystem shrink, failing to evacuate it will cause subsequent writes to the curseg attempting out-of-bounds I/O on the truncated storage range.
Fix this by expanding the curseg evacuation loop upper bound to NR_CURSEG_TYPE to ensure all active curseg types are safely migrated out of the target range.
--- fs/f2fs/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/f2fs/gc.c +1 -1
@@ -2171,7 +2171,7 @@ static int free_segment_range(struct f2fmutex_unlock (&DIRTY_I (sbi)->seglist_lock);/* Move out cursegs from the target range */ -for (type =CURSEG_HOT_DATA ; type <NR_CURSEG_PERSIST_TYPE ; type++) { +for (type =CURSEG_HOT_DATA ; type <NR_CURSEG_TYPE ; type++) { err =f2fs_allocate_segment_for_resize (sbi, type, start, end);if (err) goto out;
Greg Kroah-Hartman
maintainerPATCH 254/1376 f2fs: fix i_size when pinned fallocate partially fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit 0f448bb3767ef6119f5cdeabcae3f10d6e75aed6 upstream.
From: Zhan Xusheng <[email protected]>
Commit 4275b59673eb ("f2fs: fix to round down start offset of fallocate for pin file") moved the allocation loop's start down to a section boundary, but the error path still converts @expanded against @pg_start, which holds the unrounded start.
@pg_start exists for that conversion: commit 88f2cfc5fa90 ("f2fs: fix to update last i_size if fallocate partially succeeds") added it as an immutable base because map.m_lblk moves every round. Each round now maps exactly sec_blks blocks starting from rounddown(pg_start, sec_blks), so pg_start + expanded overshoots the last allocated block by pg_start % sec_blks, and a partial failure leaves i_size covering a tail that was never allocated. Nothing corrects that afterwards either, since file_dont_truncate() has already cleared FADVISE_TRUNC_BIT.
It needs a start offset that is not section aligned plus a fallocate that hits ENOSPC partway, so the error path runs with expanded > 0. On an 80 MiB image with 2 MiB sections:
truncate -s 80M img
mkfs.f2fs -s 1 -f img
mount -o loop img /mnt
touch /mnt/pinned
f2fs_io pinfile set /mnt/pinned
# 2093056 = block 511, so pg_start % sec_blks = 511 f2fs_io fallocate 0 2093056 536870912 /mnt/pinned stat -c %s /mnt/pinned
filefrag -v /mnt/pinned
The last extent ends at block 10737 either way. Before, i_size is 46075904, block 11249, so 511 blocks of it were never allocated, and filefrag does not mark the last extent eof. After, i_size is 43982848, block 10738, and eof is back. A kernel from before that commit also shows no overshoot.
Keep @pg_start pointing at where allocation actually begins.
--- fs/f2fs/file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/f2fs/file.c +3 -2
@@ -1844,8 +1844,9 @@ static int f2fs_expand_inode_data(structblock_t sec_len;if (map.m_lblk % sec_blks) { - map.m_lblk =rounddown (map.m_lblk, sec_blks); - map.m_len = pg_end - map.m_lblk; + pg_start =rounddown (map.m_lblk, sec_blks); + map.m_lblk = pg_start; + map.m_len = pg_end - pg_start;if (off_end) map.m_len++; }
Greg Kroah-Hartman
maintainerPATCH 255/1376 f2fs: fix to off-by-one issue in f2fs_zero_post_eof_page()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit b2205d3cfd6c76fd5c5443ee9fdb498cfb0e1c66 upstream.
Otherwise, it will drop one more page after new_size which is not necessary.
--- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/f2fs/file.c +1 -1
@@ -49,7 +49,7 @@ static void f2fs_zero_post_eof_page(struif (lock)filemap_invalidate_lock (inode->i_mapping);/* zero or drop pages only in range of [old_size, new_size] */ -truncate_inode_pages_range (inode->i_mapping, old_size, new_size); +truncate_inode_pages_range (inode->i_mapping, old_size, new_size -1 );if (lock)filemap_invalidate_unlock (inode->i_mapping); }
Greg Kroah-Hartman
maintainerPATCH 256/1376 f2fs: fix valid block count leak on data block allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Changcheng <[email protected]>
commit 0f9af07ecc1ab486038373db6ae0436c5d674b19 upstream.
In __allocate_data_block(), when allocating a new data block (dn->data_blkaddr == NULL_ADDR), inc_valid_block_count() is called first to increment total_valid_block_count and i_blocks. If the subsequent f2fs_allocate_data_block() fails, the function returns the error directly without rolling back the already-incremented block counts, causing a permanent leak.
Fix this by calling dec_valid_block_count() to undo the increment before returning the error. The condition old_blkaddr == NULL_ADDR precisely identifies the case where inc_valid_block_count() was called.
--- fs/f2fs/data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/f2fs/data.c +4 -1
@@ -1454,8 +1454,11 @@ static int __allocate_data_block(struct old_blkaddr = dn->data_blkaddr; err =f2fs_allocate_data_block (sbi,NULL , old_blkaddr, &dn->data_blkaddr, &sum, seg_type,NULL ); -if (err) +if (err) { +if (old_blkaddr ==NULL_ADDR ) +dec_valid_block_count (sbi, dn->inode, count);return err; + }if (GET_SEGNO (sbi, old_blkaddr) !=NULL_SEGNO )f2fs_invalidate_internal_cache (sbi, old_blkaddr);
Greg Kroah-Hartman
maintainerPATCH 257/1376 f2fs: fix to zero post-EOF data when extending file size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
commit 5eced87b7d19dbc76ebdddaf322046f9ac582fcb upstream.
generic/794 4s ... - output mismatch (see /share/git/fstests/results//generic/794.out.bad)
# --- tests/generic/794.out 2026-06-12 08:46:32.766426241 +0800 # +++ /share/git/fstests/results//generic/794.out.bad 2026-07-05 18:32:55.000000000 +0800 # @@ -1,4 +1,16 @@ # QA output created by 794 # append_write # +FAIL: non-zero data in gap [4080,4096) after shutdown+remount # +000000 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a >ZZZZZZZZZZZZZZZZ< # +* # +001000
# truncate_up
# ...
# (Run 'diff -u /share/git/fstests/tests/generic/794.out /share/git/fstests/results//generic/794.out.bad' to see the entire diff)
Ran: generic/794
Failures: generic/794
Failed 1 of 1 tests
Steps of generic/794:
1. write 4096 bytes to file w/ 0x5a
2. use fiemap to get PBA of first block in file
3. truncate file to 4080
4. umount; write 4096 bytes to file w/ 0x5a directly via PBA; mount
5. extend filesize via
a) append 4096 from offset 4096, or
b) truncate 8192, or
c) fallocate 4096 from offset 4096
6. verify the gap is zeroed in memory [4080,4096)
7. sync range 4096 from offset 4096; shutdown -f (flush meta before shutdown)
8. umount; mount; verify [4080,4096) is zeroed or not.
When extending file size (e.g. via truncate, fallocate, or write) across an unaligned EOF boundary, we need to ensure that post-EOF data in the partial page is zeroed out in pagecache and marked dirty, then writeback the cache to persist zeroed data before committing inode w/ updated i_size.
This help to prevent stale disk data beyond the previous EOF from being exposed after remounting or crash recovery.
Since f2fs is a LFS filesystem, we only support direct write via PBA in pinfile, and pinfile has section-aligned filesize, so in Android, there should no problem, but for other usage in different environment, let's fix this w/ fsync_mode=strict mount option.
--- fs/f2fs/file.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 16 deletions(-)
fs/f2fs/file.c +84 -16
@@ -35,16 +35,52 @@#include <trace/events/f2fs.h> #include <uapi/linux/f2fs.h> -static void f2fs_zero_post_eof_page (struct inode *inode, -loff_t new_size,bool lock) +static int fill_zero (struct inode *inode,pgoff_t index, +loff_t start,loff_t len); + +static int do_zero_post_eof_page (struct inode *inode,loff_t new_size) +{ +loff_t old_size =i_size_read (inode); +unsigned int offset, len; +pgoff_t index; +int err; + + offset = old_size & (PAGE_SIZE -1 ); + +if (!offset) +return 0 ; + + len =min_t (loff_t,PAGE_SIZE - offset, new_size - old_size); + index = old_size >>PAGE_SHIFT ; + +if (f2fs_has_inline_data (inode)) { +/* data post eof should be always zero */ +if (new_size <=MAX_INLINE_DATA (inode)) +return 0 ; + err =f2fs_convert_inline_inode (inode); +if (err) +return err; + } + + err =fill_zero (inode, index, offset, len); +if (err) +return err; +return filemap_write_and_wait_range (inode->i_mapping, + old_size, old_size + len -1 ); +} + +static int f2fs_zero_post_eof_page (struct inode *inode, +loff_t new_size,bool lock,bool writeback) {loff_t old_size =i_size_read (inode); +bool strict = +F2FS_OPTION (F2FS_I_SB (inode)).fsync_mode ==FSYNC_MODE_STRICT ;if (old_size >= new_size) -return ; +return 0 ; -if (mapping_empty (inode->i_mapping)) -return ; +if (!strict &&mapping_empty (inode->i_mapping)) +return 0 ;if (lock)filemap_invalidate_lock (inode->i_mapping);
@@ -52,6 +88,16 @@ static void f2fs_zero_post_eof_page(strutruncate_inode_pages_range (inode->i_mapping, old_size, new_size -1 );if (lock)filemap_invalidate_unlock (inode->i_mapping); + +if (!writeback || !strict) +return 0 ; +/* +* In fsync_mode=strict, when we expand an unaligned EOF size, we +* should zero post EOF data and writeback the data immediately, +* so that it can avoid exposing stale data after metadata flush +* and POR. +*/ +return do_zero_post_eof_page (inode, new_size); }static vm_fault_t f2fs_filemap_fault (struct vm_fault *vmf)
@@ -122,7 +168,10 @@ static vm_fault_t f2fs_vm_page_mkwrite(sf2fs_bug_on (sbi,f2fs_has_inline_data (inode)); -f2fs_zero_post_eof_page (inode, (folio->index +1 ) <<PAGE_SHIFT , true); + err =f2fs_zero_post_eof_page (inode, + (folio->index +1 ) <<PAGE_SHIFT , true, false); +if (err) + goto out_pagefault;file_update_time (vmf->vma->vm_file);filemap_invalidate_lock_shared (inode->i_mapping);
@@ -179,7 +228,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(s out_sem:filemap_invalidate_unlock_shared (inode->i_mapping); - +out_pagefault:sb_end_pagefault (inode->i_sb); out: ret =vmf_fs_error (err);
@@ -1097,8 +1146,12 @@ int f2fs_setattr(struct mnt_idmap *idmapf2fs_down_write (&fi->i_gc_rwsem[WRITE ]);filemap_invalidate_lock (inode->i_mapping); -if (attr->ia_size > old_size) -f2fs_zero_post_eof_page (inode, attr->ia_size, false); +if (attr->ia_size > old_size) { + err =f2fs_zero_post_eof_page (inode, + attr->ia_size, false, true); +if (err) + goto err_out; + }truncate_setsize (inode, attr->ia_size);if (attr->ia_size <= old_size)
@@ -1107,6 +1160,7 @@ int f2fs_setattr(struct mnt_idmap *idmap* do not trim all blocks after i_size if target size is * larger than i_size. */ +err_out:filemap_invalidate_unlock (inode->i_mapping);f2fs_up_write (&fi->i_gc_rwsem[WRITE ]);if (err)
@@ -1217,7 +1271,9 @@ static int f2fs_punch_hole(struct inodeif (ret)return ret; -f2fs_zero_post_eof_page (inode, offset + len, true); + ret =f2fs_zero_post_eof_page (inode, offset + len, true, false); +if (ret) +return ret; pg_start = ((unsigned long long ) offset) >>PAGE_SHIFT ; pg_end = ((unsigned long long ) offset + len) >>PAGE_SHIFT ;
@@ -1502,7 +1558,9 @@ static int f2fs_do_collapse(struct inodef2fs_down_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]);filemap_invalidate_lock (inode->i_mapping); -f2fs_zero_post_eof_page (inode, offset + len, false); + ret =f2fs_zero_post_eof_page (inode, offset + len, false, false); +if (ret) + goto out_unlock;f2fs_lock_op (sbi);f2fs_drop_extent_tree (inode);
@@ -1510,6 +1568,7 @@ static int f2fs_do_collapse(struct inode ret =__exchange_data_block (inode, inode, end, start, nrpages - end, true);f2fs_unlock_op (sbi); +out_unlock:filemap_invalidate_unlock (inode->i_mapping);f2fs_up_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]);return ret;
@@ -1631,7 +1690,9 @@ static int f2fs_zero_range(struct inodeif (ret)return ret; -f2fs_zero_post_eof_page (inode, offset + len, true); + ret =f2fs_zero_post_eof_page (inode, offset + len, true, false); +if (ret) +return ret; pg_start = ((unsigned long long ) offset) >>PAGE_SHIFT ; pg_end = ((unsigned long long ) offset + len) >>PAGE_SHIFT ;
@@ -1765,7 +1826,9 @@ static int f2fs_insert_range(struct inodf2fs_down_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]);filemap_invalidate_lock (mapping); -f2fs_zero_post_eof_page (inode, offset + len, false); + ret =f2fs_zero_post_eof_page (inode, offset + len, false, false); +if (ret) + goto out_unlock;truncate_pagecache (inode, offset);while (!ret && idx > pg_start) {
@@ -1781,6 +1844,7 @@ static int f2fs_insert_range(struct inod idx + delta, nr, false);f2fs_unlock_op (sbi); } +out_unlock:filemap_invalidate_unlock (mapping);f2fs_up_write (&F2FS_I (inode)->i_gc_rwsem[WRITE ]);if (ret)
@@ -1823,7 +1887,9 @@ static int f2fs_expand_inode_data(structif (err)return err; -f2fs_zero_post_eof_page (inode, offset + len, true); + err =f2fs_zero_post_eof_page (inode, offset + len, true, true); +if (err) +return err;f2fs_balance_fs (sbi, true);
@@ -4839,8 +4905,10 @@ static ssize_t f2fs_write_checks(structif (err)return err; -f2fs_zero_post_eof_page (inode, - iocb->ki_pos +iov_iter_count (from), true); + err =f2fs_zero_post_eof_page (inode, + iocb->ki_pos +iov_iter_count (from), true, true); +if (err) +return err;return count; }
Greg Kroah-Hartman
maintainerPATCH 258/1376 drm/panthor: fix firmware control interface bounds checks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <[email protected]>
commit 6a47f9fd2d970674ed9dedc52fc7ab76fd015785 upstream.
panthor_init_cs_iface() and panthor_init_csg_iface() validate firmware control interface offsets with 32-bit arithmetic and the size of the host wrapper structures. The offsets are derived from firmware-provided strides, so the arithmetic can wrap before the bounds check, and the host wrapper size is not the size of the firmware control interface being mapped.
Use 64-bit arithmetic for the computed offsets and validate against the actual firmware control interface structure sizes with subtraction-based bounds checks. Also validate that the shared section is large enough for the global control interface before using it.
--- drivers/gpu/drm/panthor/panthor_fw.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/gpu/drm/panthor/panthor_fw.c +13 -6
@@ -797,14 +797,15 @@ static int panthor_init_cs_iface(structstruct panthor_fw_csg_iface *csg_iface =panthor_fw_get_csg_iface (ptdev, csg_idx);struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx];u64 shared_section_sz =panthor_kernel_bo_size (ptdev->fw->shared_section->mem); -u32 iface_offset =CSF_GROUP_CONTROL_OFFSET + - (csg_idx * glb_iface->control->group_stride) + +u64 iface_offset =CSF_GROUP_CONTROL_OFFSET + + ((u64 )csg_idx * glb_iface->control->group_stride) +CSF_STREAM_CONTROL_OFFSET + - (cs_idx * csg_iface->control->stream_stride); + ((u64 )cs_idx * csg_iface->control->stream_stride);struct panthor_fw_cs_iface *first_cs_iface =panthor_fw_get_cs_iface (ptdev,0 ,0 ); -if (iface_offset +sizeof (*cs_iface) >= shared_section_sz) +if (iface_offset > shared_section_sz || +sizeof (*cs_iface->control) > shared_section_sz - iface_offset)return -EINVAL ;spin_lock_init (&cs_iface->lock);
@@ -854,10 +855,12 @@ static int panthor_init_csg_iface(structstruct panthor_fw_global_iface *glb_iface =panthor_fw_get_glb_iface (ptdev);struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx];u64 shared_section_sz =panthor_kernel_bo_size (ptdev->fw->shared_section->mem); -u32 iface_offset =CSF_GROUP_CONTROL_OFFSET + (csg_idx * glb_iface->control->group_stride); +u64 iface_offset =CSF_GROUP_CONTROL_OFFSET + + ((u64 )csg_idx * glb_iface->control->group_stride);unsigned int i; -if (iface_offset +sizeof (*csg_iface) >= shared_section_sz) +if (iface_offset > shared_section_sz || +sizeof (*csg_iface->control) > shared_section_sz - iface_offset)return -EINVAL ;spin_lock_init (&csg_iface->lock);
@@ -909,11 +912,15 @@ static u32 panthor_get_instr_features(ststatic int panthor_fw_init_ifaces (struct panthor_device *ptdev) {struct panthor_fw_global_iface *glb_iface = &ptdev->fw->iface.global; +u64 shared_section_sz =panthor_kernel_bo_size (ptdev->fw->shared_section->mem);unsigned int i;if (!ptdev->fw->shared_section->mem->kmap)return -EINVAL ; +if (sizeof (*glb_iface->control) > shared_section_sz) +return -EINVAL ; +spin_lock_init (&glb_iface->lock); glb_iface->control = ptdev->fw->shared_section->mem->kmap;
Greg Kroah-Hartman
maintainerPATCH 259/1376 drm/bridge: dw-hdmi: fix i2c adapter leak on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 09b195a7bb23df56269cd2a95d01ba3a5533af13 upstream.
Make sure to drop the i2c adapter device and module references before returning when detecting a malformed devicetree during probe.
--- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +2 -1
@@ -3383,7 +3383,8 @@ struct dw_hdmi *dw_hdmi_probe(struct plabreak ;default :dev_err (dev,"reg-io-width must be 1 or 4\n" ); -return ERR_PTR (-EINVAL ); + ret = -EINVAL ; + goto err_res; } iores =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
Greg Kroah-Hartman
maintainerPATCH 260/1376 drm/panel-edp: fix i2c adapter leak on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit e2a9e291275a74e309a21cbb1def6296a72d6aed upstream.
Make sure to drop the i2c adapter reference on probe failure (e.g. probe deferral) and on driver unbind also if a devicetree redundantly uses the 'ddc-i2c-bus' property to point to the aux ddc bus.
--- drivers/gpu/drm/panel/panel-edp.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/gpu/drm/panel/panel-edp.c +13 -6
@@ -831,6 +831,13 @@ exit:return 0 ; } +static void panel_edp_put_adapter (void *_adap) +{ +struct i2c_adapter *adap = _adap; + +put_device (&adap->dev); +} +static int panel_edp_probe (struct device *dev,const struct panel_desc *desc,struct drm_dp_aux *aux) {
@@ -877,6 +884,11 @@ static int panel_edp_probe(struct deviceif (!panel->ddc)return -EPROBE_DEFER ; + + err =devm_add_action_or_reset (dev, panel_edp_put_adapter, + panel->ddc); +if (err) +return err; }else if (aux) { panel->ddc = &aux->ddc; }
@@ -890,7 +902,7 @@ static int panel_edp_probe(struct device err =drm_panel_of_backlight (&panel->base);if (err) - goto err_finished_ddc_init; +return err;/* * We use runtime PM for prepare / unprepare since those power the panel
@@ -937,9 +949,6 @@ static int panel_edp_probe(struct device err_finished_pm_runtime:pm_runtime_dont_use_autosuspend (dev);pm_runtime_disable (dev); -err_finished_ddc_init: -if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc)) -put_device (&panel->ddc->dev);return err; }
@@ -983,8 +992,6 @@ static void panel_edp_remove(struct devipm_runtime_dont_use_autosuspend (dev);pm_runtime_disable (dev); -if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc)) -put_device (&panel->ddc->dev);drm_edid_free (panel->drm_edid); panel->drm_edid =NULL ;
Greg Kroah-Hartman
maintainerPATCH 261/1376 drm: fix race between partial drm_dev_register() failure and ioctl
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danilo Krummrich <[email protected]>
commit eb197f7d60f00d0f5b1b3505dfc86a7e36045a3e upstream.
If drm_dev_register() fails after registering a minor (e.g. render minor registered, primary minor fails), userspace could have opened the first minor and entered a drm_dev_enter() critical section. Since the unplugged flag was never set, the ioctl proceeds while the error path tears down device resources.
Fix this by introducing drm_dev_synchronize_unplug(), which sets the unplugged flag and waits for the SRCU barrier, ensuring all in-flight drm_dev_enter() critical sections complete before cleanup proceeds; call it on the error path of drm_dev_register().
--- drivers/gpu/drm/drm_drv.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
drivers/gpu/drm/drm_drv.c +25 -9
@@ -469,6 +469,22 @@ void drm_dev_exit(int idx) }EXPORT_SYMBOL (drm_dev_exit); +/* +* Mark the device as unplugged and wait for any in-flight drm_dev_enter() +* critical sections to complete. +*/ +static void drm_dev_synchronize_unplug (struct drm_device *dev) +{ +/* +* After synchronizing any critical read section is guaranteed to see +* the new value of ->unplugged, and any critical section which might +* still have seen the old value of ->unplugged is guaranteed to have +* finished. +*/ + dev->unplugged = true; +synchronize_srcu (&drm_unplug_srcu); +} +/** * drm_dev_unplug - unplug a DRM device * @dev: DRM device
@@ -481,15 +497,7 @@ EXPORT_SYMBOL(drm_dev_exit);*/ void drm_dev_unplug (struct drm_device *dev) { -/* -* After synchronizing any critical read section is guaranteed to see -* the new value of ->unplugged, and any critical section which might -* still have seen the old value of ->unplugged is guaranteed to have -* finished. -*/ - dev->unplugged = true; -synchronize_srcu (&drm_unplug_srcu); - +drm_dev_synchronize_unplug (dev);drm_dev_unregister (dev);/* Clear all CPU mappings pointing to this device */
@@ -931,6 +939,7 @@ int drm_dev_register(struct drm_device * goto err_minors; dev->registered = true; + dev->unplugged = false;if (driver->load) { ret = driver->load (dev, flags);
@@ -957,6 +966,13 @@ err_unload:if (dev->driver->unload) dev->driver->unload (dev); err_minors: +/* +* If a minor was registered before the failure, userspace could have +* opened it and entered a drm_dev_enter() critical section. Ensure all +* such sections complete before we clean up. +*/ +drm_dev_synchronize_unplug (dev); +remove_compat_control_link (dev);drm_minor_unregister (dev,DRM_MINOR_ACCEL );drm_minor_unregister (dev,DRM_MINOR_PRIMARY );
Greg Kroah-Hartman
maintainerPATCH 262/1376 drm/i915: Guard against NULL driver_data in i915_pci_probe()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit 3785d40831ba5601296283e0197e10e089392757 upstream.
pci_match_device() can return the dummy pci_device_id_any entry when a device is force-bound via sysfs driver_override, in which case ->driver_data is unset (NULL). i915_pci_probe() casts it to struct intel_device_info * unconditionally and dereferences intel_info->require_force_probe, causing a NULL-ptr-deref.
--- drivers/gpu/drm/i915/i915_pci.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/i915/i915_pci.c +3 -0
@@ -961,6 +961,9 @@ static int i915_pci_probe(struct pci_dev (struct intel_device_info *) ent->driver_data;int err; +if (!intel_info) +return -ENODEV ; +if (intel_info->require_force_probe && !id_forced (pdev->device)) {dev_info (&pdev->dev, "Your graphics device %04x is not properly supported by i915 in this\n"
Greg Kroah-Hartman
maintainerPATCH 263/1376 drm/ssd130x: fix column and row end address in partial updates for ssd132x
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amit Barzilai <[email protected]>
commit 99e9c09358195454ecd200b9c6aba6b7d209fad4 upstream.
On partial screen updates, SSD132X controllers expect to get the rectangle addresses as arguments of the "Set Column Address" and "Set Row Address" commands. Each command expects the start address and end address of the row/column in absolute format, however the end addresses were being sent in a relative format (relative to the start address).
The relative end addresses work only when the start address is 0. In those situations, there is no value difference between relative and absolute addresses.
--- drivers/gpu/drm/solomon/ssd130x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/gpu/drm/solomon/ssd130x.c +3 -2
@@ -863,12 +863,13 @@ static int ssd132x_update_rect(struct ss*/ /* Set column start and end */ - ret =ssd130x_write_cmd (ssd130x,3 ,SSD132X_SET_COL_RANGE , x / segment_width, columns -1 ); + ret =ssd130x_write_cmd (ssd130x,3 ,SSD132X_SET_COL_RANGE , x / segment_width, + x / segment_width + columns -1 );if (ret <0 )return ret;/* Set row start and end */ - ret =ssd130x_write_cmd (ssd130x,3 ,SSD132X_SET_ROW_RANGE , y, rows -1 ); + ret =ssd130x_write_cmd (ssd130x,3 ,SSD132X_SET_ROW_RANGE , y, y + rows -1 );if (ret <0 )return ret;
Greg Kroah-Hartman
maintainerPATCH 264/1376 drm/sun4i: fix refcount leak in sun4i_backend_init_sat()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit f7a56ff6240e6fd0cb36a3c0a911a1cd54789ce2 upstream.
When sun4i_backend_init_sat() calls reset_control_deassert() it increments the deassert_count of the reset controller, and must pair that with a reset_control_assert() call to decrement it. In the error path where clk_prepare_enable() fails, the function returns immediately without calling reset_control_assert(), leaking the reference count. Other error paths, like the devm_clk_get() failure, correctly jump to the err_assert_reset label which performs the missing assert.
Fix the leak by using the existing err_assert_reset label in the clk_prepare_enable error path instead of returning directly.
--- drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/sun4i/sun4i_backend.c +1 -1
@@ -685,7 +685,7 @@ static int sun4i_backend_init_sat(struct ret =clk_prepare_enable (backend->sat_clk);if (ret) {dev_err (dev,"Couldn't enable the SAT clock\n" ); -return ret; + goto err_assert_reset; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 265/1376 drm/ssd130x: fix column and row end address in partial updates in ssd133x
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amit Barzilai <[email protected]>
commit b7fcb70162acd7f15ed20bc64a14c150db34256f upstream.
On partial screen updates, SSD133X controllers expect to get the rectangle addresses as arguments of the "Set Column Address" and "Set Row Address" commands. Each command expects the start address and end address of the row/column in absolute format, however the end addresses were being sent in a relative format (relative to the start address).
The relative end addresses work only when the start address is 0. In those situations, there is no value difference between relative and absolute addresses.
--- drivers/gpu/drm/solomon/ssd130x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/solomon/ssd130x.c +2 -2
@@ -915,12 +915,12 @@ static int ssd133x_update_rect(struct ss*/ /* Set column start and end */ - ret =ssd130x_write_cmd (ssd130x,3 ,SSD133X_SET_COL_RANGE , x, columns -1 ); + ret =ssd130x_write_cmd (ssd130x,3 ,SSD133X_SET_COL_RANGE , x, x + columns -1 );if (ret <0 )return ret;/* Set row start and end */ - ret =ssd130x_write_cmd (ssd130x,3 ,SSD133X_SET_ROW_RANGE , y, rows -1 ); + ret =ssd130x_write_cmd (ssd130x,3 ,SSD133X_SET_ROW_RANGE , y, y + rows -1 );if (ret <0 )return ret;
Greg Kroah-Hartman
maintainerPATCH 266/1376 drm/hibmc: Fix list of formats on the primary plane
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 0e682e136c466ae37c62f18099f591c096260ee0 upstream.
Remove all formats from the primary plane that are unsupported for various reasons.
* Formats with alpha channel: planes should not announce alpha channels unless they support transparency. There's no transparency support in the primary plane's implementation.
* Formats with BGR order. The common format is in RGB channel order. There's no BGR support in the primary plane's implementation.
* RGB888: atomic_update programs the format from cpp[0] * 8 / 16. For RGB888's cpp value of 3 this returns 1.5; rounded to 1. Programming the value of 1 to HIBMC_CRT_DISP_CTL_FORMAT sets up RGB565. Hence, the output is distorted. This can be tested by booting with video=1024x768-24.
Removing all unsupported formats leaves XRGB8888 and RGB565. Both of which are supported and work correctly.
--- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +2 -4
@@ -153,10 +153,8 @@ static void hibmc_plane_atomic_update(st }static const u32 channel_formats1[] = { -DRM_FORMAT_RGB565 ,DRM_FORMAT_BGR565 ,DRM_FORMAT_RGB888 , -DRM_FORMAT_BGR888 ,DRM_FORMAT_XRGB8888 ,DRM_FORMAT_XBGR8888 , -DRM_FORMAT_RGBA8888 ,DRM_FORMAT_BGRA8888 ,DRM_FORMAT_ARGB8888 , -DRM_FORMAT_ABGR8888 +DRM_FORMAT_XRGB8888 , +DRM_FORMAT_RGB565 , };static const struct drm_plane_funcs hibmc_plane_funcs = {
Greg Kroah-Hartman
maintainerPATCH 267/1376 drm/hibmc: Use drm_atomic_helper_check_plane_state()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
commit 715c5db68bdbd4a524b79ebf20fb61e880fffea0 upstream.
Call drm_atomic_helper_check_plane_state() from the primary plane's atomic-check helper and replace the custom implementation.
All plane's implementations of atomic_check should call the shared _check_plane_state() helper first. It adjusts the plane state for correct positioning, rotation and scaling of the plane. Do this even if the plane's CRTC has been disabled by setting the parameter can_update_disabled. The original code returned early in this case, but it's safe to so and cleaner to have all plane state initialized.
As we don't set can_position, drm_atomic_helper_check_plane_state()'s visibility check tests if the plane covers all of the CRTC. This is a small change from the original code, which tested if the plane is exactly the size of the CRTC. With the new test, the plane still has to cover all of the CRTC, but can be larger than the CRTC's size. A later patch can fully implement this feature in hibmc.
If the plane is disabled, the helper clears the visibility flag in the plane state. On errors or if the plane is not visible, the atomic-check helper can return early. Implement all this in hibmc and drop the custom code that does some of it.
v2:
- extend the commit description (Yongbang)
--- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 50 ++++++++----------------- 1 file changed, 16 insertions(+), 34 deletions(-)
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +16 -34
@@ -72,46 +72,28 @@ static int hibmc_get_best_clock_idx(consstatic int hibmc_plane_atomic_check (struct drm_plane *plane,struct drm_atomic_state *state) { -struct drm_plane_state *new_plane_state =drm_atomic_get_new_plane_state (state, - plane); -struct drm_framebuffer *fb = new_plane_state->fb; -struct drm_crtc *crtc = new_plane_state->crtc; -struct drm_crtc_state *crtc_state; -u32 src_w = new_plane_state->src_w >>16 ; -u32 src_h = new_plane_state->src_h >>16 ; - -if (!crtc || !fb) -return 0 ; - - crtc_state =drm_atomic_get_crtc_state (state, crtc); -if (IS_ERR (crtc_state)) -return PTR_ERR (crtc_state); - -if (src_w != new_plane_state->crtc_w || src_h != new_plane_state->crtc_h) { -drm_dbg_atomic (plane->dev,"scale not support\n" ); -return -EINVAL ; - } - -if (new_plane_state->crtc_x <0 || new_plane_state->crtc_y <0 ) { -drm_dbg_atomic (plane->dev,"crtc_x/y of drm_plane state is invalid\n" ); -return -EINVAL ; - } - -if (!crtc_state->enable) +struct drm_plane_state *new_plane_state = +drm_atomic_get_new_plane_state (state, plane); +struct drm_crtc_state *new_crtc_state =NULL ; +int ret; + +if (new_plane_state->crtc) + new_crtc_state =drm_atomic_get_new_crtc_state (state, new_plane_state->crtc); + + ret =drm_atomic_helper_check_plane_state (new_plane_state, new_crtc_state, +DRM_PLANE_NO_SCALING , +DRM_PLANE_NO_SCALING , + false, true); +if (ret) +return ret; +else if (!new_plane_state->visible)return 0 ; -if (new_plane_state->crtc_x + new_plane_state->crtc_w > - crtc_state->adjusted_mode.hdisplay || - new_plane_state->crtc_y + new_plane_state->crtc_h > - crtc_state->adjusted_mode.vdisplay) { -drm_dbg_atomic (plane->dev,"visible portion of plane is invalid\n" ); -return -EINVAL ; - } -if (new_plane_state->fb->pitches[0 ] %128 !=0 ) {drm_dbg_atomic (plane->dev,"wrong stride with 128-byte aligned\n" );return -EINVAL ; } +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 268/1376 drm/amd/display: avoid divide-by-zero in __is_lut_linear()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit 4f40873f8a4107df2b9c8e68c947c4fd0cd519d2 upstream.
__is_lut_linear() computes the expected value of each entry with
expected = i * MAX_DRM_LUT_VALUE / (size - 1);
If it is ever called with a single-entry LUT, size - 1 is zero and the kernel takes a divide error (#DE). A LUT with fewer than two entries cannot describe a linear mapping anyway, so return false early instead of dividing by zero.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +6 -0
@@ -360,6 +360,12 @@ static bool __is_lut_linear(const structuint32_t expected;int delta; +/* A LUT with fewer than two entries can't be interpolated and would +* divide by zero below (size - 1); it can't be treated as linear. +*/ +if (size <2 ) +return false; +for (i =0 ; i < size; i++) {/* All color values should equal */ if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
Greg Kroah-Hartman
maintainerPATCH 269/1376 drm/amd/display: validate plane degamma LUT size for private color prop
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit e4c3ab59021e7c146a84b6671f0d530972bd58b4 upstream.
Unlike the CRTC degamma path, which is guarded by amdgpu_dm_verify_lut_sizes(), the per-plane degamma LUT size was never validated before use. __set_dm_plane_degamma() passed the user-supplied size straight into __is_lut_linear() and, for a non-linear LUT, into __set_input_tf() -> __drm_lut_to_dc_gamma(), the latter always iterating MAX_COLOR_LUT_ENTRIES entries regardless of the actual LUT size.
A malformed AMD_PLANE_DEGAMMA_LUT blob (e.g. a single entry) could thus trigger a divide-by-zero in __is_lut_linear() or an out-of-bounds read in __drm_lut_to_dc_gamma(). Reject any plane degamma LUT whose size does not match MAX_COLOR_LUT_ENTRIES, mirroring the invariant the code already asserts a few lines below (and which the CRTC path enforces).
The AMD_PLANE_DEGAMMA_LUT property is only exposed on builds with AMD_PRIVATE_COLOR defined.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +7 -0
@@ -1149,6 +1149,13 @@ __set_dm_plane_degamma(struct drm_plane_ degamma_lut =__extract_blob_lut (dm_plane_state->degamma_lut, °amma_size); +if (degamma_lut && degamma_size !=MAX_COLOR_LUT_ENTRIES ) { +drm_dbg (plane_state->state->dev, +"Invalid Plane Degamma LUT size. Should be %u but got %u.\n" , +MAX_COLOR_LUT_ENTRIES , degamma_size); +return -EINVAL ; + } + has_degamma_lut = degamma_lut && !__is_lut_linear (degamma_lut, degamma_size);
Greg Kroah-Hartman
maintainerPATCH 270/1376 drm/amdgpu/vcn: fix integer overflow in dec_msg buffer count check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David (Ming Qiang) Wu <[email protected]>
commit 4d7390530853eb7befda9cc786e4c86e8ad7ac9e upstream.
If the supplied msg[2] (num_buffers) is 0x3FFFFFFF, the expression 6 + num_buffers * 4 wraps to 2 and the bounds check passes, letting the parser loop far past the end of the message BO. Triggering it additionally requires a ~4GiB mapping so that msg[1] survives the earlier "header does not fit in BO" check.
Rewrite the test in division form, which is overflow-free by construction. Also update the message to reflect that msg is invalid.
--- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 10 +++++++--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +7 -3
@@ -1898,9 +1898,13 @@ static int vcn_v3_0_dec_msg(struct amdgp len_dw = msg[1 ] /4 ; num_buffers = msg[2 ]; -/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */ -if (num_buffers > len_dw ||6 + num_buffers *4 > len_dw) { -DRM_ERROR ("VCN message has too many buffers!\n" ); +/* Verify that all indices fit within the claimed length. +* There are 6 dwords in the header before the first buffer. +* Each buffer has 4 dwords. Any trailing dwords after the +* last buffer are ignored. +*/ +if (len_dw <6 || num_buffers > (len_dw -6 ) /4 ) { +DRM_ERROR ("Invalid VCN message!\n" ); r = -EINVAL ; goto out; }
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +7 -3
@@ -1821,9 +1821,13 @@ static int vcn_v4_0_dec_msg(struct amdgp len_dw = msg[1 ] /4 ; num_buffers = msg[2 ]; -/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */ -if (num_buffers > len_dw ||6 + num_buffers *4 > len_dw) { -DRM_ERROR ("VCN message has too many buffers!\n" ); +/* Verify that all indices fit within the claimed length. +* There are 6 dwords in the header before the first buffer. +* Each buffer has 4 dwords. Any trailing dwords after the +* last buffer are ignored. +*/ +if (len_dw <6 || num_buffers > (len_dw -6 ) /4 ) { +DRM_ERROR ("Invalid VCN message!\n" ); r = -EINVAL ; goto out; }