Commit 73029a4d authored by Daniel Starke's avatar Daniel Starke Committed by Greg Kroah-Hartman

tty: n_gsm: fix reset fifo race condition

gsmtty_write() and gsm_dlci_data_output() properly guard the fifo access.
However, gsm_dlci_close() and gsmtty_flush_buffer() modifies the fifo but
do not guard this.
Add a guard here to prevent race conditions on parallel writes to the fifo.

Fixes: e1eaea46 ("tty: n_gsm line discipline")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarDaniel Starke <daniel.starke@siemens.com>
Link: https://lore.kernel.org/r/20220414094225.4527-17-daniel.starke@siemens.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1adf6fee
...@@ -1442,13 +1442,17 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control) ...@@ -1442,13 +1442,17 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
static void gsm_dlci_close(struct gsm_dlci *dlci) static void gsm_dlci_close(struct gsm_dlci *dlci)
{ {
unsigned long flags;
del_timer(&dlci->t1); del_timer(&dlci->t1);
if (debug & 8) if (debug & 8)
pr_debug("DLCI %d goes closed.\n", dlci->addr); pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED; dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) { if (dlci->addr != 0) {
tty_port_tty_hangup(&dlci->port, false); tty_port_tty_hangup(&dlci->port, false);
spin_lock_irqsave(&dlci->lock, flags);
kfifo_reset(&dlci->fifo); kfifo_reset(&dlci->fifo);
spin_unlock_irqrestore(&dlci->lock, flags);
/* Ensure that gsmtty_open() can return. */ /* Ensure that gsmtty_open() can return. */
tty_port_set_initialized(&dlci->port, 0); tty_port_set_initialized(&dlci->port, 0);
wake_up_interruptible(&dlci->port.open_wait); wake_up_interruptible(&dlci->port.open_wait);
...@@ -3148,13 +3152,17 @@ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty) ...@@ -3148,13 +3152,17 @@ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
static void gsmtty_flush_buffer(struct tty_struct *tty) static void gsmtty_flush_buffer(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
unsigned long flags;
if (dlci->state == DLCI_CLOSED) if (dlci->state == DLCI_CLOSED)
return; return;
/* Caution needed: If we implement reliable transport classes /* Caution needed: If we implement reliable transport classes
then the data being transmitted can't simply be junked once then the data being transmitted can't simply be junked once
it has first hit the stack. Until then we can just blow it it has first hit the stack. Until then we can just blow it
away */ away */
spin_lock_irqsave(&dlci->lock, flags);
kfifo_reset(&dlci->fifo); kfifo_reset(&dlci->fifo);
spin_unlock_irqrestore(&dlci->lock, flags);
/* Need to unhook this DLCI from the transmit queue logic */ /* Need to unhook this DLCI from the transmit queue logic */
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment