]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
usb: typec: ucsi: Fix NULL pointer access
authorAndrei Kuchynski <akuchynski@chromium.org>
Wed, 5 Mar 2025 11:17:39 +0000 (11:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Mar 2025 15:55:46 +0000 (16:55 +0100)
Resources should be released only after all threads that utilize them
have been destroyed.
This commit ensures that resources are not released prematurely by waiting
for the associated workqueue to complete before deallocating them.

Cc: stable <stable@kernel.org>
Fixes: b9aa02ca39a4 ("usb: typec: ucsi: Add polling mechanism for partner tasks like alt mode checking")
Signed-off-by: Andrei Kuchynski <akuchynski@chromium.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20250305111739.1489003-2-akuchynski@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/ucsi.c

index 7a56d3f840d75b4abfd4e79ff0b0490950b448c2..2a2915b0a645ff14b4fa6af6a6de5fd1c1dcd41b 100644 (file)
@@ -1825,11 +1825,11 @@ static int ucsi_init(struct ucsi *ucsi)
 
 err_unregister:
        for (con = connector; con->port; con++) {
+               if (con->wq)
+                       destroy_workqueue(con->wq);
                ucsi_unregister_partner(con);
                ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
                ucsi_unregister_port_psy(con);
-               if (con->wq)
-                       destroy_workqueue(con->wq);
 
                usb_power_delivery_unregister_capabilities(con->port_sink_caps);
                con->port_sink_caps = NULL;
@@ -2013,10 +2013,6 @@ void ucsi_unregister(struct ucsi *ucsi)
 
        for (i = 0; i < ucsi->cap.num_connectors; i++) {
                cancel_work_sync(&ucsi->connector[i].work);
-               ucsi_unregister_partner(&ucsi->connector[i]);
-               ucsi_unregister_altmodes(&ucsi->connector[i],
-                                        UCSI_RECIPIENT_CON);
-               ucsi_unregister_port_psy(&ucsi->connector[i]);
 
                if (ucsi->connector[i].wq) {
                        struct ucsi_work *uwork;
@@ -2032,6 +2028,11 @@ void ucsi_unregister(struct ucsi *ucsi)
                        destroy_workqueue(ucsi->connector[i].wq);
                }
 
+               ucsi_unregister_partner(&ucsi->connector[i]);
+               ucsi_unregister_altmodes(&ucsi->connector[i],
+                                        UCSI_RECIPIENT_CON);
+               ucsi_unregister_port_psy(&ucsi->connector[i]);
+
                usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
                ucsi->connector[i].port_sink_caps = NULL;
                usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);