[PATCH stable v4.4+] usb: gadget: serial: fix oops when data rx'd after close

From: Krzysztof Kozlowski
Date: Thu Oct 18 2018 - 10:29:06 EST


From: Stephen Warren <swarren@xxxxxxxxxx>

commit daa35bd95634a2a2d72d1049c93576a02711cb1a upstream

When the gadget serial device has no associated TTY, do not pass any
received data into the TTY layer for processing; simply drop it instead.
This prevents the TTY layer from calling back into the gadget serial
driver, which will then crash in e.g. gs_write_room() due to lack of
gadget serial device to TTY association (i.e. a NULL pointer dereference).

Signed-off-by: Stephen Warren <swarren@xxxxxxxxxx>
Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
Signed-off-by: Krzysztof Kozlowski <krzk@xxxxxxxxxx>

---

This is necessary for v4.4+ to fix:

[ 134.015750] Unable to handle kernel NULL pointer dereference at virtual address 000000a8
[ 134.023988] pgd = 80004000
[ 134.026749] [000000a8] *pgd=00000000
[ 134.030417] Internal error: Oops: 17 [#1] ARM
[ 134.034826] Modules linked in: ctr ccm usb_f_acm u_serial ath9k_htc ath9k_common ath9k_hw ath mac80211 cfg80211 libcomposite configfs
[ 134.047166] CPU: 0 PID: 51 Comm: kworker/u2:1 Not tainted 4.9.133 #60
[ 134.053664] Hardware name: Freescale Vybrid VF5xx/VF6xx (Device Tree)
[ 134.060195] Workqueue: events_unbound flush_to_ldisc
[ 134.065244] task: 86a42140 task.stack: 86a9a000
[ 134.069872] PC is at gs_flush_chars+0x18/0x30 [u_serial]
[ 134.075261] LR is at n_tty_receive_buf_common+0x648/0xa54
[ 134.080726] pc : [<7f169d4c>] lr : [<803cce74>] psr: 200f0093
[ 134.080726] sp : 86a9be08 ip : 86a9be20 fp : 86a9be1c
[ 134.092310] r10: 86bff600 r9 : 862240cc r8 : 00000000
[ 134.097589] r7 : 862240cc r6 : 00000000 r5 : 00000000 r4 : 200f0013
[ 134.104177] r3 : 7f169d34 r2 : 0000000a r1 : 0000003c r0 : 00000000
[ 134.110763] Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none
[ 134.118081] Control: 10c5387d Table: 85fb8059 DAC: 00000051
[ 134.123882] Process kworker/u2:1 (pid: 51, stack limit = 0x86a9a208)
[ 134.130293] Stack: (0x86a9be08 to 0x86a9c000)
[ 134.134717] be00: 89f0b000 00000000 86a9be8c 86a9be20 803cce74 7f169d40
[ 134.143000] be20: 86bff658 00020001 86bff73c 86a9be38 55555556 89f0b000 86a9be6c 8061f090
[ 134.151282] be40: 89f0b018 89f0d000 89f0b000 00000000 86224090 0000003c 00000000 0000003c
[ 134.159567] be60: 86a9be94 0000003c 803cd280 86be5e00 8604ea40 86be5e14 00000000 86802014
[ 134.167852] be80: 86a9bea4 86a9be90 803cd29c 803cc838 00000001 80101438 86a9bebc 86a9bea8
[ 134.176135] bea0: 803d00c4 803cd28c 86224000 86be5e04 86a9bee4 86a9bec0 803d05fc 803d00a8
[ 134.184419] bec0: 86be5e04 86acf980 00000000 86808700 86802000 00000000 86a9bf1c 86a9bee8
[ 134.192703] bee0: 8012ef38 803d054c 00000088 8090cac0 86a9a000 86acf980 86802000 86acf998
[ 134.200988] bf00: 00000088 8090cac0 86a9a000 86802014 86a9bf5c 86a9bf20 8012f260 8012ee20
[ 134.209270] bf20: 86ad1dc0 8070ee70 8092c91c 86802000 00000000 00000000 86ad1dc0 86a9a000
[ 134.217554] bf40: 86acf980 8012f1f4 00000000 00000000 86a9bfac 86a9bf60 80134a78 8012f200
[ 134.225838] bf60: 00000000 00000000 86ad1dc0 86acf980 00000000 86a9bf74 86a9bf74 00000000
[ 134.234122] bf80: 86a9bf80 86a9bf80 8013b048 86ad1dc0 80134980 00000000 00000000 00000000
[ 134.242406] bfa0: 00000000 86a9bfb0 80107990 8013498c 00000000 00000000 00000000 00000000
[ 134.250688] bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 134.258970] bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[ 134.267228] Backtrace:
[ 134.269785] [<7f169d34>] (gs_flush_chars [u_serial]) from [<803cce74>] (n_tty_receive_buf_common+0x648/0xa54)
[ 134.279800] r5:00000000 r4:89f0b000
[ 134.283449] [<803cc82c>] (n_tty_receive_buf_common) from [<803cd29c>] (n_tty_receive_buf2+0x1c/0x24)
[ 134.292695] r10:86802014 r9:00000000 r8:86be5e14 r7:8604ea40 r6:86be5e00 r5:803cd280
[ 134.300610] r4:0000003c
[ 134.303216] [<803cd280>] (n_tty_receive_buf2) from [<803d00c4>] (tty_ldisc_receive_buf+0x28/0x64)
[ 134.312201] [<803d009c>] (tty_ldisc_receive_buf) from [<803d05fc>] (flush_to_ldisc+0xbc/0xd4)
[ 134.320822] r5:86be5e04 r4:86224000
[ 134.324476] [<803d0540>] (flush_to_ldisc) from [<8012ef38>] (process_one_work+0x124/0x3e0)
[ 134.332851] r9:00000000 r8:86802000 r7:86808700 r6:00000000 r5:86acf980 r4:86be5e04
[ 134.340706] [<8012ee14>] (process_one_work) from [<8012f260>] (worker_thread+0x6c/0x5a8)
[ 134.348905] r10:86802014 r9:86a9a000 r8:8090cac0 r7:00000088 r6:86acf998 r5:86802000
[ 134.356828] r4:86acf980
[ 134.359431] [<8012f1f4>] (worker_thread) from [<80134a78>] (kthread+0xf8/0x110)
[ 134.366847] r10:00000000 r9:00000000 r8:8012f1f4 r7:86acf980 r6:86a9a000 r5:86ad1dc0
[ 134.374765] r4:00000000
[ 134.377375] [<80134980>] (kthread) from [<80107990>] (ret_from_fork+0x14/0x24)
[ 134.384708] r8:00000000 r7:00000000 r6:00000000 r5:80134980 r4:86ad1dc0
[ 134.391483] Code: e24cb004 e5900168 e10f4000 f10c0080 (e59030a8)
[ 134.397643] ---[ end trace 6d6c0a94eccf9fda ]---

Reproduction:
1. Set up USB serial gadget and connect to device.
2. On device:
while true; do echo "abcdefgh01234567890" > /dev/ttyGS0; done
3. On PC, execute simultaneously:
while true; do cat /dev/ttyACM0 >> /tmp/tmp-dl; done
for i in `seq 10000` ; do echo "XXXXXXXXXXXXXX" > /dev/ttyACM0 ; done
---
drivers/usb/gadget/function/u_serial.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index f7771d86ad6c..4ea44f7122ee 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -518,7 +518,7 @@ static void gs_rx_push(unsigned long _port)
}

/* push data to (open) tty */
- if (req->actual) {
+ if (req->actual && tty) {
char *packet = req->buf;
unsigned size = req->actual;
unsigned n;
--
2.7.4