Skip to content

Commit 88d02c9

Browse files
groeckgregkh
authored andcommitted
usb: typec: tcpm: Ignore unsupported/unknown alternate mode requests
TCPM may receive PD messages associated with unknown or unsupported alternate modes. If that happens, calls to typec_match_altmode() will return NULL. The tcpm code does not currently take this into account. This results in crashes. Unable to handle kernel NULL pointer dereference at virtual address 000001f0 pgd = 41dad9a1 [000001f0] *pgd=00000000 Internal error: Oops: 5 [#1] THUMB2 Modules linked in: tcpci tcpm CPU: 0 PID: 2338 Comm: kworker/u2:0 Not tainted 5.1.18-sama5-armv7-r2 #6 Hardware name: Atmel SAMA5 Workqueue: 2-0050 tcpm_pd_rx_handler [tcpm] PC is at typec_altmode_attention+0x0/0x14 LR is at tcpm_pd_rx_handler+0xa3b/0xda0 [tcpm] ... [<c03fbee8>] (typec_altmode_attention) from [<bf8030fb>] (tcpm_pd_rx_handler+0xa3b/0xda0 [tcpm]) [<bf8030fb>] (tcpm_pd_rx_handler [tcpm]) from [<c012082b>] (process_one_work+0x123/0x2a8) [<c012082b>] (process_one_work) from [<c0120a6d>] (worker_thread+0xbd/0x3b0) [<c0120a6d>] (worker_thread) from [<c012431f>] (kthread+0xcf/0xf4) [<c012431f>] (kthread) from [<c01010f9>] (ret_from_fork+0x11/0x38) Ignore PD messages if the associated alternate mode is not supported. Fixes: e9576fe ("usb: typec: tcpm: Support for Alternate Modes") Cc: stable <[email protected]> Reported-by: Douglas Gilbert <[email protected]> Cc: Douglas Gilbert <[email protected]> Acked-by: Heikki Krogerus <[email protected]> Tested-by: Douglas Gilbert <[email protected]> Signed-off-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent cb53c51 commit 88d02c9

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

drivers/usb/typec/tcpm/tcpm.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,8 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
11091109
break;
11101110
case CMD_ATTENTION:
11111111
/* Attention command does not have response */
1112-
typec_altmode_attention(adev, p[1]);
1112+
if (adev)
1113+
typec_altmode_attention(adev, p[1]);
11131114
return 0;
11141115
default:
11151116
break;
@@ -1161,20 +1162,26 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
11611162
}
11621163
break;
11631164
case CMD_ENTER_MODE:
1164-
typec_altmode_update_active(pdev, true);
1165-
1166-
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
1167-
response[0] = VDO(adev->svid, 1, CMD_EXIT_MODE);
1168-
response[0] |= VDO_OPOS(adev->mode);
1169-
return 1;
1165+
if (adev && pdev) {
1166+
typec_altmode_update_active(pdev, true);
1167+
1168+
if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
1169+
response[0] = VDO(adev->svid, 1,
1170+
CMD_EXIT_MODE);
1171+
response[0] |= VDO_OPOS(adev->mode);
1172+
return 1;
1173+
}
11701174
}
11711175
return 0;
11721176
case CMD_EXIT_MODE:
1173-
typec_altmode_update_active(pdev, false);
1177+
if (adev && pdev) {
1178+
typec_altmode_update_active(pdev, false);
11741179

1175-
/* Back to USB Operation */
1176-
WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB,
1177-
NULL));
1180+
/* Back to USB Operation */
1181+
WARN_ON(typec_altmode_notify(adev,
1182+
TYPEC_STATE_USB,
1183+
NULL));
1184+
}
11781185
break;
11791186
default:
11801187
break;
@@ -1184,8 +1191,10 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
11841191
switch (cmd) {
11851192
case CMD_ENTER_MODE:
11861193
/* Back to USB Operation */
1187-
WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB,
1188-
NULL));
1194+
if (adev)
1195+
WARN_ON(typec_altmode_notify(adev,
1196+
TYPEC_STATE_USB,
1197+
NULL));
11891198
break;
11901199
default:
11911200
break;
@@ -1196,7 +1205,8 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
11961205
}
11971206

11981207
/* Informing the alternate mode drivers about everything */
1199-
typec_altmode_vdm(adev, p[0], &p[1], cnt);
1208+
if (adev)
1209+
typec_altmode_vdm(adev, p[0], &p[1], cnt);
12001210

12011211
return rlen;
12021212
}

0 commit comments

Comments
 (0)