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

[PATCH] large dev_t - second series (6/15)

	tty redirect handling sanitized.  Such ttys (/dev/tty and
/dev/console) get a different file_operations; its ->write() handles
redirects; checks for file->f_op == &tty_fops updated, checks for
major:minor being that of a redirector replaced with check for
->f_op->write value.  Piece of code in tty_io.c that had been #if 0
since 0.99<something> had been finally put out of its misery. kdev_val()
is gone.
parent 25a6ca89
...@@ -50,9 +50,6 @@ ...@@ -50,9 +50,6 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
/* number of characters left in xmit buffer before select has we have room */ /* number of characters left in xmit buffer before select has we have room */
#define WAKEUP_CHARS 256 #define WAKEUP_CHARS 256
...@@ -951,6 +948,8 @@ static inline int copy_from_read_buf(struct tty_struct *tty, ...@@ -951,6 +948,8 @@ static inline int copy_from_read_buf(struct tty_struct *tty,
return retval; return retval;
} }
extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *);
static ssize_t read_chan(struct tty_struct *tty, struct file *file, static ssize_t read_chan(struct tty_struct *tty, struct file *file,
unsigned char *buf, size_t nr) unsigned char *buf, size_t nr)
{ {
...@@ -975,9 +974,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, ...@@ -975,9 +974,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
/* NOTE: not yet done after every sleep pending a thorough /* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */ check of the logic of this change. -- jlc */
/* don't stop on /dev/console */ /* don't stop on /dev/console */
if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) && if (file->f_op->write != redirected_tty_write && current->tty == tty) {
!IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) &&
current->tty == tty) {
if (tty->pgrp <= 0) if (tty->pgrp <= 0)
printk("read_chan: tty->pgrp <= 0!\n"); printk("read_chan: tty->pgrp <= 0!\n");
else if (current->pgrp != tty->pgrp) { else if (current->pgrp != tty->pgrp) {
...@@ -1168,9 +1165,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, ...@@ -1168,9 +1165,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
ssize_t retval = 0; ssize_t retval = 0;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
if (L_TOSTOP(tty) && if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
!IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) {
retval = tty_check_change(tty); retval = tty_check_change(tty);
if (retval) if (retval)
return retval; return retval;
......
...@@ -103,11 +103,6 @@ ...@@ -103,11 +103,6 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0))
#define IS_TTY_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0))
#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
#define IS_PTMX_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2))
#undef TTY_DEBUG_HANGUP #undef TTY_DEBUG_HANGUP
#define TTY_PARANOIA_CHECK 1 #define TTY_PARANOIA_CHECK 1
...@@ -136,6 +131,7 @@ static void initialize_tty_struct(struct tty_struct *tty); ...@@ -136,6 +131,7 @@ 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 *);
static ssize_t tty_write(struct file *, const char *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char *, size_t, loff_t *);
ssize_t redirected_tty_write(struct file *, const char *, size_t, loff_t *);
static unsigned int tty_poll(struct file *, poll_table *); static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *); static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *); static int tty_release(struct inode *, struct file *);
...@@ -382,6 +378,17 @@ static struct file_operations tty_fops = { ...@@ -382,6 +378,17 @@ static struct file_operations tty_fops = {
.fasync = tty_fasync, .fasync = tty_fasync,
}; };
static struct file_operations console_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = redirected_tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
static struct file_operations hung_up_tty_fops = { static struct file_operations hung_up_tty_fops = {
.llseek = no_llseek, .llseek = no_llseek,
.read = hung_up_tty_read, .read = hung_up_tty_read,
...@@ -425,12 +432,9 @@ void do_tty_hangup(void *data) ...@@ -425,12 +432,9 @@ void do_tty_hangup(void *data)
check_tty_count(tty, "do_tty_hangup"); check_tty_count(tty, "do_tty_hangup");
file_list_lock(); file_list_lock();
list_for_each_entry(filp, &tty->tty_files, f_list) { list_for_each_entry(filp, &tty->tty_files, f_list) {
if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) || if (filp->f_op->write == redirected_tty_write)
IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
cons_filp = filp; cons_filp = filp;
continue; if (filp->f_op->write != tty_write)
}
if (filp->f_op != &tty_fops)
continue; continue;
closecount++; closecount++;
tty_fasync(-1, filp, 0); /* can't block */ tty_fasync(-1, filp, 0); /* can't block */
...@@ -650,22 +654,6 @@ static ssize_t tty_read(struct file * file, char * buf, size_t count, ...@@ -650,22 +654,6 @@ static ssize_t tty_read(struct file * file, char * buf, size_t count,
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO; return -EIO;
/* This check not only needs to be done before reading, but also
whenever read_chan() gets woken up after sleeping, so I've
moved it to there. This should only be done for the N_TTY
line discipline, anyway. Same goes for write_chan(). -- jlc. */
#if 0
if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */
(tty->pgrp > 0) &&
(current->tty == tty) &&
(tty->pgrp != current->pgrp))
if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
return -EIO;
else {
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
#endif
lock_kernel(); lock_kernel();
if (tty->ldisc.read) if (tty->ldisc.read)
i = (tty->ldisc.read)(tty,file,buf,count); i = (tty->ldisc.read)(tty,file,buf,count);
...@@ -730,21 +718,27 @@ static inline ssize_t do_tty_write( ...@@ -730,21 +718,27 @@ static inline ssize_t do_tty_write(
static ssize_t tty_write(struct file * file, const char * buf, size_t count, static ssize_t tty_write(struct file * file, const char * buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
int is_console;
struct tty_struct * tty; struct tty_struct * tty;
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
/*
* For now, we redirect writes from /dev/console as
* well as /dev/tty0.
*/
is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
IS_CONSOLE_DEV(inode->i_rdev);
/* Can't seek (pwrite) on ttys. */ /* Can't seek (pwrite) on ttys. */
if (ppos != &file->f_pos) if (ppos != &file->f_pos)
return -ESPIPE; return -ESPIPE;
if (is_console) { tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
if (!tty->ldisc.write)
return -EIO;
return do_tty_write(tty->ldisc.write, tty, file,
(const unsigned char *)buf, count);
}
ssize_t redirected_tty_write(struct file * file, const char * buf, size_t count,
loff_t *ppos)
{
struct file *p = NULL; struct file *p = NULL;
spin_lock(&redirect_lock); spin_lock(&redirect_lock);
...@@ -755,21 +749,16 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count, ...@@ -755,21 +749,16 @@ static ssize_t tty_write(struct file * file, const char * buf, size_t count,
spin_unlock(&redirect_lock); spin_unlock(&redirect_lock);
if (p) { if (p) {
ssize_t res = vfs_write(p, buf, count, &p->f_pos); ssize_t res;
/* Can't seek (pwrite) on ttys. */
if (ppos != &file->f_pos)
return -ESPIPE;
res = vfs_write(p, buf, count, &p->f_pos);
fput(p); fput(p);
return res; return res;
} }
}
tty = (struct tty_struct *)file->private_data; return tty_write(file, buf, count, ppos);
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
if (!tty->ldisc.write)
return -EIO;
return do_tty_write(tty->ldisc.write, tty, file,
(const unsigned char *)buf, count);
} }
/* Semaphore to protect creating and releasing a tty */ /* Semaphore to protect creating and releasing a tty */
...@@ -1306,14 +1295,11 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1306,14 +1295,11 @@ static int tty_open(struct inode * inode, struct file * filp)
int noctty, retval; int noctty, retval;
struct tty_driver *driver; struct tty_driver *driver;
int index; int index;
kdev_t device; dev_t device = kdev_t_to_nr(inode->i_rdev);
unsigned short saved_flags; unsigned short saved_flags = filp->f_flags;
saved_flags = filp->f_flags;
retry_open: retry_open:
noctty = filp->f_flags & O_NOCTTY; noctty = filp->f_flags & O_NOCTTY;
device = inode->i_rdev; if (device == MKDEV(TTYAUX_MAJOR,0)) {
if (IS_TTY_DEV(device)) {
if (!current->tty) if (!current->tty)
return -ENXIO; return -ENXIO;
driver = current->tty->driver; driver = current->tty->driver;
...@@ -1323,7 +1309,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1323,7 +1309,7 @@ static int tty_open(struct inode * inode, struct file * filp)
goto got_driver; goto got_driver;
} }
#ifdef CONFIG_VT #ifdef CONFIG_VT
if (IS_CONSOLE_DEV(device)) { if (device == MKDEV(TTY_MAJOR,0)) {
extern int fg_console; extern int fg_console;
extern struct tty_driver *console_driver; extern struct tty_driver *console_driver;
driver = console_driver; driver = console_driver;
...@@ -1332,7 +1318,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1332,7 +1318,7 @@ static int tty_open(struct inode * inode, struct file * filp)
goto got_driver; goto got_driver;
} }
#endif #endif
if (IS_SYSCONS_DEV(device)) { if (device == MKDEV(TTYAUX_MAJOR,1)) {
struct console *c = console_drivers; struct console *c = console_drivers;
for (c = console_drivers; c; c = c->next) { for (c = console_drivers; c; c = c->next) {
if (!c->device) if (!c->device)
...@@ -1348,7 +1334,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1348,7 +1334,7 @@ static int tty_open(struct inode * inode, struct file * filp)
return -ENODEV; return -ENODEV;
} }
if (IS_PTMX_DEV(device)) { if (device == MKDEV(TTYAUX_MAJOR,2)) {
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
/* find a device that is not in use. */ /* find a device that is not in use. */
retval = -1; retval = -1;
...@@ -1365,7 +1351,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1365,7 +1351,7 @@ static int tty_open(struct inode * inode, struct file * filp)
return -ENODEV; return -ENODEV;
#endif /* CONFIG_UNIX_98_PTYS */ #endif /* CONFIG_UNIX_98_PTYS */
} else { } else {
driver = get_tty_driver(kdev_t_to_nr(device), &index); driver = get_tty_driver(device, &index);
if (!driver) if (!driver)
return -ENODEV; return -ENODEV;
got_driver: got_driver:
...@@ -1407,6 +1393,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1407,6 +1393,7 @@ static int tty_open(struct inode * inode, struct file * filp)
/* /*
* Need to reset f_op in case a hangup happened. * Need to reset f_op in case a hangup happened.
*/ */
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops; filp->f_op = &tty_fops;
goto retry_open; goto retry_open;
} }
...@@ -1516,10 +1503,9 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, ...@@ -1516,10 +1503,9 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
return 0; return 0;
} }
static int tioccons(struct inode *inode, struct file *file) static int tioccons(struct file *file)
{ {
if (IS_SYSCONS_DEV(inode->i_rdev) || if (file->f_op->write == redirected_tty_write) {
IS_CONSOLE_DEV(inode->i_rdev)) {
struct file *f; struct file *f;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -1786,7 +1772,7 @@ int tty_ioctl(struct inode * inode, struct file * file, ...@@ -1786,7 +1772,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 real_tty!=tty ? -EINVAL : tioccons(inode, file); return real_tty!=tty ? -EINVAL : tioccons(file);
case FIONBIO: case FIONBIO:
return fionbio(file, (int *) arg); return fionbio(file, (int *) arg);
case TIOCEXCL: case TIOCEXCL:
...@@ -1917,8 +1903,10 @@ static void __do_SAK(void *arg) ...@@ -1917,8 +1903,10 @@ static void __do_SAK(void *arg)
spin_lock(&p->files->file_lock); spin_lock(&p->files->file_lock);
for (i=0; i < p->files->max_fds; i++) { for (i=0; i < p->files->max_fds; i++) {
filp = fcheck_files(p->files, i); filp = fcheck_files(p->files, i);
if (filp && (filp->f_op == &tty_fops) && if (!filp)
(filp->private_data == tty)) { continue;
if (filp->f_op->read == tty_read &&
filp->private_data == tty) {
printk(KERN_NOTICE "SAK: killed process %d" printk(KERN_NOTICE "SAK: killed process %d"
" (%s): fd#%d opened to the tty\n", " (%s): fd#%d opened to the tty\n",
p->pid, p->comm, i); p->pid, p->comm, i);
...@@ -2446,7 +2434,7 @@ void __init tty_init(void) ...@@ -2446,7 +2434,7 @@ void __init tty_init(void)
tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL);
strcpy(console_cdev.kobj.name, "dev.console"); strcpy(console_cdev.kobj.name, "dev.console");
cdev_init(&console_cdev, &tty_fops); cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n"); panic("Couldn't register /dev/console driver\n");
...@@ -2468,7 +2456,7 @@ void __init tty_init(void) ...@@ -2468,7 +2456,7 @@ void __init tty_init(void)
#ifdef CONFIG_VT #ifdef CONFIG_VT
strcpy(vc0_cdev.kobj.name, "dev.vc0"); strcpy(vc0_cdev.kobj.name, "dev.vc0");
cdev_init(&vc0_cdev, &tty_fops); cdev_init(&vc0_cdev, &console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n"); panic("Couldn't register /dev/tty0 driver\n");
......
...@@ -80,16 +80,6 @@ typedef struct { ...@@ -80,16 +80,6 @@ typedef struct {
#define mk_kdev(major, minor) ((kdev_t) { __mkdev(major,minor) } ) #define mk_kdev(major, minor) ((kdev_t) { __mkdev(major,minor) } )
/*
* The "values" are just _cookies_, usable for
* internal equality comparisons and for things
* like NFS filehandle conversion.
*/
static inline unsigned int kdev_val(kdev_t dev)
{
return dev.value;
}
#define NODEV (mk_kdev(0,0)) #define NODEV (mk_kdev(0,0))
/* Mask off the high bits for now.. */ /* Mask off the high bits for now.. */
......
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