Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Pass domain number to pci_bus_release_domain_nr() explicitly

The pci_bus_release_domain_nr() API is supposed to free the domain
number allocated by pci_bus_find_domain_nr(). Most of the callers of
pci_bus_find_domain_nr(), store the domain number in pci_bus::domain_nr.

As such, the pci_bus_release_domain_nr() implicitly frees the domain
number by dereferencing 'struct pci_bus'. However, one of the callers
of this API, the PCI endpoint subsystem, doesn't have 'struct pci_bus',
so it only passes NULL. Due to this, the API will end up dereferencing
the NULL pointer.

To fix this issue, pass the domain number to this API explicitly. Since
'struct pci_bus' is not used for anything else other than extracting the
domain number, it makes sense to pass the domain number directly.

Fixes: 0328947c5032 ("PCI: endpoint: Assign PCI domain number for endpoint controllers")
Closes: https://lore.kernel.org/linux-pci/c0c40ddb-bf64-4b22-9dd1-8dbb18aa2813@stanley.mountain
Link: https://lore.kernel.org/linux-pci/20240912053025.25314-1-manivannan.sadhasivam@linaro.org
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[kwilczynski: commit log]
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>

authored by

Manivannan Sadhasivam and committed by
Krzysztof Wilczyński
0cca961a d14bc28a

+11 -11
+1 -1
drivers/pci/endpoint/pci-epc-core.c
··· 840 840 device_unregister(&epc->dev); 841 841 842 842 #ifdef CONFIG_PCI_DOMAINS_GENERIC 843 - pci_bus_release_domain_nr(NULL, &epc->dev); 843 + pci_bus_release_domain_nr(&epc->dev, epc->domain_nr); 844 844 #endif 845 845 } 846 846 EXPORT_SYMBOL_GPL(pci_epc_destroy);
+7 -7
drivers/pci/pci.c
··· 6801 6801 return ida_alloc(&pci_domain_nr_dynamic_ida, GFP_KERNEL); 6802 6802 } 6803 6803 6804 - static void of_pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) 6804 + static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) 6805 6805 { 6806 - if (bus->domain_nr < 0) 6806 + if (domain_nr < 0) 6807 6807 return; 6808 6808 6809 6809 /* Release domain from IDA where it was allocated. */ 6810 - if (of_get_pci_domain_nr(parent->of_node) == bus->domain_nr) 6811 - ida_free(&pci_domain_nr_static_ida, bus->domain_nr); 6810 + if (of_get_pci_domain_nr(parent->of_node) == domain_nr) 6811 + ida_free(&pci_domain_nr_static_ida, domain_nr); 6812 6812 else 6813 - ida_free(&pci_domain_nr_dynamic_ida, bus->domain_nr); 6813 + ida_free(&pci_domain_nr_dynamic_ida, domain_nr); 6814 6814 } 6815 6815 6816 6816 int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) ··· 6819 6819 acpi_pci_bus_find_domain_nr(bus); 6820 6820 } 6821 6821 6822 - void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) 6822 + void pci_bus_release_domain_nr(struct device *parent, int domain_nr) 6823 6823 { 6824 6824 if (!acpi_disabled) 6825 6825 return; 6826 - of_pci_bus_release_domain_nr(bus, parent); 6826 + of_pci_bus_release_domain_nr(parent, domain_nr); 6827 6827 } 6828 6828 #endif 6829 6829
+1 -1
drivers/pci/probe.c
··· 1061 1061 1062 1062 free: 1063 1063 #ifdef CONFIG_PCI_DOMAINS_GENERIC 1064 - pci_bus_release_domain_nr(bus, parent); 1064 + pci_bus_release_domain_nr(parent, bus->domain_nr); 1065 1065 #endif 1066 1066 kfree(bus); 1067 1067 return err;
+1 -1
drivers/pci/remove.c
··· 163 163 #ifdef CONFIG_PCI_DOMAINS_GENERIC 164 164 /* Release domain_nr if it was dynamically allocated */ 165 165 if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) 166 - pci_bus_release_domain_nr(bus, host_bridge->dev.parent); 166 + pci_bus_release_domain_nr(host_bridge->dev.parent, bus->domain_nr); 167 167 #endif 168 168 169 169 pci_remove_bus(bus);
+1 -1
include/linux/pci.h
··· 1884 1884 { return 0; } 1885 1885 #endif 1886 1886 int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); 1887 - void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent); 1887 + void pci_bus_release_domain_nr(struct device *parent, int domain_nr); 1888 1888 #endif 1889 1889 1890 1890 /* Some architectures require additional setup to direct VGA traffic */