Skip to content
  • Jack Pham's avatar
    1f4642b7
    usb: typec: ucsi: Retrieve all the PDOs instead of just the first 4 · 1f4642b7
    Jack Pham authored
    
    
    commit 4dbc6a4e ("usb: typec: ucsi: save power data objects
    in PD mode") introduced retrieval of the PDOs when connected to a
    PD-capable source. But only the first 4 PDOs are received since
    that is the maximum number that can be fetched at a time given the
    MESSAGE_IN length limitation (16 bytes). However, as per the PD spec
    a connected source may advertise up to a maximum of 7 PDOs.
    
    If such a source is connected it's possible the PPM could have
    negotiated a power contract with one of the PDOs at index greater
    than 4, and would be reflected in the request data object's (RDO)
    object position field. This would result in an out-of-bounds access
    when the rdo_index() is used to index into the src_pdos array in
    ucsi_psy_get_voltage_now().
    
    With the help of the UBSAN -fsanitize=array-bounds checker enabled
    this exact issue is revealed when connecting to a PD source adapter
    that advertise 5 PDOs and the PPM enters a contract having selected
    the 5th one.
    
    [  151.545106][   T70] Unexpected kernel BRK exception at EL1
    [  151.545112][   T70] Internal error: BRK handler: f2005512 [#1] PREEMPT SMP
    ...
    [  151.545499][   T70] pc : ucsi_psy_get_prop+0x208/0x20c
    [  151.545507][   T70] lr : power_supply_show_property+0xc0/0x328
    ...
    [  151.545542][   T70] Call trace:
    [  151.545544][   T70]  ucsi_psy_get_prop+0x208/0x20c
    [  151.545546][   T70]  power_supply_uevent+0x1a4/0x2f0
    [  151.545550][   T70]  dev_uevent+0x200/0x384
    [  151.545555][   T70]  kobject_uevent_env+0x1d4/0x7e8
    [  151.545557][   T70]  power_supply_changed_work+0x174/0x31c
    [  151.545562][   T70]  process_one_work+0x244/0x6f0
    [  151.545564][   T70]  worker_thread+0x3e0/0xa64
    
    We can resolve this by instead retrieving and storing up to the
    maximum of 7 PDOs in the con->src_pdos array. This would involve
    two calls to the GET_PDOS command.
    
    Fixes: 992a60ed ("usb: typec: ucsi: register with power_supply class")
    Fixes: 4dbc6a4e ("usb: typec: ucsi: save power data objects in PD mode")
    Cc: stable@vger.kernel.org
    Reported-and-tested-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
    Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
    Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
    Link: https://lore.kernel.org/r/20210503074611.30973-1-jackp@codeaurora.org
    
    
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    1f4642b7
    usb: typec: ucsi: Retrieve all the PDOs instead of just the first 4
    Jack Pham authored
    
    
    commit 4dbc6a4e ("usb: typec: ucsi: save power data objects
    in PD mode") introduced retrieval of the PDOs when connected to a
    PD-capable source. But only the first 4 PDOs are received since
    that is the maximum number that can be fetched at a time given the
    MESSAGE_IN length limitation (16 bytes). However, as per the PD spec
    a connected source may advertise up to a maximum of 7 PDOs.
    
    If such a source is connected it's possible the PPM could have
    negotiated a power contract with one of the PDOs at index greater
    than 4, and would be reflected in the request data object's (RDO)
    object position field. This would result in an out-of-bounds access
    when the rdo_index() is used to index into the src_pdos array in
    ucsi_psy_get_voltage_now().
    
    With the help of the UBSAN -fsanitize=array-bounds checker enabled
    this exact issue is revealed when connecting to a PD source adapter
    that advertise 5 PDOs and the PPM enters a contract having selected
    the 5th one.
    
    [  151.545106][   T70] Unexpected kernel BRK exception at EL1
    [  151.545112][   T70] Internal error: BRK handler: f2005512 [#1] PREEMPT SMP
    ...
    [  151.545499][   T70] pc : ucsi_psy_get_prop+0x208/0x20c
    [  151.545507][   T70] lr : power_supply_show_property+0xc0/0x328
    ...
    [  151.545542][   T70] Call trace:
    [  151.545544][   T70]  ucsi_psy_get_prop+0x208/0x20c
    [  151.545546][   T70]  power_supply_uevent+0x1a4/0x2f0
    [  151.545550][   T70]  dev_uevent+0x200/0x384
    [  151.545555][   T70]  kobject_uevent_env+0x1d4/0x7e8
    [  151.545557][   T70]  power_supply_changed_work+0x174/0x31c
    [  151.545562][   T70]  process_one_work+0x244/0x6f0
    [  151.545564][   T70]  worker_thread+0x3e0/0xa64
    
    We can resolve this by instead retrieving and storing up to the
    maximum of 7 PDOs in the con->src_pdos array. This would involve
    two calls to the GET_PDOS command.
    
    Fixes: 992a60ed ("usb: typec: ucsi: register with power_supply class")
    Fixes: 4dbc6a4e ("usb: typec: ucsi: save power data objects in PD mode")
    Cc: stable@vger.kernel.org
    Reported-and-tested-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
    Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
    Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
    Link: https://lore.kernel.org/r/20210503074611.30973-1-jackp@codeaurora.org
    
    
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Loading