#include <linux/device.h>
#include <linux/idr.h>
#include <linux/wait.h>
-#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/bitops.h>
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
extern int pty_limit; /* Config limit on Unix98 ptys */
static DEFINE_IDR(allocated_ptys);
static DECLARE_MUTEX(allocated_ptys_lock);
-static int ptmx_open(struct inode *, struct file *);
#endif
extern void disable_early_printk(void);
ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *);
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
+static int ptmx_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static inline void free_tty_struct(struct tty_struct *tty)
{
- kfree(tty->write_buf);
kfree(tty);
}
lock_kernel();
- down(&tty_sem);
tty = current->signal->tty;
if (tty) {
tty_pgrp = tty->pgrp;
- up(&tty_sem);
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
} else {
kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
}
- up(&tty_sem);
unlock_kernel();
return;
}
kill_pg(tty_pgrp, SIGCONT, on_exit);
}
- /* Must lock changes to tty_old_pgrp */
- down(&tty_sem);
current->signal->tty_old_pgrp = 0;
tty->session = 0;
tty->pgrp = -1;
- /* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
p->signal->tty = NULL;
} while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
read_unlock(&tasklist_lock);
- up(&tty_sem);
unlock_kernel();
}
* denial-of-service type attacks
*/
static inline ssize_t do_tty_write(
- ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
+ ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char __user *, size_t),
struct tty_struct *tty,
struct file *file,
- const char __user *buf,
+ const unsigned char __user *buf,
size_t count)
{
ssize_t ret = 0, written = 0;
- unsigned int chunk;
if (down_interruptible(&tty->atomic_write)) {
return -ERESTARTSYS;
}
-
- /*
- * We chunk up writes into a temporary buffer. This
- * simplifies low-level drivers immensely, since they
- * don't have locking issues and user mode accesses.
- *
- * But if TTY_NO_WRITE_SPLIT is set, we should use a
- * big chunk-size..
- */
- chunk = 4096;
- if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
- chunk = 65536;
- if (count < chunk)
- chunk = count;
-
- /* write_buf/write_cnt is protected by the atomic_write semaphore */
- if (tty->write_cnt < chunk) {
- unsigned char *buf;
-
- if (chunk < 1024)
- chunk = 1024;
-
- buf = kmalloc(chunk, GFP_KERNEL);
- if (!buf) {
- up(&tty->atomic_write);
- return -ENOMEM;
- }
- kfree(tty->write_buf);
- tty->write_cnt = chunk;
- tty->write_buf = buf;
- }
-
- /* Do the write .. */
- for (;;) {
- size_t size = count;
- if (size > chunk)
- size = chunk;
- ret = -EFAULT;
- if (copy_from_user(tty->write_buf, buf, size))
- break;
+ if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
lock_kernel();
- ret = write(tty, file, tty->write_buf, size);
+ written = write(tty, file, buf, count);
unlock_kernel();
- if (ret <= 0)
- break;
- written += ret;
- buf += ret;
- count -= ret;
- if (!count)
- break;
- ret = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- cond_resched();
+ } else {
+ for (;;) {
+ unsigned long size = max((unsigned long)PAGE_SIZE*2, 16384UL);
+ if (size > count)
+ size = count;
+ lock_kernel();
+ ret = write(tty, file, buf, size);
+ unlock_kernel();
+ if (ret <= 0)
+ break;
+ written += ret;
+ buf += ret;
+ count -= ret;
+ if (!count)
+ break;
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ cond_resched();
+ }
}
if (written) {
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
if (!ld->write)
ret = -EIO;
else
- ret = do_tty_write(ld->write, tty, file, buf, count);
+ ret = do_tty_write(ld->write, tty, file,
+ (const unsigned char __user *)buf, count);
tty_ldisc_deref(ld);
return ret;
}
int i = index + driver->name_base;
/* ->name is initialized to "ttyp", but "tty" is expected */
sprintf(p, "%s%c%x",
- driver->subtype == PTY_TYPE_SLAVE ? "pty" : driver->name,
- ptychar[i >> 4 & 0xf], i & 0xf);
+ driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
+ ptychar[i >> 4 & 0xf], i & 0xf);
}
static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
int retval=0;
+ /*
+ * Check whether we need to acquire the tty semaphore to avoid
+ * race conditions. For now, play it safe.
+ */
+ down(&tty_sem);
+
/* check whether we're reopening an existing tty */
if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
tty = devpts_get_tty(idx);
/* All paths come through here to release the semaphore */
end_init:
+ up(&tty_sem);
return retval;
/* Release locally allocated memory ... nothing placed in slots */
* each iteration we avoid any problems.
*/
while (1) {
- /* Guard against races with tty->count changes elsewhere and
- opens on /dev/tty */
-
- down(&tty_sem);
tty_closing = tty->count <= 1;
o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
- up(&tty_sem);
do_sleep = 0;
if (tty_closing) {
* both sides, and we've completed the last operation that could
* block, so it's safe to proceed with closing.
*/
-
- down(&tty_sem);
if (pty_master) {
if (--o_tty->count < 0) {
printk(KERN_WARNING "release_dev: bad pty slave count "
tty->count, tty_name(tty, buf));
tty->count = 0;
}
- up(&tty_sem);
-
+
/*
* We've decremented tty->count, so we need to remove this file
* descriptor off the tty->tty_files list; this serves two
noctty = filp->f_flags & O_NOCTTY;
index = -1;
retval = 0;
-
- down(&tty_sem);
if (device == MKDEV(TTYAUX_MAJOR,0)) {
- if (!current->signal->tty) {
- up(&tty_sem);
+ if (!current->signal->tty)
return -ENXIO;
- }
driver = current->signal->tty->driver;
index = current->signal->tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
noctty = 1;
goto got_driver;
}
- up(&tty_sem);
return -ENODEV;
}
driver = get_tty_driver(device, &index);
- if (!driver) {
- up(&tty_sem);
+ if (!driver)
return -ENODEV;
- }
got_driver:
retval = init_dev(driver, index, &tty);
- up(&tty_sem);
if (retval)
return retval;
}
up(&allocated_ptys_lock);
- down(&tty_sem);
retval = init_dev(ptm_driver, index, &tty);
- up(&tty_sem);
-
if (retval)
goto out;
*/
static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
{
- tty->driver->write(tty, &ch, 1);
+ tty->driver->write(tty, 0, &ch, 1);
}
static struct class_simple *tty_class;