From 8f520021837d45c47d0ab57e7271f8d88bf7f3a4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 13 Oct 2008 10:38:46 +0100 Subject: tty: Termios locking - sort out real_tty confusions and lock reads This moves us towards sanity and should mean our termios locking is now complete and comprehensive. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/char/tty_ioctl.c | 58 +++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'drivers/char/tty_ioctl.c') diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 93bfa1d6cc9..30670851e51 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -893,6 +893,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, { struct tty_struct *real_tty; void __user *p = (void __user *)arg; + int ret = 0; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -928,18 +929,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 case TCGETS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #else case TCGETS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TCGETS2: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); case TCSETSW2: @@ -957,36 +964,46 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 case TIOCGLCKTRMIOS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) return -EPERM; + mutex_lock(&real_tty->termios_mutex); if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #else case TIOCGLCKTRMIOS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = -EPERM; + mutex_lock(&real_tty->termios_mutex); if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #endif #ifdef TCGETX case TCGETX: if (real_tty->termiox == NULL) return -EINVAL; + mutex_lock(&real_tty->termios_mutex); if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TCSETX: return set_termiox(real_tty, p, 0); case TCSETXW: @@ -995,10 +1012,11 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termiox(real_tty, p, TERMIOS_FLUSH); #endif case TIOCGSOFTCAR: - /* FIXME: for correctness we may need to take the termios - lock here - review */ - return put_user(C_CLOCAL(real_tty) ? 1 : 0, + mutex_lock(&real_tty->termios_mutex); + ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, (int __user *)arg); + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; -- cgit v1.2.3