aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Khoroshilov <khoroshilov@ispras.ru>2012-09-15 01:29:37 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-26 13:20:40 -0700
commit221b7b5796b520b51c34c40239d77921ba39225b (patch)
tree18a779b98a3872b086461308e49862a0777a0dcb
parent08b79dd10bb24f5fb12446d21d32c87a8136c770 (diff)
pcmcia: synclink_cs: fix potential tty NULL dereference
tty_port_tty_get() can return NULL after port hangup that may happen anytime. The patch adds checks that tty_port_tty_get() returns nonNULL around places where tty is actually used. I have no actual hardware to test the patch, so I have updated rx side processing from common sense only. v2: rx handling updated according Alan Cox feedback. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/char/pcmcia/synclink_cs.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0a484b4..a6b8dde 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -891,6 +891,14 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
int work = 0;
struct mgsl_icount *icount = &info->icount;
+ if (!tty) {
+ /* tty is not available anymore */
+ issue_command(info, CHA, CMD_RXRESET);
+ if (debug_level >= DEBUG_LEVEL_ISR)
+ printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__);
+ return;
+ }
+
if (tcd) {
/* early termination, get FIFO count from RBCL register */
fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
@@ -980,7 +988,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
else
#endif
{
- if (tty->stopped || tty->hw_stopped) {
+ if (tty && (tty->stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
@@ -1000,7 +1008,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
if (!info->tx_active)
return;
} else {
- if (tty->stopped || tty->hw_stopped) {
+ if (tty && (tty->stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
@@ -1050,13 +1058,12 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- if (info->port.flags & ASYNC_CTS_FLOW) {
+ if (tty && (info->port.flags & ASYNC_CTS_FLOW)) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx start...");
- if (tty)
- tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
tx_start(info, tty);
info->pending_bh |= BH_TRANSMIT;
return;
@@ -1065,8 +1072,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
if (!(info->serial_signals & SerialSignal_CTS)) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx stop...");
- if (tty)
- tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
tx_stop(info);
}
}