X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Ftty%2Ftty_io.c;h=1f9ee25b635e7196c6a0c464da5d8d91f88c59c8;hp=05085beb83dbe31b49679735530fa4a5a42b8882;hb=710dbb61210c0546cd1bfd9ebd0ad29207202d26;hpb=a84f6aa68e35a911c28e5871c87356dce3607b40 diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 05085beb83db..1f9ee25b635e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -940,6 +940,14 @@ void start_tty(struct tty_struct *tty) EXPORT_SYMBOL(start_tty); +/* We limit tty time update visibility to every 8 seconds or so. */ +static void tty_update_time(struct timespec *time) +{ + unsigned long sec = get_seconds(); + if (abs(sec - time->tv_sec) & ~7) + time->tv_sec = sec; +} + /** * tty_read - read method for tty device files * @file: pointer to tty file @@ -976,8 +984,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, else i = -EIO; tty_ldisc_deref(ld); + if (i > 0) - inode->i_atime = current_fs_time(inode->i_sb); + tty_update_time(&inode->i_atime); + return i; } @@ -1079,8 +1089,8 @@ static inline ssize_t do_tty_write( cond_resched(); } if (written) { - struct inode *inode = file->f_path.dentry->d_inode; - inode->i_mtime = current_fs_time(inode->i_sb); + struct inode *inode = file->f_path.dentry->d_inode; + tty_update_time(&inode->i_mtime); ret = written; } out: @@ -1212,9 +1222,9 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) * * Locking: None */ -static void tty_line_name(struct tty_driver *driver, int index, char *p) +static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) { - sprintf(p, "%s%d", driver->name, index + driver->name_base); + return sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** @@ -1584,6 +1594,7 @@ int tty_release(struct inode *inode, struct file *filp) int devpts; int idx; char buf[64]; + long timeout = 0; if (tty_paranoia_check(tty, inode, "tty_release_dev")) return 0; @@ -1711,7 +1722,11 @@ int tty_release(struct inode *inode, struct file *filp) "active!\n", tty_name(tty, buf)); tty_unlock(); mutex_unlock(&tty_mutex); - schedule(); + schedule_timeout_killable(timeout); + if (timeout < 120 * HZ) + timeout = 2 * timeout + 1; + else + timeout = MAX_SCHEDULE_TIMEOUT; } /* @@ -1970,8 +1985,24 @@ got_driver: if (!noctty && current->signal->leader && !current->signal->tty && - tty->session == NULL) - __proc_set_tty(current, tty); + tty->session == NULL) { + /* + * Don't let a process that only has write access to the tty + * obtain the privileges associated with having a tty as + * controlling terminal (being able to reopen it with full + * access through /dev/tty, being able to perform pushback). + * Many distributions set the group of all ttys to "tty" and + * grant write-only access to all terminals for setgid tty + * binaries, which should not imply full privileges on all ttys. + * + * This could theoretically break old code that performs open() + * on a write-only file descriptor. In that case, it might be + * necessary to also permit this if + * inode_permission(inode, MAY_READ) == 0. + */ + if (filp->f_mode & FMODE_READ) + __proc_set_tty(current, tty); + } spin_unlock_irq(¤t->sighand->siglock); tty_unlock(); mutex_unlock(&tty_mutex); @@ -2251,7 +2282,7 @@ static int fionbio(struct file *file, int __user *p) * Takes ->siglock() when updating signal->tty */ -static int tiocsctty(struct tty_struct *tty, int arg) +static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) { int ret = 0; if (current->signal->leader && (task_session(current) == tty->session)) @@ -2284,6 +2315,13 @@ static int tiocsctty(struct tty_struct *tty, int arg) goto unlock; } } + + /* See the comment in tty_open(). */ + if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto unlock; + } + proc_set_tty(current, tty); unlock: mutex_unlock(&tty_mutex); @@ -2436,6 +2474,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) return ret; } +/** + * tiocgetd - get line discipline + * @tty: tty device + * @p: pointer to user data + * + * Retrieves the line discipline id directly from the ldisc. + * + * Locking: waits for ldisc reference (in case the line discipline + * is changing or the tty is being hungup) + */ + +static int tiocgetd(struct tty_struct *tty, int __user *p) +{ + struct tty_ldisc *ld; + int ret; + + ld = tty_ldisc_ref_wait(tty); + ret = put_user(ld->ops->num, p); + tty_ldisc_deref(ld); + return ret; +} + /** * send_break - performed time break * @tty: device to break on @@ -2638,7 +2698,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) no_tty(); return 0; case TIOCSCTTY: - return tiocsctty(tty, arg); + return tiocsctty(tty, file, arg); case TIOCGPGRP: return tiocgpgrp(tty, real_tty, p); case TIOCSPGRP: @@ -2646,7 +2706,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: - return put_user(tty->ldisc->ops->num, (int __user *)p); + return tiocgetd(tty, p); case TIOCSETD: return tiocsetd(tty, p); case TIOCVHANGUP: @@ -3311,9 +3371,19 @@ static ssize_t show_cons_active(struct device *dev, if (i >= ARRAY_SIZE(cs)) break; } - while (i--) - count += sprintf(buf + count, "%s%d%c", - cs[i]->name, cs[i]->index, i ? ' ':'\n'); + while (i--) { + int index = cs[i]->index; + struct tty_driver *drv = cs[i]->device(cs[i], &index); + + /* don't resolve tty0 as some programs depend on it */ + if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR)) + count += tty_line_name(drv, index, buf + count); + else + count += sprintf(buf + count, "%s%d", + cs[i]->name, cs[i]->index); + + count += sprintf(buf + count, "%c", i ? ' ':'\n'); + } console_unlock(); return count;