usb: dwc3: dwc3-msm-core: Reject incompatible role/mode request

If USB controller is configured to work in a specific mode, reject
any compatible role/mode request. For example, if device mode is
only allowed, switching to host mode/role is not allowed. The current
code allows this and it results in accessing invalid dwc host structures.

Change-Id: I5e4d905c8240ad228f48b40fe36298029d8770e1
Signed-off-by: Pavankumar Kondeti <quic_pkondeti@quicinc.com>
This commit is contained in:
Pavankumar Kondeti 2022-01-04 19:24:31 +05:30 • committed by Michael Bestas
commit c22c572f86
No known key found for this signature in database
GPG key ID: CC95044519BE6669

View file

@ -4219,6 +4219,21 @@ static inline const char *usb_role_string(enum usb_role role)
return "Invalid";
}
static bool dwc3_msm_role_allowed(struct dwc3_msm *mdwc, enum usb_role role)
{
dev_dbg(mdwc->dev, "%s: dr_mode=%s role_requested=%s\n",
__func__, usb_dr_modes[mdwc->dr_mode],
usb_role_string(role));
if (role == USB_ROLE_HOST && mdwc->dr_mode == USB_DR_MODE_PERIPHERAL)
return false;
if (role == USB_ROLE_DEVICE && mdwc->dr_mode == USB_DR_MODE_HOST)
return false;
return true;
}
static enum usb_role dwc3_msm_usb_get_role(struct device *dev)
{
struct dwc3_msm *mdwc = dev_get_drvdata(dev);
@ -4242,6 +4257,9 @@ static int dwc3_msm_usb_set_role(struct device *dev, enum usb_role role)
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
enum usb_role cur_role = USB_ROLE_NONE;
if (!dwc3_msm_role_allowed(mdwc, role))
return -EINVAL;
cur_role = dwc3_msm_usb_get_role(dev);
switch (role) {
@ -4342,14 +4360,13 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
struct dwc3_msm *mdwc = dev_get_drvdata(dev);
if (sysfs_streq(buf, "peripheral")) {
if (mdwc->dr_mode == USB_DR_MODE_HOST) {
dev_err(dev, "Core supports host mode only.\n");
if (!dwc3_msm_role_allowed(mdwc, USB_ROLE_DEVICE))
return -EINVAL;
}
mdwc->vbus_active = true;
mdwc->id_state = DWC3_ID_FLOAT;
} else if (sysfs_streq(buf, "host")) {
if (!dwc3_msm_role_allowed(mdwc, USB_ROLE_HOST))
return -EINVAL;
mdwc->vbus_active = false;
mdwc->id_state = DWC3_ID_GROUND;
} else {