aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2008-04-30 03:53:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 11:29:40 -0400
commit47f86834bbd4193139d61d659bebf9ab9d691e37 (patch)
tree6724b07e24929eba5c6df31f07871d9d6b4aa296
parent04f378b198da233ca0aca341b113dc6579d46123 (diff)
redo locking of tty->pgrp
Historically tty->pgrp and friends were pid_t and the code "knew" they were safe. The change to pid structs opened up a few races and the removal of the BKL in places made them quite hittable. We put tty->pgrp under the ctrl_lock for the tty. Signed-off-by: Alan Cox <alan@redhat.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/tty_io.c78
-rw-r--r--drivers/char/vt.c6
-rw-r--r--include/linux/tty.h10
3 files changed, 72 insertions, 22 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 0b0354bc28d6..c8aa318eaa18 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1204,26 +1204,37 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
1204 * not in the foreground, send a SIGTTOU. If the signal is blocked or 1204 * not in the foreground, send a SIGTTOU. If the signal is blocked or
1205 * ignored, go ahead and perform the operation. (POSIX 7.2) 1205 * ignored, go ahead and perform the operation. (POSIX 7.2)
1206 * 1206 *
1207 * Locking: none - FIXME: review this 1207 * Locking: ctrl_lock - FIXME: review this
1208 */ 1208 */
1209 1209
1210int tty_check_change(struct tty_struct *tty) 1210int tty_check_change(struct tty_struct *tty)
1211{ 1211{
1212 unsigned long flags;
1213 int ret = 0;
1214
1212 if (current->signal->tty != tty) 1215 if (current->signal->tty != tty)
1213 return 0; 1216 return 0;
1217
1218 spin_lock_irqsave(&tty->ctrl_lock, flags);
1219
1214 if (!tty->pgrp) { 1220 if (!tty->pgrp) {
1215 printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); 1221 printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
1216 return 0; 1222 goto out;
1217 } 1223 }
1218 if (task_pgrp(current) == tty->pgrp) 1224 if (task_pgrp(current) == tty->pgrp)
1219 return 0; 1225 goto out;
1220 if (is_ignored(SIGTTOU)) 1226 if (is_ignored(SIGTTOU))
1221 return 0; 1227 goto out;
1222 if (is_current_pgrp_orphaned()) 1228 if (is_current_pgrp_orphaned()) {
1223 return -EIO; 1229 ret = -EIO;
1230 goto out;
1231 }
1224 kill_pgrp(task_pgrp(current), SIGTTOU, 1); 1232 kill_pgrp(task_pgrp(current), SIGTTOU, 1);
1225 set_thread_flag(TIF_SIGPENDING); 1233 set_thread_flag(TIF_SIGPENDING);
1226 return -ERESTARTSYS; 1234 ret = -ERESTARTSYS;
1235out:
1236 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
1237 return ret;
1227} 1238}
1228 1239
1229EXPORT_SYMBOL(tty_check_change); 1240EXPORT_SYMBOL(tty_check_change);
@@ -1403,6 +1414,7 @@ static void do_tty_hangup(struct work_struct *work)
1403 struct task_struct *p; 1414 struct task_struct *p;
1404 struct tty_ldisc *ld; 1415 struct tty_ldisc *ld;
1405 int closecount = 0, n; 1416 int closecount = 0, n;
1417 unsigned long flags;
1406 1418
1407 if (!tty) 1419 if (!tty)
1408 return; 1420 return;
@@ -1479,19 +1491,24 @@ static void do_tty_hangup(struct work_struct *work)
1479 __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); 1491 __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
1480 __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); 1492 __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
1481 put_pid(p->signal->tty_old_pgrp); /* A noop */ 1493 put_pid(p->signal->tty_old_pgrp); /* A noop */
1494 spin_lock_irqsave(&tty->ctrl_lock, flags);
1482 if (tty->pgrp) 1495 if (tty->pgrp)
1483 p->signal->tty_old_pgrp = get_pid(tty->pgrp); 1496 p->signal->tty_old_pgrp = get_pid(tty->pgrp);
1497 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
1484 spin_unlock_irq(&p->sighand->siglock); 1498 spin_unlock_irq(&p->sighand->siglock);
1485 } while_each_pid_task(tty->session, PIDTYPE_SID, p); 1499 } while_each_pid_task(tty->session, PIDTYPE_SID, p);
1486 } 1500 }
1487 read_unlock(&tasklist_lock); 1501 read_unlock(&tasklist_lock);
1488 1502
1503 spin_lock_irqsave(&tty->ctrl_lock, flags);
1489 tty->flags = 0; 1504 tty->flags = 0;
1490 put_pid(tty->session); 1505 put_pid(tty->session);
1491 put_pid(tty->pgrp); 1506 put_pid(tty->pgrp);
1492 tty->session = NULL; 1507 tty->session = NULL;
1493 tty->pgrp = NULL; 1508 tty->pgrp = NULL;
1494 tty->ctrl_status = 0; 1509 tty->ctrl_status = 0;
1510 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
1511
1495 /* 1512 /*
1496 * If one of the devices matches a console pointer, we 1513 * If one of the devices matches a console pointer, we
1497 * cannot just call hangup() because that will cause 1514 * cannot just call hangup() because that will cause
@@ -1666,10 +1683,13 @@ void disassociate_ctty(int on_exit)
1666 /* It is possible that do_tty_hangup has free'd this tty */ 1683 /* It is possible that do_tty_hangup has free'd this tty */
1667 tty = get_current_tty(); 1684 tty = get_current_tty();
1668 if (tty) { 1685 if (tty) {
1686 unsigned long flags;
1687 spin_lock_irqsave(&tty->ctrl_lock, flags);
1669 put_pid(tty->session); 1688 put_pid(tty->session);
1670 put_pid(tty->pgrp); 1689 put_pid(tty->pgrp);
1671 tty->session = NULL; 1690 tty->session = NULL;
1672 tty->pgrp = NULL; 1691 tty->pgrp = NULL;
1692 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
1673 } else { 1693 } else {
1674#ifdef TTY_DEBUG_HANGUP 1694#ifdef TTY_DEBUG_HANGUP
1675 printk(KERN_DEBUG "error attempted to write to tty [0x%p]" 1695 printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1785,10 +1805,8 @@ EXPORT_SYMBOL(start_tty);
1785 * for hung up devices before calling the line discipline method. 1805 * for hung up devices before calling the line discipline method.
1786 * 1806 *
1787 * Locking: 1807 * Locking:
1788 * Locks the line discipline internally while needed 1808 * Locks the line discipline internally while needed. Multiple
1789 * For historical reasons the line discipline read method is 1809 * read calls may be outstanding in parallel.
1790 * invoked under the BKL. This will go away in time so do not rely on it
1791 * in new code. Multiple read calls may be outstanding in parallel.
1792 */ 1810 */
1793 1811
1794static ssize_t tty_read(struct file *file, char __user *buf, size_t count, 1812static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
@@ -2888,6 +2906,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
2888static int tty_fasync(int fd, struct file *filp, int on) 2906static int tty_fasync(int fd, struct file *filp, int on)
2889{ 2907{
2890 struct tty_struct *tty; 2908 struct tty_struct *tty;
2909 unsigned long flags;
2891 int retval; 2910 int retval;
2892 2911
2893 tty = (struct tty_struct *)filp->private_data; 2912 tty = (struct tty_struct *)filp->private_data;
@@ -2903,6 +2922,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
2903 struct pid *pid; 2922 struct pid *pid;
2904 if (!waitqueue_active(&tty->read_wait)) 2923 if (!waitqueue_active(&tty->read_wait))
2905 tty->minimum_to_wake = 1; 2924 tty->minimum_to_wake = 1;
2925 spin_lock_irqsave(&tty->ctrl_lock, flags);
2906 if (tty->pgrp) { 2926 if (tty->pgrp) {
2907 pid = tty->pgrp; 2927 pid = tty->pgrp;
2908 type = PIDTYPE_PGID; 2928 type = PIDTYPE_PGID;
@@ -2910,6 +2930,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
2910 pid = task_pid(current); 2930 pid = task_pid(current);
2911 type = PIDTYPE_PID; 2931 type = PIDTYPE_PID;
2912 } 2932 }
2933 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
2913 retval = __f_setown(filp, pid, type, 0); 2934 retval = __f_setown(filp, pid, type, 0);
2914 if (retval) 2935 if (retval)
2915 return retval; 2936 return retval;
@@ -2995,6 +3016,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
2995 struct winsize __user *arg) 3016 struct winsize __user *arg)
2996{ 3017{
2997 struct winsize tmp_ws; 3018 struct winsize tmp_ws;
3019 struct pid *pgrp, *rpgrp;
3020 unsigned long flags;
2998 3021
2999 if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) 3022 if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
3000 return -EFAULT; 3023 return -EFAULT;
@@ -3012,10 +3035,21 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
3012 } 3035 }
3013 } 3036 }
3014#endif 3037#endif
3015 if (tty->pgrp) 3038 /* Get the PID values and reference them so we can
3016 kill_pgrp(tty->pgrp, SIGWINCH, 1); 3039 avoid holding the tty ctrl lock while sending signals */
3017 if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp) 3040 spin_lock_irqsave(&tty->ctrl_lock, flags);
3018 kill_pgrp(real_tty->pgrp, SIGWINCH, 1); 3041 pgrp = get_pid(tty->pgrp);
3042 rpgrp = get_pid(real_tty->pgrp);
3043 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
3044
3045 if (pgrp)
3046 kill_pgrp(pgrp, SIGWINCH, 1);
3047 if (rpgrp != pgrp && rpgrp)
3048 kill_pgrp(rpgrp, SIGWINCH, 1);
3049
3050 put_pid(pgrp);
3051 put_pid(rpgrp);
3052
3019 tty->winsize = tmp_ws; 3053 tty->winsize = tmp_ws;
3020 real_tty->winsize = tmp_ws; 3054 real_tty->winsize = tmp_ws;
3021done: 3055done:
@@ -3171,7 +3205,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
3171 * Set the process group of the tty to the session passed. Only 3205 * Set the process group of the tty to the session passed. Only
3172 * permitted where the tty session is our session. 3206 * permitted where the tty session is our session.
3173 * 3207 *
3174 * Locking: RCU 3208 * Locking: RCU, ctrl lock
3175 */ 3209 */
3176 3210
3177static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) 3211static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3179,6 +3213,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
3179 struct pid *pgrp; 3213 struct pid *pgrp;
3180 pid_t pgrp_nr; 3214 pid_t pgrp_nr;
3181 int retval = tty_check_change(real_tty); 3215 int retval = tty_check_change(real_tty);
3216 unsigned long flags;
3182 3217
3183 if (retval == -EIO) 3218 if (retval == -EIO)
3184 return -ENOTTY; 3219 return -ENOTTY;
@@ -3201,8 +3236,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
3201 if (session_of_pgrp(pgrp) != task_session(current)) 3236 if (session_of_pgrp(pgrp) != task_session(current))
3202 goto out_unlock; 3237 goto out_unlock;
3203 retval = 0; 3238 retval = 0;
3239 spin_lock_irqsave(&tty->ctrl_lock, flags);
3204 put_pid(real_tty->pgrp); 3240 put_pid(real_tty->pgrp);
3205 real_tty->pgrp = get_pid(pgrp); 3241 real_tty->pgrp = get_pid(pgrp);
3242 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
3206out_unlock: 3243out_unlock:
3207 rcu_read_unlock(); 3244 rcu_read_unlock();
3208 return retval; 3245 return retval;
@@ -4077,14 +4114,19 @@ void proc_clear_tty(struct task_struct *p)
4077} 4114}
4078EXPORT_SYMBOL(proc_clear_tty); 4115EXPORT_SYMBOL(proc_clear_tty);
4079 4116
4117/* Called under the sighand lock */
4118
4080static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) 4119static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
4081{ 4120{
4082 if (tty) { 4121 if (tty) {
4083 /* We should not have a session or pgrp to here but.... */ 4122 unsigned long flags;
4123 /* We should not have a session or pgrp to put here but.... */
4124 spin_lock_irqsave(&tty->ctrl_lock, flags);
4084 put_pid(tty->session); 4125 put_pid(tty->session);
4085 put_pid(tty->pgrp); 4126 put_pid(tty->pgrp);
4086 tty->session = get_pid(task_session(tsk));
4087 tty->pgrp = get_pid(task_pgrp(tsk)); 4127 tty->pgrp = get_pid(task_pgrp(tsk));
4128 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
4129 tty->session = get_pid(task_session(tsk));
4088 } 4130 }
4089 put_pid(tsk->signal->tty_old_pgrp); 4131 put_pid(tsk->signal->tty_old_pgrp);
4090 tsk->signal->tty = tty; 4132 tsk->signal->tty = tty;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index e64f0bf3624e..c71d1d0f13b9 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -909,15 +909,21 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
909 909
910 if (vc->vc_tty) { 910 if (vc->vc_tty) {
911 struct winsize ws, *cws = &vc->vc_tty->winsize; 911 struct winsize ws, *cws = &vc->vc_tty->winsize;
912 unsigned long flags;
912 913
913 memset(&ws, 0, sizeof(ws)); 914 memset(&ws, 0, sizeof(ws));
914 ws.ws_row = vc->vc_rows; 915 ws.ws_row = vc->vc_rows;
915 ws.ws_col = vc->vc_cols; 916 ws.ws_col = vc->vc_cols;
916 ws.ws_ypixel = vc->vc_scan_lines; 917 ws.ws_ypixel = vc->vc_scan_lines;
918
919 mutex_lock(&vc->vc_tty->termios_mutex);
920 spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags);
917 if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && 921 if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
918 vc->vc_tty->pgrp) 922 vc->vc_tty->pgrp)
919 kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); 923 kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
924 spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags);
920 *cws = ws; 925 *cws = ws;
926 mutex_unlock(&vc->vc_tty->termios_mutex);
921 } 927 }
922 928
923 if (CON_IS_VISIBLE(vc)) 929 if (CON_IS_VISIBLE(vc))
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 4d3702bade03..381085e45cca 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -184,21 +184,22 @@ struct tty_struct {
184 struct tty_ldisc ldisc; 184 struct tty_ldisc ldisc;
185 struct mutex termios_mutex; 185 struct mutex termios_mutex;
186 spinlock_t ctrl_lock; 186 spinlock_t ctrl_lock;
187 /* Termios values are protected by the termios mutex */
187 struct ktermios *termios, *termios_locked; 188 struct ktermios *termios, *termios_locked;
188 char name[64]; 189 char name[64];
189 struct pid *pgrp; 190 struct pid *pgrp; /* Protected by ctrl lock */
190 struct pid *session; 191 struct pid *session;
191 unsigned long flags; 192 unsigned long flags;
192 int count; 193 int count;
193 struct winsize winsize; 194 struct winsize winsize; /* termios mutex */
194 unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; 195 unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
195 unsigned char low_latency:1, warned:1; 196 unsigned char low_latency:1, warned:1;
196 unsigned char ctrl_status; 197 unsigned char ctrl_status; /* ctrl_lock */
197 unsigned int receive_room; /* Bytes free for queue */ 198 unsigned int receive_room; /* Bytes free for queue */
198 199
199 struct tty_struct *link; 200 struct tty_struct *link;
200 struct fasync_struct *fasync; 201 struct fasync_struct *fasync;
201 struct tty_bufhead buf; 202 struct tty_bufhead buf; /* Locked internally */
202 int alt_speed; /* For magic substitution of 38400 bps */ 203 int alt_speed; /* For magic substitution of 38400 bps */
203 wait_queue_head_t write_wait; 204 wait_queue_head_t write_wait;
204 wait_queue_head_t read_wait; 205 wait_queue_head_t read_wait;
@@ -212,6 +213,7 @@ struct tty_struct {
212 /* 213 /*
213 * The following is data for the N_TTY line discipline. For 214 * The following is data for the N_TTY line discipline. For
214 * historical reasons, this is included in the tty structure. 215 * historical reasons, this is included in the tty structure.
216 * Mostly locked by the BKL.
215 */ 217 */
216 unsigned int column; 218 unsigned int column;
217 unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; 219 unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;