summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGaurav Kohli <gkohli@codeaurora.org>2018-01-23 02:46:34 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-01-23 02:57:37 -0500
commitb027e2298bd588d6fa36ed2eda97447fb3eac078 (patch)
tree3b90cee88ac74c2828b90b67d67cf7adf6e9e310
parent09df0b3464e528c6a4ca2c48d9ff6d2fd7cbd775 (diff)
tty: fix data race between tty_init_dev and flush of buf
There can be a race, if receive_buf call comes before tty initialization completes in n_tty_open and tty->disc_data may be NULL. CPU0 CPU1 ---- ---- 000|n_tty_receive_buf_common() n_tty_open() -001|n_tty_receive_buf2() tty_ldisc_open.isra.3() -002|tty_ldisc_receive_buf(inline) tty_ldisc_setup() Using ldisc semaphore lock in tty_init_dev till disc_data initializes completely. Signed-off-by: Gaurav Kohli <gkohli@codeaurora.org> Reviewed-by: Alan Cox <alan@linux.intel.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/tty_io.c8
-rw-r--r--drivers/tty/tty_ldisc.c4
-rw-r--r--include/linux/tty.h2
3 files changed, 11 insertions, 3 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index a6ca634411e1..688bd25aa6b0 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1323,6 +1323,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
1323 "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", 1323 "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
1324 __func__, tty->driver->name); 1324 __func__, tty->driver->name);
1325 1325
1326 retval = tty_ldisc_lock(tty, 5 * HZ);
1327 if (retval)
1328 goto err_release_lock;
1326 tty->port->itty = tty; 1329 tty->port->itty = tty;
1327 1330
1328 /* 1331 /*
@@ -1333,6 +1336,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
1333 retval = tty_ldisc_setup(tty, tty->link); 1336 retval = tty_ldisc_setup(tty, tty->link);
1334 if (retval) 1337 if (retval)
1335 goto err_release_tty; 1338 goto err_release_tty;
1339 tty_ldisc_unlock(tty);
1336 /* Return the tty locked so that it cannot vanish under the caller */ 1340 /* Return the tty locked so that it cannot vanish under the caller */
1337 return tty; 1341 return tty;
1338 1342
@@ -1345,9 +1349,11 @@ err_module_put:
1345 1349
1346 /* call the tty release_tty routine to clean out this slot */ 1350 /* call the tty release_tty routine to clean out this slot */
1347err_release_tty: 1351err_release_tty:
1348 tty_unlock(tty); 1352 tty_ldisc_unlock(tty);
1349 tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n", 1353 tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n",
1350 retval, idx); 1354 retval, idx);
1355err_release_lock:
1356 tty_unlock(tty);
1351 release_tty(tty, idx); 1357 release_tty(tty, idx);
1352 return ERR_PTR(retval); 1358 return ERR_PTR(retval);
1353} 1359}
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 24ec5c7e6b20..4e7946c0484b 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -337,7 +337,7 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty)
337 ldsem_up_write(&tty->ldisc_sem); 337 ldsem_up_write(&tty->ldisc_sem);
338} 338}
339 339
340static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) 340int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
341{ 341{
342 int ret; 342 int ret;
343 343
@@ -348,7 +348,7 @@ static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
348 return 0; 348 return 0;
349} 349}
350 350
351static void tty_ldisc_unlock(struct tty_struct *tty) 351void tty_ldisc_unlock(struct tty_struct *tty)
352{ 352{
353 clear_bit(TTY_LDISC_HALTED, &tty->flags); 353 clear_bit(TTY_LDISC_HALTED, &tty->flags);
354 __tty_ldisc_unlock(tty); 354 __tty_ldisc_unlock(tty);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 7ac8ba208b1f..0a6c71e0ad01 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -405,6 +405,8 @@ extern const char *tty_name(const struct tty_struct *tty);
405extern struct tty_struct *tty_kopen(dev_t device); 405extern struct tty_struct *tty_kopen(dev_t device);
406extern void tty_kclose(struct tty_struct *tty); 406extern void tty_kclose(struct tty_struct *tty);
407extern int tty_dev_name_to_number(const char *name, dev_t *number); 407extern int tty_dev_name_to_number(const char *name, dev_t *number);
408extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout);
409extern void tty_ldisc_unlock(struct tty_struct *tty);
408#else 410#else
409static inline void tty_kref_put(struct tty_struct *tty) 411static inline void tty_kref_put(struct tty_struct *tty)
410{ } 412{ }