diff --git a/patches.suse/usb-dwc3-Fix-race-between-dwc3_set_mode-and-__dwc3_s.patch b/patches.suse/usb-dwc3-Fix-race-between-dwc3_set_mode-and-__dwc3_s.patch new file mode 100644 index 0000000..3d99ec9 --- /dev/null +++ b/patches.suse/usb-dwc3-Fix-race-between-dwc3_set_mode-and-__dwc3_s.patch @@ -0,0 +1,103 @@ +From 62c73bfea048e66168df09da6d3e4510ecda40bb Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Mon, 28 Nov 2022 17:15:26 +0100 +Subject: [PATCH] usb: dwc3: Fix race between dwc3_set_mode and __dwc3_set_mode +Git-commit: 62c73bfea048e66168df09da6d3e4510ecda40bb +References: git-fixes +Patch-mainline: v6.2-rc1 + +dwc->desired_dr_role is changed by dwc3_set_mode inside a spinlock but +then read by __dwc3_set_mode outside of that lock. This can lead to a +race condition when very quick successive role switch events happen: + +CPU A + dwc3_set_mode(DWC3_GCTL_PRTCAP_HOST) // first role switch event + spin_lock_irqsave(&dwc->lock, flags); + dwc->desired_dr_role = mode; // DWC3_GCTL_PRTCAP_HOST + spin_unlock_irqrestore(&dwc->lock, flags); + queue_work(system_freezable_wq, &dwc->drd_work); + +CPU B + __dwc3_set_mode + // .... + spin_lock_irqsave(&dwc->lock, flags); + // desired_dr_role is DWC3_GCTL_PRTCAP_HOST + dwc3_set_prtcap(dwc, dwc->desired_dr_role); + spin_unlock_irqrestore(&dwc->lock, flags); + +CPU A + dwc3_set_mode(DWC3_GCTL_PRTCAP_DEVICE) // second event + spin_lock_irqsave(&dwc->lock, flags); + dwc->desired_dr_role = mode; // DWC3_GCTL_PRTCAP_DEVICE + spin_unlock_irqrestore(&dwc->lock, flags); + +CPU B (continues running __dwc3_set_mode) + switch (dwc->desired_dr_role) { // DWC3_GCTL_PRTCAP_DEVICE + // .... + case DWC3_GCTL_PRTCAP_DEVICE: + // .... + ret = dwc3_gadget_init(dwc); + +We then have DWC3_GCTL.DWC3_GCTL_PRTCAPDIR = DWC3_GCTL_PRTCAP_HOST and +dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST but initialized the +controller in device mode. It's also possible to get into a state +where both host and device are intialized at the same time. +Fix this race by creating a local copy of desired_dr_role inside +__dwc3_set_mode while holding dwc->lock. + +Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly") +Cc: stable +Acked-by: Thinh Nguyen +Signed-off-by: Sven Peter +Link: https://lore.kernel.org/r/20221128161526.79730-1-sven@svenpeter.dev +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Oliver Neukum +--- + drivers/usb/dwc3/core.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -118,17 +118,22 @@ static void __dwc3_set_mode(struct work_ + struct dwc3 *dwc = work_to_dwc(work); + unsigned long flags; + int ret; ++ u32 desired_dr_role; + +- if (!dwc->desired_dr_role) ++ spin_lock_irqsave(&dwc->lock, flags); ++ desired_dr_role = dwc->desired_dr_role; ++ spin_unlock_irqrestore(&dwc->lock, flags); ++ ++ if (!desired_dr_role) + return; + +- if (dwc->desired_dr_role == dwc->current_dr_role) ++ if (desired_dr_role == dwc->current_dr_role) + return; + + if (dwc->dr_mode != USB_DR_MODE_OTG) + return; + +- if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG) ++ if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG) + return; + + switch (dwc->current_dr_role) { +@@ -145,13 +150,13 @@ static void __dwc3_set_mode(struct work_ + + spin_lock_irqsave(&dwc->lock, flags); + +- dwc3_set_prtcap(dwc, dwc->desired_dr_role); ++ dwc3_set_prtcap(dwc, desired_dr_role); + +- dwc->current_dr_role = dwc->desired_dr_role; ++ dwc->current_dr_role = desired_dr_role; + + spin_unlock_irqrestore(&dwc->lock, flags); + +- switch (dwc->desired_dr_role) { ++ switch (desired_dr_role) { + case DWC3_GCTL_PRTCAP_HOST: + ret = dwc3_host_init(dwc); + if (ret) diff --git a/series.conf b/series.conf index a7bb8f9..ce73e36 100644 --- a/series.conf +++ b/series.conf @@ -63156,6 +63156,7 @@ patches.suse/crypto-arm64-Fix-unused-variable-compilation-warnings-of-cpu_feature.patch patches.suse/tracing-Fix-infinite-loop-in-tracing_read_pipe-on-overflowed-print_trace_line.patch patches.suse/usb-typec-Check-for-ops-exit-instead-of-ops-enter-in.patch + patches.suse/usb-dwc3-Fix-race-between-dwc3_set_mode-and-__dwc3_s.patch patches.suse/usb-storage-Add-check-for-kcalloc.patch patches.suse/x86-mm-Randomize-per-cpu-entry-area.patch patches.suse/powerpc-xive-add-missing-iounmap-in-error-path-in-xi.patch