]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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, 19 Sep 2023 10:22:53 +0000 (12:22 +0200)
commit f23643306430f86e2f413ee2b986e0773e79da31 upstream.

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 0aefb9e14f22815bd0e8acb26afcd6b5444e0f58..407d2a84633a888d84020d6bd43e43733eac03f3 100644 (file)
@@ -154,12 +154,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 104d16506bfeb8b542849df19d73dbf222c62065..7833518c60388df35fd5ee3a9325cb49e1a411eb 100644 (file)
@@ -1863,7 +1863,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 65933cbe91299972b837abbde0c37bc44c4f2e8e..c33a8bc626d3679db2a1165178743c201aa2bb7c 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,