diff options
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r-- | drivers/char/tty_ioctl.c | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 6f4c7d0a53bf..8116bb1c8f80 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer); | |||
97 | * @tty: terminal | 97 | * @tty: terminal |
98 | * | 98 | * |
99 | * Indicate that a tty should stop transmitting data down the stack. | 99 | * Indicate that a tty should stop transmitting data down the stack. |
100 | * Takes the termios mutex to protect against parallel throttle/unthrottle | ||
101 | * and also to ensure the driver can consistently reference its own | ||
102 | * termios data at this point when implementing software flow control. | ||
100 | */ | 103 | */ |
101 | 104 | ||
102 | void tty_throttle(struct tty_struct *tty) | 105 | void tty_throttle(struct tty_struct *tty) |
103 | { | 106 | { |
107 | mutex_lock(&tty->termios_mutex); | ||
104 | /* check TTY_THROTTLED first so it indicates our state */ | 108 | /* check TTY_THROTTLED first so it indicates our state */ |
105 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && | 109 | if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && |
106 | tty->ops->throttle) | 110 | tty->ops->throttle) |
107 | tty->ops->throttle(tty); | 111 | tty->ops->throttle(tty); |
112 | mutex_unlock(&tty->termios_mutex); | ||
108 | } | 113 | } |
109 | EXPORT_SYMBOL(tty_throttle); | 114 | EXPORT_SYMBOL(tty_throttle); |
110 | 115 | ||
@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle); | |||
113 | * @tty: terminal | 118 | * @tty: terminal |
114 | * | 119 | * |
115 | * Indicate that a tty may continue transmitting data down the stack. | 120 | * Indicate that a tty may continue transmitting data down the stack. |
121 | * Takes the termios mutex to protect against parallel throttle/unthrottle | ||
122 | * and also to ensure the driver can consistently reference its own | ||
123 | * termios data at this point when implementing software flow control. | ||
124 | * | ||
125 | * Drivers should however remember that the stack can issue a throttle, | ||
126 | * then change flow control method, then unthrottle. | ||
116 | */ | 127 | */ |
117 | 128 | ||
118 | void tty_unthrottle(struct tty_struct *tty) | 129 | void tty_unthrottle(struct tty_struct *tty) |
119 | { | 130 | { |
131 | mutex_lock(&tty->termios_mutex); | ||
120 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && | 132 | if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && |
121 | tty->ops->unthrottle) | 133 | tty->ops->unthrottle) |
122 | tty->ops->unthrottle(tty); | 134 | tty->ops->unthrottle(tty); |
135 | mutex_unlock(&tty->termios_mutex); | ||
123 | } | 136 | } |
124 | EXPORT_SYMBOL(tty_unthrottle); | 137 | EXPORT_SYMBOL(tty_unthrottle); |
125 | 138 | ||
@@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) | |||
613 | return 0; | 626 | return 0; |
614 | } | 627 | } |
615 | 628 | ||
629 | static void copy_termios(struct tty_struct *tty, struct ktermios *kterm) | ||
630 | { | ||
631 | mutex_lock(&tty->termios_mutex); | ||
632 | memcpy(kterm, tty->termios, sizeof(struct ktermios)); | ||
633 | mutex_unlock(&tty->termios_mutex); | ||
634 | } | ||
635 | |||
636 | static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) | ||
637 | { | ||
638 | mutex_lock(&tty->termios_mutex); | ||
639 | memcpy(kterm, tty->termios_locked, sizeof(struct ktermios)); | ||
640 | mutex_unlock(&tty->termios_mutex); | ||
641 | } | ||
642 | |||
616 | static int get_termio(struct tty_struct *tty, struct termio __user *termio) | 643 | static int get_termio(struct tty_struct *tty, struct termio __user *termio) |
617 | { | 644 | { |
618 | if (kernel_termios_to_user_termio(termio, tty->termios)) | 645 | struct ktermios kterm; |
646 | copy_termios(tty, &kterm); | ||
647 | if (kernel_termios_to_user_termio(termio, &kterm)) | ||
619 | return -EFAULT; | 648 | return -EFAULT; |
620 | return 0; | 649 | return 0; |
621 | } | 650 | } |
@@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
917 | struct tty_struct *real_tty; | 946 | struct tty_struct *real_tty; |
918 | void __user *p = (void __user *)arg; | 947 | void __user *p = (void __user *)arg; |
919 | int ret = 0; | 948 | int ret = 0; |
949 | struct ktermios kterm; | ||
950 | struct termiox ktermx; | ||
920 | 951 | ||
921 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 952 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
922 | tty->driver->subtype == PTY_TYPE_MASTER) | 953 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
952 | return set_termios(real_tty, p, TERMIOS_OLD); | 983 | return set_termios(real_tty, p, TERMIOS_OLD); |
953 | #ifndef TCGETS2 | 984 | #ifndef TCGETS2 |
954 | case TCGETS: | 985 | case TCGETS: |
955 | mutex_lock(&real_tty->termios_mutex); | 986 | copy_termios(real_tty, &kterm); |
956 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | 987 | if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) |
957 | ret = -EFAULT; | 988 | ret = -EFAULT; |
958 | mutex_unlock(&real_tty->termios_mutex); | ||
959 | return ret; | 989 | return ret; |
960 | #else | 990 | #else |
961 | case TCGETS: | 991 | case TCGETS: |
962 | mutex_lock(&real_tty->termios_mutex); | 992 | copy_termios(real_tty, &kterm); |
963 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) | 993 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) |
964 | ret = -EFAULT; | 994 | ret = -EFAULT; |
965 | mutex_unlock(&real_tty->termios_mutex); | ||
966 | return ret; | 995 | return ret; |
967 | case TCGETS2: | 996 | case TCGETS2: |
968 | mutex_lock(&real_tty->termios_mutex); | 997 | copy_termios(real_tty, &kterm); |
969 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) | 998 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) |
970 | ret = -EFAULT; | 999 | ret = -EFAULT; |
971 | mutex_unlock(&real_tty->termios_mutex); | ||
972 | return ret; | 1000 | return ret; |
973 | case TCSETSF2: | 1001 | case TCSETSF2: |
974 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); | 1002 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); |
@@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
987 | return set_termios(real_tty, p, TERMIOS_TERMIO); | 1015 | return set_termios(real_tty, p, TERMIOS_TERMIO); |
988 | #ifndef TCGETS2 | 1016 | #ifndef TCGETS2 |
989 | case TIOCGLCKTRMIOS: | 1017 | case TIOCGLCKTRMIOS: |
990 | mutex_lock(&real_tty->termios_mutex); | 1018 | copy_termios_locked(real_tty, &kterm); |
991 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) | 1019 | if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) |
992 | ret = -EFAULT; | 1020 | ret = -EFAULT; |
993 | mutex_unlock(&real_tty->termios_mutex); | ||
994 | return ret; | 1021 | return ret; |
995 | case TIOCSLCKTRMIOS: | 1022 | case TIOCSLCKTRMIOS: |
996 | if (!capable(CAP_SYS_ADMIN)) | 1023 | if (!capable(CAP_SYS_ADMIN)) |
997 | return -EPERM; | 1024 | return -EPERM; |
998 | mutex_lock(&real_tty->termios_mutex); | 1025 | copy_termios_locked(real_tty, &kterm); |
999 | if (user_termios_to_kernel_termios(real_tty->termios_locked, | 1026 | if (user_termios_to_kernel_termios(&kterm, |
1000 | (struct termios __user *) arg)) | 1027 | (struct termios __user *) arg)) |
1001 | ret = -EFAULT; | 1028 | return -EFAULT; |
1029 | mutex_lock(&real_tty->termios_mutex); | ||
1030 | memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); | ||
1002 | mutex_unlock(&real_tty->termios_mutex); | 1031 | mutex_unlock(&real_tty->termios_mutex); |
1003 | return ret; | 1032 | return 0; |
1004 | #else | 1033 | #else |
1005 | case TIOCGLCKTRMIOS: | 1034 | case TIOCGLCKTRMIOS: |
1006 | mutex_lock(&real_tty->termios_mutex); | 1035 | copy_termios_locked(real_tty, &kterm); |
1007 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) | 1036 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) |
1008 | ret = -EFAULT; | 1037 | ret = -EFAULT; |
1009 | mutex_unlock(&real_tty->termios_mutex); | ||
1010 | return ret; | 1038 | return ret; |
1011 | case TIOCSLCKTRMIOS: | 1039 | case TIOCSLCKTRMIOS: |
1012 | if (!capable(CAP_SYS_ADMIN)) | 1040 | if (!capable(CAP_SYS_ADMIN)) |
1013 | ret = -EPERM; | 1041 | return -EPERM; |
1014 | mutex_lock(&real_tty->termios_mutex); | 1042 | copy_termios_locked(real_tty, &kterm); |
1015 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, | 1043 | if (user_termios_to_kernel_termios_1(&kterm, |
1016 | (struct termios __user *) arg)) | 1044 | (struct termios __user *) arg)) |
1017 | ret = -EFAULT; | 1045 | return -EFAULT; |
1046 | mutex_lock(&real_tty->termios_mutex); | ||
1047 | memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); | ||
1018 | mutex_unlock(&real_tty->termios_mutex); | 1048 | mutex_unlock(&real_tty->termios_mutex); |
1019 | return ret; | 1049 | return ret; |
1020 | #endif | 1050 | #endif |
@@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1023 | if (real_tty->termiox == NULL) | 1053 | if (real_tty->termiox == NULL) |
1024 | return -EINVAL; | 1054 | return -EINVAL; |
1025 | mutex_lock(&real_tty->termios_mutex); | 1055 | mutex_lock(&real_tty->termios_mutex); |
1026 | if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) | 1056 | memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox)); |
1027 | ret = -EFAULT; | ||
1028 | mutex_unlock(&real_tty->termios_mutex); | 1057 | mutex_unlock(&real_tty->termios_mutex); |
1058 | if (copy_to_user(p, &ktermx, sizeof(struct termiox))) | ||
1059 | ret = -EFAULT; | ||
1029 | return ret; | 1060 | return ret; |
1030 | case TCSETX: | 1061 | case TCSETX: |
1031 | return set_termiox(real_tty, p, 0); | 1062 | return set_termiox(real_tty, p, 0); |
@@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1035 | return set_termiox(real_tty, p, TERMIOS_FLUSH); | 1066 | return set_termiox(real_tty, p, TERMIOS_FLUSH); |
1036 | #endif | 1067 | #endif |
1037 | case TIOCGSOFTCAR: | 1068 | case TIOCGSOFTCAR: |
1038 | mutex_lock(&real_tty->termios_mutex); | 1069 | copy_termios(real_tty, &kterm); |
1039 | ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, | 1070 | ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, |
1040 | (int __user *)arg); | 1071 | (int __user *)arg); |
1041 | mutex_unlock(&real_tty->termios_mutex); | ||
1042 | return ret; | 1072 | return ret; |
1043 | case TIOCSSOFTCAR: | 1073 | case TIOCSSOFTCAR: |
1044 | if (get_user(arg, (unsigned int __user *) arg)) | 1074 | if (get_user(arg, (unsigned int __user *) arg)) |