usb: typec: bus: verify partner exists in typec_altmode_attention
authorRD Babiera <rdbabiera@google.com>
Mon, 14 Aug 2023 18:05:59 +0000 (18:05 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Aug 2023 12:44:28 +0000 (14:44 +0200)
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>
drivers/usb/typec/bus.c
drivers/usb/typec/tcpm/tcpm.c
include/linux/usb/typec_altmode.h

index fe5b9a2e61f58aba7b1c1218e880d57023e7f2a9..e95ec7e382bb79031b276105b2a94f0509f9c33b 100644 (file)
@@ -183,12 +183,20 @@ EXPORT_SYMBOL_GPL(typec_altmode_exit);
  *
  * Notifies the partner of @adev about Attention command.
  */
-void typec_altmode_attention(struct typec_altmode *adev, u32 vdo)
+int typec_altmode_attention(struct typec_altmode *adev, u32 vdo)
 {
-       struct typec_altmode *pdev = &to_altmode(adev)->partner->adev;
+       struct altmode *partner = to_altmode(adev)->partner;
+       struct typec_altmode *pdev;
+
+       if (!partner)
+               return -ENODEV;
+
+       pdev = &partner->adev;
 
        if (pdev->ops && pdev->ops->attention)
                pdev->ops->attention(pdev, vdo);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(typec_altmode_attention);
 
index 5639b9a1e0bf3355502120b301965586df2b21ed..ab7e3d7249ab4069d3ccf9201c0ce0e307688487 100644 (file)
@@ -1877,7 +1877,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
                        }
                        break;
                case ADEV_ATTENTION:
-                       typec_altmode_attention(adev, p[1]);
+                       if (typec_altmode_attention(adev, p[1]))
+                               tcpm_log(port, "typec_altmode_attention no port partner altmode");
                        break;
                }
        }
index 350d49012659baba691df1442f9cb99f7bc4a2f6..28aeef8f9e7b5d9b6b55f0930dce116d02a4a3ce 100644 (file)
@@ -67,7 +67,7 @@ struct typec_altmode_ops {
 
 int typec_altmode_enter(struct typec_altmode *altmode, u32 *vdo);
 int typec_altmode_exit(struct typec_altmode *altmode);
-void typec_altmode_attention(struct typec_altmode *altmode, u32 vdo);
+int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo);
 int typec_altmode_vdm(struct typec_altmode *altmode,
                      const u32 header, const u32 *vdo, int count);
 int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf,