diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2006-12-08 05:36:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:28:38 -0500 |
commit | 24ec839c431eb79bb8f6abc00c4e1eb3b8c4d517 (patch) | |
tree | 2ff478b1925159eeac007913c2a8f19d5f5e6010 /drivers/char | |
parent | 562f9c574e0707f9159a729ea41faf53b221cd30 (diff) |
[PATCH] tty: ->signal->tty locking
Fix the locking of signal->tty.
Use ->sighand->siglock to protect ->signal->tty; this lock is already used
by most other members of ->signal/->sighand. And unless we are 'current'
or the tasklist_lock is held we need ->siglock to access ->signal anyway.
(NOTE: sys_unshare() is broken wrt ->sighand locking rules)
Note that tty_mutex is held over tty destruction, so while holding
tty_mutex any tty pointer remains valid. Otherwise the lifetime of ttys
are governed by their open file handles. This leaves some holes for tty
access from signal->tty (or any other non file related tty access).
It solves the tty SLAB scribbles we were seeing.
(NOTE: the change from group_send_sig_info to __group_send_sig_info needs to
be examined by someone familiar with the security framework, I think
it is safe given the SEND_SIG_PRIV from other __group_send_sig_info
invocations)
[schwidefsky@de.ibm.com: 3270 fix]
[akpm@osdl.org: various post-viro fixes]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Alan Cox <alan@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: Roland McGrath <roland@redhat.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: James Morris <jmorris@namei.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Jan Kara <jack@ucw.cz>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/tty_io.c | 237 |
1 files changed, 141 insertions, 96 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index b3cfc8bc613c..0c856a6f3677 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(tty_std_termios); | |||
126 | 126 | ||
127 | LIST_HEAD(tty_drivers); /* linked list of tty drivers */ | 127 | LIST_HEAD(tty_drivers); /* linked list of tty drivers */ |
128 | 128 | ||
129 | /* Semaphore to protect creating and releasing a tty. This is shared with | 129 | /* Mutex to protect creating and releasing a tty. This is shared with |
130 | vt.c for deeply disgusting hack reasons */ | 130 | vt.c for deeply disgusting hack reasons */ |
131 | DEFINE_MUTEX(tty_mutex); | 131 | DEFINE_MUTEX(tty_mutex); |
132 | EXPORT_SYMBOL(tty_mutex); | 132 | EXPORT_SYMBOL(tty_mutex); |
@@ -250,7 +250,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) | |||
250 | "!= #fd's(%d) in %s\n", | 250 | "!= #fd's(%d) in %s\n", |
251 | tty->name, tty->count, count, routine); | 251 | tty->name, tty->count, count, routine); |
252 | return count; | 252 | return count; |
253 | } | 253 | } |
254 | #endif | 254 | #endif |
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
@@ -259,18 +259,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) | |||
259 | * Tty buffer allocation management | 259 | * Tty buffer allocation management |
260 | */ | 260 | */ |
261 | 261 | ||
262 | |||
263 | /** | ||
264 | * tty_buffer_free_all - free buffers used by a tty | ||
265 | * @tty: tty to free from | ||
266 | * | ||
267 | * Remove all the buffers pending on a tty whether queued with data | ||
268 | * or in the free ring. Must be called when the tty is no longer in use | ||
269 | * | ||
270 | * Locking: none | ||
271 | */ | ||
272 | |||
273 | |||
274 | /** | 262 | /** |
275 | * tty_buffer_free_all - free buffers used by a tty | 263 | * tty_buffer_free_all - free buffers used by a tty |
276 | * @tty: tty to free from | 264 | * @tty: tty to free from |
@@ -614,7 +602,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | |||
614 | * they are not on hot paths so a little discipline won't do | 602 | * they are not on hot paths so a little discipline won't do |
615 | * any harm. | 603 | * any harm. |
616 | * | 604 | * |
617 | * Locking: takes termios_sem | 605 | * Locking: takes termios_mutex |
618 | */ | 606 | */ |
619 | 607 | ||
620 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | 608 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) |
@@ -915,7 +903,7 @@ static void tty_ldisc_enable(struct tty_struct *tty) | |||
915 | * context. | 903 | * context. |
916 | * | 904 | * |
917 | * Locking: takes tty_ldisc_lock. | 905 | * Locking: takes tty_ldisc_lock. |
918 | * called functions take termios_sem | 906 | * called functions take termios_mutex |
919 | */ | 907 | */ |
920 | 908 | ||
921 | static int tty_set_ldisc(struct tty_struct *tty, int ldisc) | 909 | static int tty_set_ldisc(struct tty_struct *tty, int ldisc) |
@@ -1267,12 +1255,12 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); | |||
1267 | * | 1255 | * |
1268 | * Locking: | 1256 | * Locking: |
1269 | * BKL | 1257 | * BKL |
1270 | * redirect lock for undoing redirection | 1258 | * redirect lock for undoing redirection |
1271 | * file list lock for manipulating list of ttys | 1259 | * file list lock for manipulating list of ttys |
1272 | * tty_ldisc_lock from called functions | 1260 | * tty_ldisc_lock from called functions |
1273 | * termios_sem resetting termios data | 1261 | * termios_mutex resetting termios data |
1274 | * tasklist_lock to walk task list for hangup event | 1262 | * tasklist_lock to walk task list for hangup event |
1275 | * | 1263 | * ->siglock to protect ->signal/->sighand |
1276 | */ | 1264 | */ |
1277 | static void do_tty_hangup(struct work_struct *work) | 1265 | static void do_tty_hangup(struct work_struct *work) |
1278 | { | 1266 | { |
@@ -1354,14 +1342,18 @@ static void do_tty_hangup(struct work_struct *work) | |||
1354 | read_lock(&tasklist_lock); | 1342 | read_lock(&tasklist_lock); |
1355 | if (tty->session > 0) { | 1343 | if (tty->session > 0) { |
1356 | do_each_task_pid(tty->session, PIDTYPE_SID, p) { | 1344 | do_each_task_pid(tty->session, PIDTYPE_SID, p) { |
1345 | spin_lock_irq(&p->sighand->siglock); | ||
1357 | if (p->signal->tty == tty) | 1346 | if (p->signal->tty == tty) |
1358 | p->signal->tty = NULL; | 1347 | p->signal->tty = NULL; |
1359 | if (!p->signal->leader) | 1348 | if (!p->signal->leader) { |
1349 | spin_unlock_irq(&p->sighand->siglock); | ||
1360 | continue; | 1350 | continue; |
1361 | group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); | 1351 | } |
1362 | group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | 1352 | __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); |
1353 | __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | ||
1363 | if (tty->pgrp > 0) | 1354 | if (tty->pgrp > 0) |
1364 | p->signal->tty_old_pgrp = tty->pgrp; | 1355 | p->signal->tty_old_pgrp = tty->pgrp; |
1356 | spin_unlock_irq(&p->sighand->siglock); | ||
1365 | } while_each_task_pid(tty->session, PIDTYPE_SID, p); | 1357 | } while_each_task_pid(tty->session, PIDTYPE_SID, p); |
1366 | } | 1358 | } |
1367 | read_unlock(&tasklist_lock); | 1359 | read_unlock(&tasklist_lock); |
@@ -1453,6 +1445,14 @@ int tty_hung_up_p(struct file * filp) | |||
1453 | 1445 | ||
1454 | EXPORT_SYMBOL(tty_hung_up_p); | 1446 | EXPORT_SYMBOL(tty_hung_up_p); |
1455 | 1447 | ||
1448 | static void session_clear_tty(pid_t session) | ||
1449 | { | ||
1450 | struct task_struct *p; | ||
1451 | do_each_task_pid(session, PIDTYPE_SID, p) { | ||
1452 | proc_clear_tty(p); | ||
1453 | } while_each_task_pid(session, PIDTYPE_SID, p); | ||
1454 | } | ||
1455 | |||
1456 | /** | 1456 | /** |
1457 | * disassociate_ctty - disconnect controlling tty | 1457 | * disassociate_ctty - disconnect controlling tty |
1458 | * @on_exit: true if exiting so need to "hang up" the session | 1458 | * @on_exit: true if exiting so need to "hang up" the session |
@@ -1469,31 +1469,35 @@ EXPORT_SYMBOL(tty_hung_up_p); | |||
1469 | * The argument on_exit is set to 1 if called when a process is | 1469 | * The argument on_exit is set to 1 if called when a process is |
1470 | * exiting; it is 0 if called by the ioctl TIOCNOTTY. | 1470 | * exiting; it is 0 if called by the ioctl TIOCNOTTY. |
1471 | * | 1471 | * |
1472 | * Locking: tty_mutex is taken to protect current->signal->tty | 1472 | * Locking: |
1473 | * BKL is taken for hysterical raisins | 1473 | * BKL is taken for hysterical raisins |
1474 | * Tasklist lock is taken (under tty_mutex) to walk process | 1474 | * tty_mutex is taken to protect tty |
1475 | * lists for the session. | 1475 | * ->siglock is taken to protect ->signal/->sighand |
1476 | * tasklist_lock is taken to walk process list for sessions | ||
1477 | * ->siglock is taken to protect ->signal/->sighand | ||
1476 | */ | 1478 | */ |
1477 | 1479 | ||
1478 | void disassociate_ctty(int on_exit) | 1480 | void disassociate_ctty(int on_exit) |
1479 | { | 1481 | { |
1480 | struct tty_struct *tty; | 1482 | struct tty_struct *tty; |
1481 | struct task_struct *p; | ||
1482 | int tty_pgrp = -1; | 1483 | int tty_pgrp = -1; |
1484 | int session; | ||
1483 | 1485 | ||
1484 | lock_kernel(); | 1486 | lock_kernel(); |
1485 | 1487 | ||
1486 | mutex_lock(&tty_mutex); | 1488 | mutex_lock(&tty_mutex); |
1487 | tty = current->signal->tty; | 1489 | tty = get_current_tty(); |
1488 | if (tty) { | 1490 | if (tty) { |
1489 | tty_pgrp = tty->pgrp; | 1491 | tty_pgrp = tty->pgrp; |
1490 | mutex_unlock(&tty_mutex); | 1492 | mutex_unlock(&tty_mutex); |
1493 | /* XXX: here we race, there is nothing protecting tty */ | ||
1491 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) | 1494 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) |
1492 | tty_vhangup(tty); | 1495 | tty_vhangup(tty); |
1493 | } else { | 1496 | } else { |
1494 | if (current->signal->tty_old_pgrp) { | 1497 | pid_t old_pgrp = current->signal->tty_old_pgrp; |
1495 | kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); | 1498 | if (old_pgrp) { |
1496 | kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); | 1499 | kill_pg(old_pgrp, SIGHUP, on_exit); |
1500 | kill_pg(old_pgrp, SIGCONT, on_exit); | ||
1497 | } | 1501 | } |
1498 | mutex_unlock(&tty_mutex); | 1502 | mutex_unlock(&tty_mutex); |
1499 | unlock_kernel(); | 1503 | unlock_kernel(); |
@@ -1505,19 +1509,29 @@ void disassociate_ctty(int on_exit) | |||
1505 | kill_pg(tty_pgrp, SIGCONT, on_exit); | 1509 | kill_pg(tty_pgrp, SIGCONT, on_exit); |
1506 | } | 1510 | } |
1507 | 1511 | ||
1508 | /* Must lock changes to tty_old_pgrp */ | 1512 | spin_lock_irq(¤t->sighand->siglock); |
1509 | mutex_lock(&tty_mutex); | ||
1510 | current->signal->tty_old_pgrp = 0; | 1513 | current->signal->tty_old_pgrp = 0; |
1511 | tty->session = 0; | 1514 | session = current->signal->session; |
1512 | tty->pgrp = -1; | 1515 | spin_unlock_irq(¤t->sighand->siglock); |
1516 | |||
1517 | mutex_lock(&tty_mutex); | ||
1518 | /* It is possible that do_tty_hangup has free'd this tty */ | ||
1519 | tty = get_current_tty(); | ||
1520 | if (tty) { | ||
1521 | tty->session = 0; | ||
1522 | tty->pgrp = 0; | ||
1523 | } else { | ||
1524 | #ifdef TTY_DEBUG_HANGUP | ||
1525 | printk(KERN_DEBUG "error attempted to write to tty [0x%p]" | ||
1526 | " = NULL", tty); | ||
1527 | #endif | ||
1528 | } | ||
1529 | mutex_unlock(&tty_mutex); | ||
1513 | 1530 | ||
1514 | /* Now clear signal->tty under the lock */ | 1531 | /* Now clear signal->tty under the lock */ |
1515 | read_lock(&tasklist_lock); | 1532 | read_lock(&tasklist_lock); |
1516 | do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { | 1533 | session_clear_tty(session); |
1517 | p->signal->tty = NULL; | ||
1518 | } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); | ||
1519 | read_unlock(&tasklist_lock); | 1534 | read_unlock(&tasklist_lock); |
1520 | mutex_unlock(&tty_mutex); | ||
1521 | unlock_kernel(); | 1535 | unlock_kernel(); |
1522 | } | 1536 | } |
1523 | 1537 | ||
@@ -2337,16 +2351,10 @@ static void release_dev(struct file * filp) | |||
2337 | * tty. | 2351 | * tty. |
2338 | */ | 2352 | */ |
2339 | if (tty_closing || o_tty_closing) { | 2353 | if (tty_closing || o_tty_closing) { |
2340 | struct task_struct *p; | ||
2341 | |||
2342 | read_lock(&tasklist_lock); | 2354 | read_lock(&tasklist_lock); |
2343 | do_each_task_pid(tty->session, PIDTYPE_SID, p) { | 2355 | session_clear_tty(tty->session); |
2344 | p->signal->tty = NULL; | ||
2345 | } while_each_task_pid(tty->session, PIDTYPE_SID, p); | ||
2346 | if (o_tty) | 2356 | if (o_tty) |
2347 | do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { | 2357 | session_clear_tty(o_tty->session); |
2348 | p->signal->tty = NULL; | ||
2349 | } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); | ||
2350 | read_unlock(&tasklist_lock); | 2358 | read_unlock(&tasklist_lock); |
2351 | } | 2359 | } |
2352 | 2360 | ||
@@ -2443,9 +2451,9 @@ static void release_dev(struct file * filp) | |||
2443 | * The termios state of a pty is reset on first open so that | 2451 | * The termios state of a pty is reset on first open so that |
2444 | * settings don't persist across reuse. | 2452 | * settings don't persist across reuse. |
2445 | * | 2453 | * |
2446 | * Locking: tty_mutex protects current->signal->tty, get_tty_driver and | 2454 | * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. |
2447 | * init_dev work. tty->count should protect the rest. | 2455 | * tty->count should protect the rest. |
2448 | * task_lock is held to update task details for sessions | 2456 | * ->siglock protects ->signal/->sighand |
2449 | */ | 2457 | */ |
2450 | 2458 | ||
2451 | static int tty_open(struct inode * inode, struct file * filp) | 2459 | static int tty_open(struct inode * inode, struct file * filp) |
@@ -2467,12 +2475,13 @@ retry_open: | |||
2467 | mutex_lock(&tty_mutex); | 2475 | mutex_lock(&tty_mutex); |
2468 | 2476 | ||
2469 | if (device == MKDEV(TTYAUX_MAJOR,0)) { | 2477 | if (device == MKDEV(TTYAUX_MAJOR,0)) { |
2470 | if (!current->signal->tty) { | 2478 | tty = get_current_tty(); |
2479 | if (!tty) { | ||
2471 | mutex_unlock(&tty_mutex); | 2480 | mutex_unlock(&tty_mutex); |
2472 | return -ENXIO; | 2481 | return -ENXIO; |
2473 | } | 2482 | } |
2474 | driver = current->signal->tty->driver; | 2483 | driver = tty->driver; |
2475 | index = current->signal->tty->index; | 2484 | index = tty->index; |
2476 | filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ | 2485 | filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ |
2477 | /* noctty = 1; */ | 2486 | /* noctty = 1; */ |
2478 | goto got_driver; | 2487 | goto got_driver; |
@@ -2547,17 +2556,16 @@ got_driver: | |||
2547 | filp->f_op = &tty_fops; | 2556 | filp->f_op = &tty_fops; |
2548 | goto retry_open; | 2557 | goto retry_open; |
2549 | } | 2558 | } |
2559 | |||
2560 | mutex_lock(&tty_mutex); | ||
2561 | spin_lock_irq(¤t->sighand->siglock); | ||
2550 | if (!noctty && | 2562 | if (!noctty && |
2551 | current->signal->leader && | 2563 | current->signal->leader && |
2552 | !current->signal->tty && | 2564 | !current->signal->tty && |
2553 | tty->session == 0) { | 2565 | tty->session == 0) |
2554 | task_lock(current); | 2566 | __proc_set_tty(current, tty); |
2555 | current->signal->tty = tty; | 2567 | spin_unlock_irq(¤t->sighand->siglock); |
2556 | task_unlock(current); | 2568 | mutex_unlock(&tty_mutex); |
2557 | current->signal->tty_old_pgrp = 0; | ||
2558 | tty->session = current->signal->session; | ||
2559 | tty->pgrp = process_group(current); | ||
2560 | } | ||
2561 | return 0; | 2569 | return 0; |
2562 | } | 2570 | } |
2563 | 2571 | ||
@@ -2747,7 +2755,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p) | |||
2747 | * | 2755 | * |
2748 | * Copies the kernel idea of the window size into the user buffer. | 2756 | * Copies the kernel idea of the window size into the user buffer. |
2749 | * | 2757 | * |
2750 | * Locking: tty->termios_sem is taken to ensure the winsize data | 2758 | * Locking: tty->termios_mutex is taken to ensure the winsize data |
2751 | * is consistent. | 2759 | * is consistent. |
2752 | */ | 2760 | */ |
2753 | 2761 | ||
@@ -2774,8 +2782,8 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) | |||
2774 | * Locking: | 2782 | * Locking: |
2775 | * Called function use the console_sem is used to ensure we do | 2783 | * Called function use the console_sem is used to ensure we do |
2776 | * not try and resize the console twice at once. | 2784 | * not try and resize the console twice at once. |
2777 | * The tty->termios_sem is used to ensure we don't double | 2785 | * The tty->termios_mutex is used to ensure we don't double |
2778 | * resize and get confused. Lock order - tty->termios.sem before | 2786 | * resize and get confused. Lock order - tty->termios_mutex before |
2779 | * console sem | 2787 | * console sem |
2780 | */ | 2788 | */ |
2781 | 2789 | ||
@@ -2880,25 +2888,28 @@ static int fionbio(struct file *file, int __user *p) | |||
2880 | * leader to set this tty as the controlling tty for the session. | 2888 | * leader to set this tty as the controlling tty for the session. |
2881 | * | 2889 | * |
2882 | * Locking: | 2890 | * Locking: |
2883 | * Takes tasklist lock internally to walk sessions | ||
2884 | * Takes task_lock() when updating signal->tty | ||
2885 | * Takes tty_mutex() to protect tty instance | 2891 | * Takes tty_mutex() to protect tty instance |
2886 | * | 2892 | * Takes tasklist_lock internally to walk sessions |
2893 | * Takes ->siglock() when updating signal->tty | ||
2887 | */ | 2894 | */ |
2888 | 2895 | ||
2889 | static int tiocsctty(struct tty_struct *tty, int arg) | 2896 | static int tiocsctty(struct tty_struct *tty, int arg) |
2890 | { | 2897 | { |
2891 | struct task_struct *p; | 2898 | int ret = 0; |
2892 | |||
2893 | if (current->signal->leader && | 2899 | if (current->signal->leader && |
2894 | (current->signal->session == tty->session)) | 2900 | (current->signal->session == tty->session)) |
2895 | return 0; | 2901 | return ret; |
2902 | |||
2903 | mutex_lock(&tty_mutex); | ||
2896 | /* | 2904 | /* |
2897 | * The process must be a session leader and | 2905 | * The process must be a session leader and |
2898 | * not have a controlling tty already. | 2906 | * not have a controlling tty already. |
2899 | */ | 2907 | */ |
2900 | if (!current->signal->leader || current->signal->tty) | 2908 | if (!current->signal->leader || current->signal->tty) { |
2901 | return -EPERM; | 2909 | ret = -EPERM; |
2910 | goto unlock; | ||
2911 | } | ||
2912 | |||
2902 | if (tty->session > 0) { | 2913 | if (tty->session > 0) { |
2903 | /* | 2914 | /* |
2904 | * This tty is already the controlling | 2915 | * This tty is already the controlling |
@@ -2908,24 +2919,18 @@ static int tiocsctty(struct tty_struct *tty, int arg) | |||
2908 | /* | 2919 | /* |
2909 | * Steal it away | 2920 | * Steal it away |
2910 | */ | 2921 | */ |
2911 | |||
2912 | read_lock(&tasklist_lock); | 2922 | read_lock(&tasklist_lock); |
2913 | do_each_task_pid(tty->session, PIDTYPE_SID, p) { | 2923 | session_clear_tty(tty->session); |
2914 | p->signal->tty = NULL; | ||
2915 | } while_each_task_pid(tty->session, PIDTYPE_SID, p); | ||
2916 | read_unlock(&tasklist_lock); | 2924 | read_unlock(&tasklist_lock); |
2917 | } else | 2925 | } else { |
2918 | return -EPERM; | 2926 | ret = -EPERM; |
2927 | goto unlock; | ||
2928 | } | ||
2919 | } | 2929 | } |
2920 | mutex_lock(&tty_mutex); | 2930 | proc_set_tty(current, tty); |
2921 | task_lock(current); | 2931 | unlock: |
2922 | current->signal->tty = tty; | ||
2923 | task_unlock(current); | ||
2924 | mutex_unlock(&tty_mutex); | 2932 | mutex_unlock(&tty_mutex); |
2925 | current->signal->tty_old_pgrp = 0; | 2933 | return ret; |
2926 | tty->session = current->signal->session; | ||
2927 | tty->pgrp = process_group(current); | ||
2928 | return 0; | ||
2929 | } | 2934 | } |
2930 | 2935 | ||
2931 | /** | 2936 | /** |
@@ -2937,7 +2942,7 @@ static int tiocsctty(struct tty_struct *tty, int arg) | |||
2937 | * Obtain the process group of the tty. If there is no process group | 2942 | * Obtain the process group of the tty. If there is no process group |
2938 | * return an error. | 2943 | * return an error. |
2939 | * | 2944 | * |
2940 | * Locking: none. Reference to ->signal->tty is safe. | 2945 | * Locking: none. Reference to current->signal->tty is safe. |
2941 | */ | 2946 | */ |
2942 | 2947 | ||
2943 | static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | 2948 | static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) |
@@ -2995,7 +3000,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t | |||
2995 | * Obtain the session id of the tty. If there is no session | 3000 | * Obtain the session id of the tty. If there is no session |
2996 | * return an error. | 3001 | * return an error. |
2997 | * | 3002 | * |
2998 | * Locking: none. Reference to ->signal->tty is safe. | 3003 | * Locking: none. Reference to current->signal->tty is safe. |
2999 | */ | 3004 | */ |
3000 | 3005 | ||
3001 | static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | 3006 | static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) |
@@ -3214,14 +3219,11 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
3214 | clear_bit(TTY_EXCLUSIVE, &tty->flags); | 3219 | clear_bit(TTY_EXCLUSIVE, &tty->flags); |
3215 | return 0; | 3220 | return 0; |
3216 | case TIOCNOTTY: | 3221 | case TIOCNOTTY: |
3217 | /* FIXME: taks lock or tty_mutex ? */ | ||
3218 | if (current->signal->tty != tty) | 3222 | if (current->signal->tty != tty) |
3219 | return -ENOTTY; | 3223 | return -ENOTTY; |
3220 | if (current->signal->leader) | 3224 | if (current->signal->leader) |
3221 | disassociate_ctty(0); | 3225 | disassociate_ctty(0); |
3222 | task_lock(current); | 3226 | proc_clear_tty(current); |
3223 | current->signal->tty = NULL; | ||
3224 | task_unlock(current); | ||
3225 | return 0; | 3227 | return 0; |
3226 | case TIOCSCTTY: | 3228 | case TIOCSCTTY: |
3227 | return tiocsctty(tty, arg); | 3229 | return tiocsctty(tty, arg); |
@@ -3321,7 +3323,7 @@ static void __do_SAK(struct work_struct *work) | |||
3321 | 3323 | ||
3322 | if (!tty) | 3324 | if (!tty) |
3323 | return; | 3325 | return; |
3324 | session = tty->session; | 3326 | session = tty->session; |
3325 | 3327 | ||
3326 | /* We don't want an ldisc switch during this */ | 3328 | /* We don't want an ldisc switch during this */ |
3327 | disc = tty_ldisc_ref(tty); | 3329 | disc = tty_ldisc_ref(tty); |
@@ -3834,9 +3836,52 @@ int tty_unregister_driver(struct tty_driver *driver) | |||
3834 | cdev_del(&driver->cdev); | 3836 | cdev_del(&driver->cdev); |
3835 | return 0; | 3837 | return 0; |
3836 | } | 3838 | } |
3837 | |||
3838 | EXPORT_SYMBOL(tty_unregister_driver); | 3839 | EXPORT_SYMBOL(tty_unregister_driver); |
3839 | 3840 | ||
3841 | dev_t tty_devnum(struct tty_struct *tty) | ||
3842 | { | ||
3843 | return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; | ||
3844 | } | ||
3845 | EXPORT_SYMBOL(tty_devnum); | ||
3846 | |||
3847 | void proc_clear_tty(struct task_struct *p) | ||
3848 | { | ||
3849 | spin_lock_irq(&p->sighand->siglock); | ||
3850 | p->signal->tty = NULL; | ||
3851 | spin_unlock_irq(&p->sighand->siglock); | ||
3852 | } | ||
3853 | EXPORT_SYMBOL(proc_clear_tty); | ||
3854 | |||
3855 | void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) | ||
3856 | { | ||
3857 | if (tty) { | ||
3858 | tty->session = tsk->signal->session; | ||
3859 | tty->pgrp = process_group(tsk); | ||
3860 | } | ||
3861 | tsk->signal->tty = tty; | ||
3862 | tsk->signal->tty_old_pgrp = 0; | ||
3863 | } | ||
3864 | |||
3865 | void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) | ||
3866 | { | ||
3867 | spin_lock_irq(&tsk->sighand->siglock); | ||
3868 | __proc_set_tty(tsk, tty); | ||
3869 | spin_unlock_irq(&tsk->sighand->siglock); | ||
3870 | } | ||
3871 | |||
3872 | struct tty_struct *get_current_tty(void) | ||
3873 | { | ||
3874 | struct tty_struct *tty; | ||
3875 | WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); | ||
3876 | tty = current->signal->tty; | ||
3877 | /* | ||
3878 | * session->tty can be changed/cleared from under us, make sure we | ||
3879 | * issue the load. The obtained pointer, when not NULL, is valid as | ||
3880 | * long as we hold tty_mutex. | ||
3881 | */ | ||
3882 | barrier(); | ||
3883 | return tty; | ||
3884 | } | ||
3840 | 3885 | ||
3841 | /* | 3886 | /* |
3842 | * Initialize the console device. This is called *early*, so | 3887 | * Initialize the console device. This is called *early*, so |