| From d2fd6e81912a665993b24dcdc1c1384a42a54f7e Mon Sep 17 00:00:00 2001 |
| From: Logan Gunthorpe <logang@deltatee.com> |
| Date: Thu, 17 Jan 2019 08:46:34 -0600 |
| Subject: PCI: Fix __initdata issue with "pci=disable_acs_redir" parameter |
| |
| From: Logan Gunthorpe <logang@deltatee.com> |
| |
| commit d2fd6e81912a665993b24dcdc1c1384a42a54f7e upstream. |
| |
| The disable_acs_redir parameter stores a pointer to the string passed to |
| pci_setup(). However, the string passed to PCI setup is actually a |
| temporary copy allocated in static __initdata memory. After init, once the |
| memory is freed, it is no longer valid to reference this pointer. |
| |
| This bug was noticed in v5.0-rc1 after a change in commit c5eb1190074c |
| ("PCI / PM: Allow runtime PM without callback functions") caused |
| pci_disable_acs_redir() to be called during shutdown which manifested |
| as an unable to handle kernel paging request at: |
| |
| RIP: 0010:pci_enable_acs+0x3f/0x1e0 |
| Call Trace: |
| pci_restore_state.part.44+0x159/0x3c0 |
| pci_restore_standard_config+0x33/0x40 |
| pci_pm_runtime_resume+0x2b/0xd0 |
| ? pci_restore_standard_config+0x40/0x40 |
| __rpm_callback+0xbc/0x1b0 |
| rpm_callback+0x1f/0x70 |
| ? pci_restore_standard_config+0x40/0x40 |
| rpm_resume+0x4f9/0x710 |
| ? pci_conf1_read+0xb6/0xf0 |
| ? pci_conf1_write+0xb2/0xe0 |
| __pm_runtime_resume+0x47/0x70 |
| pci_device_shutdown+0x1e/0x60 |
| device_shutdown+0x14a/0x1f0 |
| kernel_restart+0xe/0x50 |
| __do_sys_reboot+0x1ee/0x210 |
| ? __fput+0x144/0x1d0 |
| do_writev+0x5e/0xf0 |
| ? do_writev+0x5e/0xf0 |
| do_syscall_64+0x48/0xf0 |
| entry_SYSCALL_64_after_hwframe+0x44/0xa9 |
| |
| It was also likely possible to trigger this bug when hotplugging PCI |
| devices. |
| |
| To fix this, instead of storing a pointer, we use kstrdup() to copy the |
| disable_acs_redir_param to its own buffer which will never be freed. |
| |
| Fixes: aaca43fda742 ("PCI: Add "pci=disable_acs_redir=" parameter for peer-to-peer support") |
| Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> |
| Signed-off-by: Logan Gunthorpe <logang@deltatee.com> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| Reviewed-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/pci/pci.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/pci/pci.c |
| +++ b/drivers/pci/pci.c |
| @@ -6113,7 +6113,8 @@ static int __init pci_setup(char *str) |
| } else if (!strncmp(str, "pcie_scan_all", 13)) { |
| pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); |
| } else if (!strncmp(str, "disable_acs_redir=", 18)) { |
| - disable_acs_redir_param = str + 18; |
| + disable_acs_redir_param = |
| + kstrdup(str + 18, GFP_KERNEL); |
| } else { |
| printk(KERN_ERR "PCI: Unknown option `%s'\n", |
| str); |