lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 05 Oct 2008 17:12:05 +0100
From:	Alan Cox <alan@...hat.com>
To:	linux-kernel@...r.kernel.org
Subject: [PATCH 39/76] tty: kref usage for isicom and moxa

Rather than blindly keep taking krefs we reorder the code in a few places
to pass the tty down to the right place (which is important as from the user
side it is not the case that tty == port->tty in all situations). For the irq
and related paths use the krefs to stop the tty being freed under us.

Signed-off-by: Alan Cox <alan@...hat.com>
---

 drivers/char/isicom.c |   61 +++++++++++++++++++++++++------------------------
 drivers/char/moxa.c   |   61 +++++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 53 deletions(-)

diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 8f7cc19..7d30ee1 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
 	if (retries >= 100)
 		goto unlock;
 
+	tty = tty_port_tty_get(&port->port);
+	if (tty == NULL)
+		goto put_unlock;
+
 	for (; count > 0; count--, port++) {
 		/* port not active or tx disabled to force flow control */
 		if (!(port->port.flags & ASYNC_INITIALIZED) ||
 				!(port->status & ISI_TXOK))
 			continue;
 
-		tty = port->port.tty;
-
-		if (tty == NULL)
-			continue;
-
 		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
 		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
 			continue;
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
 			tty_wakeup(tty);
 	}
 
+put_unlock:
+	tty_kref_put(tty);
 unlock:
 	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
 	/*	schedule another tx for hopefully in about 10ms	*/
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty == NULL) {
 		word_count = byte_count >> 1;
 		while (byte_count > 1) {
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 			}
 
 			if (port->port.flags & ASYNC_CTS_FLOW) {
-				if (port->port.tty->hw_stopped) {
+				if (tty->hw_stopped) {
 					if (header & ISI_CTS) {
 						port->port.tty->hw_stopped = 0;
 						/* start tx ing */
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 						tty_wakeup(tty);
 					}
 				} else if (!(header & ISI_CTS)) {
-					port->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					/* stop tx ing */
 					port->status &= ~(ISI_TXOK | ISI_CTS);
 				}
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 	}
 	outw(0x0000, base+0x04); /* enable interrupts */
 	spin_unlock(&card->card_lock);
+	tty_kref_put(tty);
 
 	return IRQ_HANDLED;
 }
 
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
-	struct tty_struct *tty;
 	unsigned long baud;
 	unsigned long base = card->base;
 	u16 channel_setup, channel = port->channel,
 		shift_count = card->shift_count;
 	unsigned char flow_ctrl;
 
-	tty = port->port.tty;
-
-	if (tty == NULL)
-		return;
 	/* FIXME: Switch to new tty baud API */
 	baud = C_BAUD(tty);
 	if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)
 
 		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
 		if (baud < 1 || baud > 4)
-			port->port.tty->termios->c_cflag &= ~CBAUDEX;
+			tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			baud += 15;
 	}
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
 	spin_unlock_irqrestore(&bp->card_lock, flags);
 }
 
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
 	unsigned long flags;
 
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
 		return -ENOMEM;
 
 	spin_lock_irqsave(&card->card_lock, flags);
-	if (port->port.tty)
-		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	if (port->port.count == 1)
 		card->count++;
 
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
 		InterruptTheCard(card->base);
 	}
 
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	port->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
 
 	port->port.count++;
 	tty->driver_data = port;
-	port->port.tty = tty;
-	error = isicom_setup_port(port);
+	tty_port_tty_set(&port->port, tty);
+	error = isicom_setup_port(tty);
 	if (error == 0)
 		error = block_til_ready(tty, filp, port);
 	return error;
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
 	struct isi_board *card = port->card;
 	struct tty_struct *tty;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
-	if (!(port->port.flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED)) {
+		tty_kref_put(tty);
 		return;
+	}
 
 	tty_port_free_xmit_buf(&port->port);
 	port->port.flags &= ~ASYNC_INITIALIZED;
 	/* 3rd October 2000 : Vinayak P Risbud */
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 
 	/*Fix done by Anil .S on 30-04-2001
 	remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
 	return 0;
 }
 
-static int isicom_set_serial_info(struct isi_port *port,
-	struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+					struct serial_struct __user *info)
 {
+	struct isi_port *port = tty->driver_data;
 	struct serial_struct newinfo;
 	int reconfig_port;
 
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
 	if (reconfig_port) {
 		unsigned long flags;
 		spin_lock_irqsave(&port->card->card_lock, flags);
-		isicom_config_port(port);
+		isicom_config_port(tty);
 		spin_unlock_irqrestore(&port->card->card_lock, flags);
 	}
 	unlock_kernel();
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
 		return isicom_get_serial_info(port, argp);
 
 	case TIOCSSERIAL:
-		return isicom_set_serial_info(port, argp);
+		return isicom_set_serial_info(tty, argp);
 
 	default:
 		return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
 		return;
 
 	spin_lock_irqsave(&port->card->card_lock, flags);
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	spin_unlock_irqrestore(&port->card->card_lock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)
 
 	port->port.count = 0;
 	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 	wake_up_interruptible(&port->port.open_wait);
 }
 
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index d3d7864..5df4003 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
 static void moxa_poll(unsigned long);
 static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
 static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
 /*
  * moxa board interface functions:
  */
@@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
 static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
 static int MoxaPortLineStatus(struct moxa_port *);
 static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
 static int MoxaPortReadData(struct moxa_port *);
 static int MoxaPortTxQueue(struct moxa_port *);
 static int MoxaPortRxQueue(struct moxa_port *);
@@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
 		for (i = 0; i < MAX_BOARDS; i++) {
 			p = moxa_boards[i].ports;
 			for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+				struct tty_struct *ttyp;
 				memset(&tmp, 0, sizeof(tmp));
 				if (!moxa_boards[i].ready)
 					goto copy;
@@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
 				if (status & 4)
 					tmp.dcd = 1;
 
-				if (!p->port.tty || !p->port.tty->termios)
+				ttyp = tty_port_tty_get(&p->port);
+				if (!ttyp || !ttyp->termios)
 					tmp.cflag = p->cflag;
 				else
-					tmp.cflag = p->port.tty->termios->c_cflag;
+					tmp.cflag = ttyp->termios->c_cflag;
+				tty_kref_put(tty);
 copy:
 				if (copy_to_user(argm, &tmp, sizeof(tmp))) {
 					mutex_unlock(&moxa_openlock);
@@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 
 	/* pci hot-un-plug support */
 	for (a = 0; a < brd->numPorts; a++)
-		if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
-			tty_hangup(brd->ports[a].port.tty);
+		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+			struct tty_struct *tty = tty_port_tty_get(
+						&brd->ports[a].port);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
+		}
 	while (1) {
 		opened = 0;
 		for (a = 0; a < brd->numPorts; a++)
@@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void)
 module_init(moxa_init);
 module_exit(moxa_exit);
 
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
 {
-	moxa_shut_down(ch);
+	struct moxa_port *ch = tty->driver_data;
+	moxa_shut_down(tty);
 	MoxaPortFlushData(ch, 2);
 	ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	ch->port.tty->driver_data = NULL;
-	ch->port.tty = NULL;
+	tty->driver_data = NULL;
+	tty_port_tty_set(&ch->port, NULL);
 }
 
 static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
 	ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
 	ch->port.count++;
 	tty->driver_data = ch;
-	ch->port.tty = tty;
+	tty_port_tty_set(&ch->port, tty);
 	if (!(ch->port.flags & ASYNC_INITIALIZED)) {
 		ch->statusflags = 0;
 		moxa_set_tty_param(tty, tty->termios);
@@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
 	if (retval) {
 		if (ch->port.count) /* 0 means already hung up... */
 			if (--ch->port.count == 0)
-				moxa_close_port(ch);
+				moxa_close_port(tty);
 	} else
 		ch->port.flags |= ASYNC_NORMAL_ACTIVE;
 	mutex_unlock(&moxa_openlock);
@@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
 		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
 	}
 
-	moxa_close_port(ch);
+	moxa_close_port(tty);
 unlock:
 	mutex_unlock(&moxa_openlock);
 }
@@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty,
 		return 0;
 
 	spin_lock_bh(&moxa_lock);
-	len = MoxaPortWriteData(ch, buf, count);
+	len = MoxaPortWriteData(tty, buf, count);
 	spin_unlock_bh(&moxa_lock);
 
 	ch->statusflags |= LOWWAIT;
@@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty)
 		return;
 	}
 	ch->port.count = 0;
-	moxa_close_port(ch);
+	moxa_close_port(tty);
 	mutex_unlock(&moxa_openlock);
 
 	wake_up_interruptible(&ch->port.open_wait);
@@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty)
 
 static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 {
+	struct tty_struct *tty;
 	dcd = !!dcd;
 
-	if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
-		if (!dcd)
-			tty_hangup(p->port.tty);
+	if (dcd != p->DCDState) {
+		tty = tty_port_tty_get(&p->port);
+		if (tty && C_CLOCAL(tty) && !dcd)
+			tty_hangup(tty);
+		tty_kref_put(tty);
 	}
 	p->DCDState = dcd;
 }
@@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
 static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 		u16 __iomem *ip)
 {
-	struct tty_struct *tty = p->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&p->port);
 	void __iomem *ofsAddr;
 	unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
 	u16 intr;
@@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
 		tty_insert_flip_char(tty, 0, TTY_BREAK);
 		tty_schedule_flip(tty);
 	}
+	tty_kref_put(tty);
 
 	if (intr & IntrLine)
 		moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
@@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
 	spin_unlock_bh(&moxa_lock);
 }
 
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
 {
-	struct tty_struct *tp = ch->port.tty;
+	struct moxa_port *ch = tty->driver_data;
 
 	if (!(ch->port.flags & ASYNC_INITIALIZED))
 		return;
@@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch)
 	/*
 	 * If we're a modem control device and HUPCL is on, drop RTS & DTR.
 	 */
-	if (C_HUPCL(tp))
+	if (C_HUPCL(tty))
 		MoxaPortLineCtrl(ch, 0, 0);
 
 	spin_lock_bh(&moxa_lock);
@@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
 	return val;
 }
 
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
 		const unsigned char *buffer, int len)
 {
+	struct moxa_port *port = tty->driver_data;
 	void __iomem *baseAddr, *ofsAddr, *ofs;
 	unsigned int c, total;
 	u16 head, tail, tx_mask, spage, epage;

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists