mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 04:12:04 -04:00
tty: hvc_console, fix crashes on parallel open/close
hvc_open sets tty->driver_data to NULL when open fails at some point. Typically, the failure happens in hp->ops->notifier_add(). If there is a racing process which tries to open such mangled tty, which was not closed yet, the process will crash in hvc_open as tty->driver_data is NULL. All this happens because close wants to know whether open failed or not. But ->open should not NULL this and other tty fields for ->close to be happy. ->open should call tty_port_set_initialized(true) and close should check by tty_port_initialized() instead. So do this properly in this driver. So this patch removes these from ->open: * tty_port_tty_set(&hp->port, NULL). This happens on last close. * tty->driver_data = NULL. Dtto. * tty_port_put(&hp->port). This happens in shutdown and until now, this must have been causing a reference underflow, if I am not missing something. Change-Id: Ie67e9bc9038a282a22f7a7baf7a4588549416725 Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: stable <stable@vger.kernel.org> Reported-and-tested-by: Raghavendra <rananta@codeaurora.org> Link: https://lore.kernel.org/r/20200526145632.13879-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Git-commit: 24eb2377f977fe06d84fca558f891f95bc28a449 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
This commit is contained in:
parent
bf4eaa44f7
commit
dbc45f4c7c
1 changed files with 8 additions and 15 deletions
|
|
@ -375,15 +375,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
|||
* tty fields and return the kref reference.
|
||||
*/
|
||||
if (rc) {
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
tty->driver_data = NULL;
|
||||
tty_port_put(&hp->port);
|
||||
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
|
||||
} else
|
||||
} else {
|
||||
/* We are ready... raise DTR/RTS */
|
||||
if (C_BAUD(tty))
|
||||
if (hp->ops->dtr_rts)
|
||||
hp->ops->dtr_rts(hp, 1);
|
||||
tty_port_set_initialized(&hp->port, true);
|
||||
}
|
||||
|
||||
/* Force wakeup of the polling thread */
|
||||
hvc_kick();
|
||||
|
|
@ -393,22 +392,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
static void hvc_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct hvc_struct *hp;
|
||||
struct hvc_struct *hp = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (tty_hung_up_p(filp))
|
||||
return;
|
||||
|
||||
/*
|
||||
* No driver_data means that this close was issued after a failed
|
||||
* hvc_open by the tty layer's release_dev() function and we can just
|
||||
* exit cleanly because the kref reference wasn't made.
|
||||
*/
|
||||
if (!tty->driver_data)
|
||||
return;
|
||||
|
||||
hp = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
|
||||
if (--hp->port.count == 0) {
|
||||
|
|
@ -416,6 +405,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
|||
/* We are done with the tty pointer now. */
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
if (!tty_port_initialized(&hp->port))
|
||||
return;
|
||||
|
||||
if (C_HUPCL(tty))
|
||||
if (hp->ops->dtr_rts)
|
||||
hp->ops->dtr_rts(hp, 0);
|
||||
|
|
@ -432,6 +424,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
|||
* waking periodically to check chars_in_buffer().
|
||||
*/
|
||||
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
|
||||
tty_port_set_initialized(&hp->port, false);
|
||||
} else {
|
||||
if (hp->port.count < 0)
|
||||
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
||||
|
|
|
|||
Loading…
Reference in a new issue