summaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_tty.c
diff options
context:
space:
mode:
authorPeter Hurley2013-03-06 14:38:20 +0100
committerGreg Kroah-Hartman2013-03-19 00:13:59 +0100
commit01a5e440c91dc6065cf3dbc38aa7276fc4ce2f26 (patch)
tree681cd21901b56dca6046fbc9516bb74221fa8b7a /drivers/tty/n_tty.c
parentn_tty: Fix unsafe driver-side signals (diff)
downloadkernel-qcow2-linux-01a5e440c91dc6065cf3dbc38aa7276fc4ce2f26.tar.gz
kernel-qcow2-linux-01a5e440c91dc6065cf3dbc38aa7276fc4ce2f26.tar.xz
kernel-qcow2-linux-01a5e440c91dc6065cf3dbc38aa7276fc4ce2f26.zip
n_tty: Lock access to tty->pgrp for POSIX job control
Concurrent access to tty->pgrp must be protected with tty->ctrl_lock. Also, as noted in the comments, reading current->signal->tty is safe because either, 1) current->signal->tty is assigned by current, or 2) current->signal->tty is set to NULL. NB: for reference, tty_check_change() implements a similar POSIX check for the ioctls corresponding to tcflush(), tcdrain(), tcsetattr(), tcsetpgrp(), tcflow() and tcsendbreak(). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r--drivers/tty/n_tty.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 61f1bc97ccd9..68865d9af8a0 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1719,10 +1719,9 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
*
- * FIXME:
- * Locking: None - redirected write test is safe, testing
- * current->signal should possibly lock current->sighand
- * pgrp locking ?
+ * Locking: redirected write test is safe
+ * current->signal->tty check is safe
+ * ctrl_lock to safely reference tty->pgrp
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -1732,19 +1731,22 @@ static int job_control(struct tty_struct *tty, struct file *file)
/* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */
/* don't stop on /dev/console */
- if (file->f_op->write != redirected_tty_write &&
- current->signal->tty == tty) {
- if (!tty->pgrp)
- printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
- else if (task_pgrp(current) != tty->pgrp) {
- if (is_ignored(SIGTTIN) ||
- is_current_pgrp_orphaned())
- return -EIO;
- kill_pgrp(task_pgrp(current), SIGTTIN, 1);
- set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
- }
+ if (file->f_op->write == redirected_tty_write ||
+ current->signal->tty != tty)
+ return 0;
+
+ spin_lock_irq(&tty->ctrl_lock);
+ if (!tty->pgrp)
+ printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+ else if (task_pgrp(current) != tty->pgrp) {
+ spin_unlock_irq(&tty->ctrl_lock);
+ if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
+ return -EIO;
+ kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+ set_thread_flag(TIF_SIGPENDING);
+ return -ERESTARTSYS;
}
+ spin_unlock_irq(&tty->ctrl_lock);
return 0;
}