[PATCH v2] PCI: Fix Oops caused by uninitialized slot->list in pci_slot_release()
From: Jubin Zhong
Date: Tue Dec 01 2020 - 21:34:43 EST
Once kobject_init_and_add() failed, pci_slot_release() is called to
delete slot->list from parent->slots. But slot->list is intialized
afterwards, so we ran into the following crash:
Unable to handle kernel NULL pointer dereference at virtual address
00000000
...
CPU: 10 PID: 1 Comm: swapper/0 Not tainted 4.4.240 #197
task: ffffeb398a45ef10 task.stack: ffffeb398a470000
PC is at __list_del_entry_valid+0x5c/0xb0
LR is at pci_slot_release+0x84/0xe4
...
__list_del_entry_valid+0x5c/0xb0
pci_slot_release+0x84/0xe4
kobject_put+0x184/0x1c4
pci_create_slot+0x17c/0x1b4
__pci_hp_initialize+0x68/0xa4
pciehp_probe+0x1a4/0x2fc
pcie_port_probe_service+0x58/0x84
driver_probe_device+0x320/0x470
__driver_attach+0x54/0xb8
bus_for_each_dev+0xc8/0xf0
driver_attach+0x30/0x3c
bus_add_driver+0x1b0/0x24c
driver_register+0x9c/0xe0
pcie_port_service_register+0x64/0x7c
pcied_init+0x44/0xa4
do_one_initcall+0x1d0/0x1f0
kernel_init_freeable+0x24c/0x254
kernel_init+0x18/0xe8
ret_from_fork+0x10/0x20
Fixes: 8a94644b440e ("PCI: Fix pci_create_slot() reference count leak")
Signed-off-by: Jubin Zhong <zhongjubin@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx #v4.4.235
----
v2:
Since both slot memory and slot->list would be handled by
pci_slot_release(), we need to make sure slot->list is properly
initialized beforehand.
v1: https://lore.kernel.org/lkml/1606288971-47927-1-git-send-email-zhongjubin@xxxxxxxxxx/
Two things need to be cleaned up on pci_create_slot's error path:
1. free slot memory
2. remove slot->list from its parent->slots
This patch mistakenly took slot memory as unfreed (which is not), and
would introduce double free problem.
---
drivers/pci/slot.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 3861505..ed2077e 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -272,6 +272,9 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
+ INIT_LIST_HEAD(&slot->list);
+ list_add(&slot->list, &parent->slots);
+
err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
"%s", slot_name);
if (err) {
@@ -279,9 +282,6 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
goto err;
}
- INIT_LIST_HEAD(&slot->list);
- list_add(&slot->list, &parent->slots);
-
down_read(&pci_bus_sem);
list_for_each_entry(dev, &parent->devices, bus_list)
if (PCI_SLOT(dev->devfn) == slot_nr)
--
1.8.5.6