Skip to content

Commit c1ec902

Browse files
niklas88smb49
authored andcommitted
s390/pci: Fix leak of struct zpci_dev when zpci_add_device() fails
BugLink: https://bugs.launchpad.net/bugs/2102118 commit 4879610 upstream. Prior to commit 0467cdd ("s390/pci: Sort PCI functions prior to creating virtual busses") the IOMMU was initialized and the device was registered as part of zpci_create_device() with the struct zpci_dev freed if either resulted in an error. With that commit this was moved into a separate function called zpci_add_device(). While this new function logs when adding failed, it expects the caller not to use and to free the struct zpci_dev on error. This difference between it and zpci_create_device() was missed while changing the callers and the incompletely initialized struct zpci_dev may get used in zpci_scan_configured_device in the error path. This then leads to a crash due to the device not being registered with the zbus. It was also not freed in this case. Fix this by handling the error return of zpci_add_device(). Since in this case the zdev was not added to the zpci_list it can simply be discarded and freed. Also make this more explicit by moving the kref_init() into zpci_add_device() and document that zpci_zdev_get()/zpci_zdev_put() must be used after adding. Cc: stable@vger.kernel.org Fixes: 0467cdd ("s390/pci: Sort PCI functions prior to creating virtual busses") Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [koichiroden: adjusted context due to missing commits: bcb5d6c ("s390/pci: introduce lock to synchronize state of zpci_dev's") 0d48566 ("s390/pci: rename lock member in struct zpci_dev")] Signed-off-by: Koichiro Den <koichiro.den@canonical.com> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
1 parent 3ff3d61 commit c1ec902

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

arch/s390/pci/pci.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -784,8 +784,9 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
784784
* @fh: Current Function Handle of the device to be created
785785
* @state: Initial state after creation either Standby or Configured
786786
*
787-
* Creates a new zpci device and adds it to its, possibly newly created, zbus
788-
* as well as zpci_list.
787+
* Allocates a new struct zpci_dev and queries the platform for its details.
788+
* If successful the device can subsequently be added to the zPCI subsystem
789+
* using zpci_add_device().
789790
*
790791
* Returns: the zdev on success or an error pointer otherwise
791792
*/
@@ -808,7 +809,6 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
808809
goto error;
809810
zdev->state = state;
810811

811-
kref_init(&zdev->kref);
812812
mutex_init(&zdev->lock);
813813
mutex_init(&zdev->kzdev_lock);
814814

@@ -820,6 +820,17 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
820820
return ERR_PTR(rc);
821821
}
822822

823+
/**
824+
* zpci_add_device() - Add a previously created zPCI device to the zPCI subsystem
825+
* @zdev: The zPCI device to be added
826+
*
827+
* A struct zpci_dev is added to the zPCI subsystem and to a virtual PCI bus creating
828+
* a new one as necessary. A hotplug slot is created and events start to be handled.
829+
* If successful from this point on zpci_zdev_get() and zpci_zdev_put() must be used.
830+
* If adding the struct zpci_dev fails the device was not added and should be freed.
831+
*
832+
* Return: 0 on success, or an error code otherwise
833+
*/
823834
int zpci_add_device(struct zpci_dev *zdev)
824835
{
825836
int rc;
@@ -833,6 +844,7 @@ int zpci_add_device(struct zpci_dev *zdev)
833844
if (rc)
834845
goto error_destroy_iommu;
835846

847+
kref_init(&zdev->kref);
836848
spin_lock(&zpci_list_lock);
837849
list_add_tail(&zdev->entry, &zpci_list);
838850
spin_unlock(&zpci_list_lock);
@@ -1120,7 +1132,8 @@ static void zpci_add_devices(struct list_head *scan_list)
11201132
list_sort(NULL, scan_list, &zpci_cmp_rid);
11211133
list_for_each_entry_safe(zdev, tmp, scan_list, entry) {
11221134
list_del_init(&zdev->entry);
1123-
zpci_add_device(zdev);
1135+
if (zpci_add_device(zdev))
1136+
kfree(zdev);
11241137
}
11251138
}
11261139

arch/s390/pci/pci_event.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
333333
zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
334334
if (IS_ERR(zdev))
335335
break;
336-
zpci_add_device(zdev);
336+
if (zpci_add_device(zdev)) {
337+
kfree(zdev);
338+
break;
339+
}
337340
} else {
338341
/* the configuration request may be stale */
339342
if (zdev->state != ZPCI_FN_STATE_STANDBY)
@@ -347,7 +350,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
347350
zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
348351
if (IS_ERR(zdev))
349352
break;
350-
zpci_add_device(zdev);
353+
if (zpci_add_device(zdev)) {
354+
kfree(zdev);
355+
break;
356+
}
351357
} else {
352358
zpci_update_fh(zdev, ccdf->fh);
353359
}

0 commit comments

Comments
 (0)