I can restore callstack using T32 as followings;
[<c001df40>] do_page_fault+0x338/0x3f8
[<c0008544>] do_DataAbort+0x38/0x98
[<c0015058>] __dabt_svc+0x38/0x60
[<c031a5a0>] tty_wakeup+0xc/0x64
[<c06f82ec>] gs_start_io+0x94/0xf4
[<c06f8698>] gserial_connect+0xe0/0x180
[<c06f7578>] acm_set_alt+0x88/0x1a8
[<c06f3c5c>] composite_setup+0xd34/0x1520
[<c070d154>] android_setup+0x1f4/0x1fc
[<c03fc6e8>] forward_to_driver+0x64/0x100
[<c03fd418>] musb_g_ep0_irq+0x7d8/0x1c18
[<c03fb094>] musb_interrupt+0x94/0xc78
[<c04024f0>] generic_interrupt+0xc34/0x1218
[<c009b020>] handle_irq_event_percpu+0xe0/0x2e4
[<c009b268>] handle_irq_event+0x44/0x64
[<c009df54>] handle_fasteoi_irq+0xe8/0x1a4
[<c009a7dc>] __handle_domain_irq+0x104/0x264
[<c0008668>] gic_handle_irq+0x2c/0x64
[<c00153a8>] __irq_usr+0x48/0x60
Kernel panic occurs because R0 is holding 0x0 whose instance is (struct tty_struct *tty).
NSR:C031A594|E1A0C00D tty_wakeup: cpy r12,r13
NSR:C031A598|E92DD830 push {r4-r5,r11-r12,r14,pc}
NSR:C031A59C|E24CB004 sub r11,r12,#0x4 ; r11,r12,#4
NSR:C031A5A0|E59031CC_______________ldr____r3,r0,#0x1CC //<--
Let me take times to look into tty_wakeup() more.
void tty_wakeup(struct tty_struct *tty)
{
struct tty_ldisc *ld;
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { // <<-- kernel panic
ld = tty_ldisc_ref(tty);
if (ld)
{
if (ld->ops->write_wakeup) ld->ops->write_wakeup(tty);
tty_ldisc_deref(ld);
}
}
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
}
As kernel log indicates below right before kernel panic occurs, gs_close() is called as mdl_sock_host.
Inside gs_close(), port->port.tty is updated as NULL.
[ 6285.082083 / 06-01 11:43:40.318] -(4)[981:mdl_sock_host]gs_close: ttyGS1 (d3681900,d7e1ca80) ...
<< Code fragment >>
static void gs_close(struct tty_struct *tty, struct file *file)
{
struct gs_port *port = tty->driver_data;
struct gserial *gser;
//snip
if (gser == NULL)
gs_buf_free(&port->port_write_buf);
else
gs_buf_clear(&port->port_write_buf);
tty->driver_data = NULL;
port->port.tty = NULL; // <<--
port->openclose = false;
Right after gs_close() is called, acm driver calls tty_wakeup() function during enumeration operation, which causes kernel panic.
With following patch, kernel crash was fixed.
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 27a7cdc..4b88415 100644
? a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -784,8 +784,11 @@ static int gs_start_io(struct gs_port *port)
port->n_read = 0;
started = gs_start_rx(port);
+ if (!port->port_usb)
+ return -EIO;
+
/* unblock any pending writes into our circular buffer */
if (started) {
+ if (started && port->port.tty) {
tty_wakeup(port->port.tty);
} else {
gs_free_requests(ep, head, &port->read_allocated);
The call to tty_wakeup() is only made in case port->port.tty points to valid address.
'Kernel Crash Case-Studies' 카테고리의 다른 글
[KernelCrash] Abort at do_raw_spin_lock() with "cat /d/shrinker" (0) | 2019.03.09 |
---|---|
[Liunx][Kernel] Abort at __list_del_entry() inside process_one_work() (0) | 2019.03.09 |
[KernelCrash] Abort at 0xecb29f00(defective device) (0) | 2019.03.09 |
[KernelCrash] Abort at mmc_wait_data_done() due to race (0) | 2019.03.09 |
[KernelCrash] Abort at __stack_chk_fail() due to defective memory (0) | 2019.03.09 |