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

usb: typec: bus: verify partner exists in typec_altmode_attention

Some usb hubs will negotiate DisplayPort Alt mode with the device
but will then negotiate a data role swap after entering the alt
mode. The data role swap causes the device to unregister all alt
modes, however the usb hub will still send Attention messages
even after failing to reregister the Alt Mode. type_altmode_attention
currently does not verify whether or not a device's altmode partner
exists, which results in a NULL pointer error when dereferencing
the typec_altmode and typec_altmode_ops belonging to the altmode
partner.

Verify the presence of a device's altmode partner before sending
the Attention message to the Alt Mode driver.

Fixes: 8a37d87d72f0 ("usb: typec: Bus type for alternate modes")
Cc: stable@vger.kernel.org
Signed-off-by: RD Babiera <rdbabiera@google.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230814180559.923475-1-rdbabiera@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

RD Babiera and committed by
Greg Kroah-Hartman
f2364330 20deab8b

+13 -4
+10 -2
drivers/usb/typec/bus.c
··· 183 183 * 184 184 * Notifies the partner of @adev about Attention command. 185 185 */ 186 - void typec_altmode_attention(struct typec_altmode *adev, u32 vdo) 186 + int typec_altmode_attention(struct typec_altmode *adev, u32 vdo) 187 187 { 188 - struct typec_altmode *pdev = &to_altmode(adev)->partner->adev; 188 + struct altmode *partner = to_altmode(adev)->partner; 189 + struct typec_altmode *pdev; 190 + 191 + if (!partner) 192 + return -ENODEV; 193 + 194 + pdev = &partner->adev; 189 195 190 196 if (pdev->ops && pdev->ops->attention) 191 197 pdev->ops->attention(pdev, vdo); 198 + 199 + return 0; 192 200 } 193 201 EXPORT_SYMBOL_GPL(typec_altmode_attention); 194 202
+2 -1
drivers/usb/typec/tcpm/tcpm.c
··· 1877 1877 } 1878 1878 break; 1879 1879 case ADEV_ATTENTION: 1880 - typec_altmode_attention(adev, p[1]); 1880 + if (typec_altmode_attention(adev, p[1])) 1881 + tcpm_log(port, "typec_altmode_attention no port partner altmode"); 1881 1882 break; 1882 1883 } 1883 1884 }
+1 -1
include/linux/usb/typec_altmode.h
··· 67 67 68 68 int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo); 69 69 int typec_altmode_exit(struct typec_altmode *altmode); 70 - void typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); 70 + int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); 71 71 int typec_altmode_vdm(struct typec_altmode *altmode, 72 72 const u32 header, const u32 *vdo, int count); 73 73 int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf,