• Yinghai Lu's avatar
    PCI/ASPM: Always set link->downstream to avoid NULL dereference on remove · 3bd7db63
    Yinghai Lu authored
    We call pcie_aspm_exit_link_state() when we remove a device.  If the device
    is the last PCIe function to be removed below a bridge and the bridge has
    an ASPM link_state struct, we disable ASPM on the link.  Disabling ASPM
    requires link->downstream (used in pcie_config_aspm_link()).
    
    We previously set link->downstream in pcie_aspm_cap_init(), but only if the
    device was not blacklisted.  Removing the blacklisted device caused a NULL
    pointer dereference in the pcie_aspm_exit_link_state() ->
    pcie_config_aspm_link() path:
    
      # echo 1 > /sys/bus/pci/devices/0000\:0b\:00.0/remove
      ...
       BUG: unable to handle kernel NULL pointer dereference at 0000000000000080
       IP: pcie_config_aspm_link+0x5d/0x2b0
       Call Trace:
        pcie_aspm_exit_link_state+0x75/0x130
        pci_stop_bus_device+0xa4/0xb0
        pci_stop_and_remove_bus_device_locked+0x1a/0x30
        remove_store+0x50/0x70
        dev_attr_store+0x18/0x30
        sysfs_kf_write+0x44/0x60
        kernfs_fop_write+0x10e/0x190
        __vfs_write+0x28/0x110
        ? rcu_read_lock_sched_held+0x5d/0x80
        ? rcu_sync_lockdep_assert+0x2c/0x60
        ? __sb_start_write+0x173/0x1a0
        ? vfs_write+0xb3/0x180
        vfs_write+0xc4/0x180
        SyS_write+0x49/0xa0
        do_syscall_64+0xa6/0x1c0
        entry_SYSCALL64_slow_path+0x25/0x25
       ---[ end trace bd187ee0267df5d9 ]---
    
    To avoid this, set link->downstream in alloc_pcie_link_state(), so every
    pcie_link_state structure has a valid link->downstream pointer.
    
    [bhelgaas: changelog]
    Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
    Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
    Acked-by: default avatarRajat Jain <rajatja@google.com>
    CC: stable@vger.kernel.org
    3bd7db63
aspm.c 35.4 KB