Commit bf78f301 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] TIOCCONS fix

This fixes the TIOCCONS race; it's the same as the 2.4 patch except for
a fix for a brown-paperbag bug in it.
parent 6a7b3d00
...@@ -132,12 +132,6 @@ extern struct tty_driver pts_driver; /* Unix98 pty slaves; for /dev/ptmx */ ...@@ -132,12 +132,6 @@ extern struct tty_driver pts_driver; /* Unix98 pty slaves; for /dev/ptmx */
extern void disable_early_printk(void); extern void disable_early_printk(void);
/*
* redirect is the pseudo-tty that console output
* is redirected to if asked by TIOCCONS.
*/
static struct tty_struct *redirect;
static void initialize_tty_struct(struct tty_struct *tty); static void initialize_tty_struct(struct tty_struct *tty);
static ssize_t tty_read(struct file *, char *, size_t, loff_t *); static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
...@@ -400,6 +394,8 @@ static struct file_operations hung_up_tty_fops = { ...@@ -400,6 +394,8 @@ static struct file_operations hung_up_tty_fops = {
.release = tty_release, .release = tty_release,
}; };
static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
static struct file *redirect;
/* /*
* This can be called by the "eventd" kernel thread. That is process synchronous, * This can be called by the "eventd" kernel thread. That is process synchronous,
* but doesn't hold any locks, so we need to make sure we have the appropriate * but doesn't hold any locks, so we need to make sure we have the appropriate
...@@ -409,7 +405,7 @@ void do_tty_hangup(void *data) ...@@ -409,7 +405,7 @@ void do_tty_hangup(void *data)
{ {
struct tty_struct *tty = (struct tty_struct *) data; struct tty_struct *tty = (struct tty_struct *) data;
struct file * cons_filp = NULL; struct file * cons_filp = NULL;
struct file *filp; struct file *filp, *f = NULL;
struct task_struct *p; struct task_struct *p;
struct pid *pid; struct pid *pid;
int closecount = 0, n; int closecount = 0, n;
...@@ -419,6 +415,15 @@ void do_tty_hangup(void *data) ...@@ -419,6 +415,15 @@ void do_tty_hangup(void *data)
/* inuse_filps is protected by the single kernel lock */ /* inuse_filps is protected by the single kernel lock */
lock_kernel(); lock_kernel();
spin_lock(&redirect_lock);
if (redirect && redirect->private_data == tty) {
f = redirect;
redirect = NULL;
}
spin_unlock(&redirect_lock);
if (f)
fput(f);
check_tty_count(tty, "do_tty_hangup"); check_tty_count(tty, "do_tty_hangup");
file_list_lock(); file_list_lock();
...@@ -726,39 +731,40 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count, ...@@ -726,39 +731,40 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count,
{ {
int is_console; int is_console;
struct tty_struct * tty; struct tty_struct * tty;
struct inode *inode; struct inode *inode = file->f_dentry->d_inode;
/* Can't seek (pwrite) on ttys. */
if (ppos != &file->f_pos)
return -ESPIPE;
/* /*
* For now, we redirect writes from /dev/console as * For now, we redirect writes from /dev/console as
* well as /dev/tty0. * well as /dev/tty0.
*/ */
inode = file->f_dentry->d_inode;
is_console = IS_SYSCONS_DEV(inode->i_rdev) || is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
IS_CONSOLE_DEV(inode->i_rdev); IS_CONSOLE_DEV(inode->i_rdev);
if (is_console && redirect) /* Can't seek (pwrite) on ttys. */
tty = redirect; if (ppos != &file->f_pos)
else return -ESPIPE;
tty = (struct tty_struct *)file->private_data;
if (is_console) {
struct file *p = NULL;
spin_lock(&redirect_lock);
if (redirect) {
get_file(redirect);
p = redirect;
}
spin_unlock(&redirect_lock);
if (p) {
ssize_t res = vfs_write(p, buf, count, &p->f_pos);
fput(p);
return res;
}
}
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
return -EIO; return -EIO;
if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO; return -EIO;
#if 0
if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == tty) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(current->pgrp))
return -EIO;
if (!is_ignored(SIGTTOU)) {
(void) kill_pg(current->pgrp, SIGTTOU, 1);
return -ERESTARTSYS;
}
}
#endif
if (!tty->ldisc.write) if (!tty->ldisc.write)
return -EIO; return -EIO;
return do_tty_write(tty->ldisc.write, tty, file, return do_tty_write(tty->ldisc.write, tty, file,
...@@ -1221,7 +1227,7 @@ static void release_dev(struct file * filp) ...@@ -1221,7 +1227,7 @@ static void release_dev(struct file * filp)
/* /*
* If _either_ side is closing, make sure there aren't any * If _either_ side is closing, make sure there aren't any
* processes that still think tty or o_tty is their controlling * processes that still think tty or o_tty is their controlling
* tty. Also, clear redirect if it points to either tty. * tty.
*/ */
if (tty_closing || o_tty_closing) { if (tty_closing || o_tty_closing) {
struct task_struct *p; struct task_struct *p;
...@@ -1235,9 +1241,6 @@ static void release_dev(struct file * filp) ...@@ -1235,9 +1241,6 @@ static void release_dev(struct file * filp)
for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid) for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid)
p->tty = NULL; p->tty = NULL;
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
if (redirect == tty || (o_tty && redirect == o_tty))
redirect = NULL;
} }
/* check whether both sides are closing ... */ /* check whether both sides are closing ... */
...@@ -1526,19 +1529,29 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, ...@@ -1526,19 +1529,29 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
return 0; return 0;
} }
static int tioccons(struct inode *inode, static int tioccons(struct inode *inode, struct file *file)
struct tty_struct *tty, struct tty_struct *real_tty)
{ {
if (IS_SYSCONS_DEV(inode->i_rdev) || if (IS_SYSCONS_DEV(inode->i_rdev) ||
IS_CONSOLE_DEV(inode->i_rdev)) { IS_CONSOLE_DEV(inode->i_rdev)) {
struct file *f;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
spin_lock(&redirect_lock);
f = redirect;
redirect = NULL; redirect = NULL;
spin_unlock(&redirect_lock);
if (f)
fput(f);
return 0; return 0;
} }
if (redirect) spin_lock(&redirect_lock);
if (redirect) {
spin_unlock(&redirect_lock);
return -EBUSY; return -EBUSY;
redirect = real_tty; }
get_file(file);
redirect = file;
spin_unlock(&redirect_lock);
return 0; return 0;
} }
...@@ -1786,7 +1799,7 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -1786,7 +1799,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCSWINSZ: case TIOCSWINSZ:
return tiocswinsz(tty, real_tty, (struct winsize *) arg); return tiocswinsz(tty, real_tty, (struct winsize *) arg);
case TIOCCONS: case TIOCCONS:
return tioccons(inode, tty, real_tty); return real_tty!=tty ? -EINVAL : tioccons(inode, file);
case FIONBIO: case FIONBIO:
return fionbio(file, (int *) arg); return fionbio(file, (int *) arg);
case TIOCEXCL: case TIOCEXCL:
......
...@@ -345,7 +345,6 @@ struct tty_struct { ...@@ -345,7 +345,6 @@ struct tty_struct {
extern void tty_write_flush(struct tty_struct *); extern void tty_write_flush(struct tty_struct *);
extern struct termios tty_std_termios; extern struct termios tty_std_termios;
extern struct tty_struct * redirect;
extern struct tty_ldisc ldiscs[]; extern struct tty_ldisc ldiscs[];
extern int fg_console, last_console, want_console; extern int fg_console, last_console, want_console;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment