Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Jan 2017 16:37:38 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r312077 - in head/sys: kern sys
Message-ID:  <201701131637.v0DGbcrX051790@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Fri Jan 13 16:37:38 2017
New Revision: 312077
URL: https://svnweb.freebsd.org/changeset/base/312077

Log:
  Check tty_gone() after allocating IO buffers.  The tty lock has to be
  dropped then reacquired due to using M_WAITOK, which opens a window in
  which the tty device can disappear.  Check for this and return ENXIO
  back up the call chain so that callers can cope.
  
  This closes a race where TF_GONE would get set while buffers were being
  allocated as part of ttydev_open(), causing a subsequent call to
  ttydevsw_modem() later in ttydev_open() to assert.
  
  Reported by:	pho
  Reviewed by:	kib

Modified:
  head/sys/kern/tty.c
  head/sys/kern/tty_inq.c
  head/sys/kern/tty_outq.c
  head/sys/sys/ttyqueue.h

Modified: head/sys/kern/tty.c
==============================================================================
--- head/sys/kern/tty.c	Fri Jan 13 15:17:25 2017	(r312076)
+++ head/sys/kern/tty.c	Fri Jan 13 16:37:38 2017	(r312077)
@@ -105,25 +105,38 @@ SYSCTL_INT(_kern, OID_AUTO, tty_drainwai
 
 #define	TTYBUF_MAX	65536
 
-static void
+/*
+ * Allocate buffer space if necessary, and set low watermarks, based on speed.
+ * Note that the ttyxxxq_setsize() functions may drop and then reacquire the tty
+ * lock during memory allocation.  They will return ENXIO if the tty disappears
+ * while unlocked.
+ */
+static int
 tty_watermarks(struct tty *tp)
 {
 	size_t bs = 0;
+	int error;
 
 	/* Provide an input buffer for 0.2 seconds of data. */
 	if (tp->t_termios.c_cflag & CREAD)
 		bs = MIN(tp->t_termios.c_ispeed / 5, TTYBUF_MAX);
-	ttyinq_setsize(&tp->t_inq, tp, bs);
+	error = ttyinq_setsize(&tp->t_inq, tp, bs);
+	if (error != 0)
+		return (error);
 
 	/* Set low watermark at 10% (when 90% is available). */
 	tp->t_inlow = (ttyinq_getallocatedsize(&tp->t_inq) * 9) / 10;
 
 	/* Provide an output buffer for 0.2 seconds of data. */
 	bs = MIN(tp->t_termios.c_ospeed / 5, TTYBUF_MAX);
-	ttyoutq_setsize(&tp->t_outq, tp, bs);
+	error = ttyoutq_setsize(&tp->t_outq, tp, bs);
+	if (error != 0)
+		return (error);
 
 	/* Set low watermark at 10% (when 90% is available). */
 	tp->t_outlow = (ttyoutq_getallocatedsize(&tp->t_outq) * 9) / 10;
+
+	return (0);
 }
 
 static int
@@ -318,7 +331,9 @@ ttydev_open(struct cdev *dev, int oflags
 			goto done;
 
 		ttydisc_open(tp);
-		tty_watermarks(tp); /* XXXGL: drops lock */
+		error = tty_watermarks(tp);
+		if (error != 0)
+			goto done;
 	}
 
 	/* Wait for Carrier Detect. */
@@ -1627,7 +1642,9 @@ tty_generic_ioctl(struct tty *tp, u_long
 			tp->t_termios.c_ospeed = t->c_ospeed;
 
 			/* Baud rate has changed - update watermarks. */
-			tty_watermarks(tp);
+			error = tty_watermarks(tp);
+			if (error)
+				return (error);
 		}
 
 		/* Copy new non-device driver parameters. */

Modified: head/sys/kern/tty_inq.c
==============================================================================
--- head/sys/kern/tty_inq.c	Fri Jan 13 15:17:25 2017	(r312076)
+++ head/sys/kern/tty_inq.c	Fri Jan 13 16:37:38 2017	(r312077)
@@ -112,7 +112,7 @@ static uma_zone_t ttyinq_zone;
 		TTYINQ_INSERT_TAIL(ti, tib);				\
 } while (0)
 
-void
+int 
 ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
 {
 	struct ttyinq_block *tib;
@@ -134,8 +134,14 @@ ttyinq_setsize(struct ttyinq *ti, struct
 		tib = uma_zalloc(ttyinq_zone, M_WAITOK);
 		tty_lock(tp);
 
+		if (tty_gone(tp)) {
+			uma_zfree(ttyinq_zone, tib);
+			return (ENXIO);
+		}
+
 		TTYINQ_INSERT_TAIL(ti, tib);
 	}
+	return (0);
 }
 
 void

Modified: head/sys/kern/tty_outq.c
==============================================================================
--- head/sys/kern/tty_outq.c	Fri Jan 13 15:17:25 2017	(r312076)
+++ head/sys/kern/tty_outq.c	Fri Jan 13 16:37:38 2017	(r312077)
@@ -89,7 +89,7 @@ ttyoutq_flush(struct ttyoutq *to)
 	to->to_end = 0;
 }
 
-void
+int
 ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
 {
 	struct ttyoutq_block *tob;
@@ -111,8 +111,14 @@ ttyoutq_setsize(struct ttyoutq *to, stru
 		tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
 		tty_lock(tp);
 
+		if (tty_gone(tp)) {
+			uma_zfree(ttyoutq_zone, tob);
+			return (ENXIO);
+		}
+
 		TTYOUTQ_INSERT_TAIL(to, tob);
 	}
+	return (0);
 }
 
 void

Modified: head/sys/sys/ttyqueue.h
==============================================================================
--- head/sys/sys/ttyqueue.h	Fri Jan 13 15:17:25 2017	(r312076)
+++ head/sys/sys/ttyqueue.h	Fri Jan 13 16:37:38 2017	(r312077)
@@ -69,7 +69,7 @@ struct ttyoutq {
 
 #ifdef _KERNEL
 /* Input queue handling routines. */
-void	ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t len);
+int	ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t len);
 void	ttyinq_free(struct ttyinq *ti);
 int	ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio,
     size_t readlen, size_t flushlen);
@@ -136,7 +136,7 @@ void	ttyinq_line_iterate_from_reprintpos
 
 /* Output queue handling routines. */
 void	ttyoutq_flush(struct ttyoutq *to);
-void	ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t len);
+int	ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t len);
 void	ttyoutq_free(struct ttyoutq *to);
 size_t	ttyoutq_read(struct ttyoutq *to, void *buf, size_t len);
 int	ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201701131637.v0DGbcrX051790>