summaryrefslogtreecommitdiff
path: root/drivers/tty/tty_io.c (follow)
Commit message (Collapse)AuthorAge
* tty: Fix data race between tiocsti() and flush_to_ldisc()Nguyen Dinh Phi2021-09-22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | commit bb2853a6a421a052268eee00fd5d3f6b3504b2b1 upstream. The ops->receive_buf() may be accessed concurrently from these two functions. If the driver flushes data to the line discipline receive_buf() method while tiocsti() is waiting for the ops->receive_buf() to finish its work, the data race will happen. For example: tty_ioctl |tty_ldisc_receive_buf ->tioctsi | ->tty_port_default_receive_buf | ->tty_ldisc_receive_buf ->hci_uart_tty_receive | ->hci_uart_tty_receive ->h4_recv | ->h4_recv In this case, the h4 receive buffer will be overwritten by the latecomer, and we will lost the data. Hence, change tioctsi() function to use the exclusive lock interface from tty_buffer to avoid the data race. Reported-by: syzbot+97388eb9d31b997fe1d0@syzkaller.appspotmail.com Reviewed-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com> Link: https://lore.kernel.org/r/20210823000641.2082292-1-phind.uet@gmail.com Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: fix return value for unsupported ioctlsJohan Hovold2021-05-22
| | | | | | | | | | | | | | | | | | | | | [ Upstream commit 1b8b20868a6d64cfe8174a21b25b74367bdf0560 ] Drivers should return -ENOTTY ("Inappropriate I/O control operation") when an ioctl isn't supported, while -EINVAL is used for invalid arguments. Fix up the TIOCMGET, TIOCMSET and TIOCGICOUNT helpers which returned -EINVAL when a tty driver did not implement the corresponding operations. Note that the TIOCMGET and TIOCMSET helpers predate git and do not get a corresponding Fixes tag below. Fixes: d281da7ff6f7 ("tty: Make tiocgicount a handler") Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20210407095208.31838-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
* tty: Fix ->session lockingJann Horn2020-12-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | commit c8bcd9c5be24fb9e6132e97da5a35e55a83e36b9 upstream. Currently, locking of ->session is very inconsistent; most places protect it using the legacy tty mutex, but disassociate_ctty(), __do_SAK(), tiocspgrp() and tiocgsid() don't. Two of the writers hold the ctrl_lock (because they already need it for ->pgrp), but __proc_set_tty() doesn't do that yet. On a PREEMPT=y system, an unprivileged user can theoretically abuse this broken locking to read 4 bytes of freed memory via TIOCGSID if tiocgsid() is preempted long enough at the right point. (Other things might also go wrong, especially if root-only ioctls are involved; I'm not sure about that.) Change the locking on ->session such that: - tty_lock() is held by all writers: By making disassociate_ctty() hold it. This should be fine because the same lock can already be taken through the call to tty_vhangup_session(). The tricky part is that we need to shorten the area covered by siglock to be able to take tty_lock() without ugly retry logic; as far as I can tell, this should be fine, since nothing in the signal_struct is touched in the `if (tty)` branch. - ctrl_lock is held by all writers: By changing __proc_set_tty() to hold the lock a little longer. - All readers that aren't holding tty_lock() hold ctrl_lock: By adding locking to tiocgsid() and __do_SAK(), and expanding the area covered by ctrl_lock in tiocspgrp(). Cc: stable@kernel.org Signed-off-by: Jann Horn <jannh@google.com> Reviewed-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Fix ->pgrp locking in tiocspgrp()Jann Horn2020-12-11
| | | | | | | | | | | | | | | | | | | | | commit 54ffccbf053b5b6ca4f6e45094b942fab92a25fc upstream. tiocspgrp() takes two tty_struct pointers: One to the tty that userspace passed to ioctl() (`tty`) and one to the TTY being changed (`real_tty`). These pointers are different when ioctl() is called with a master fd. To properly lock real_tty->pgrp, we must take real_tty->ctrl_lock. This bug makes it possible for racing ioctl(TIOCSPGRP, ...) calls on both sides of a PTY pair to corrupt the refcount of `struct pid`, leading to use-after-free errors. Fixes: 47f86834bbd4 ("redo locking of tty->pgrp") CC: stable@kernel.org Signed-off-by: Jann Horn <jannh@google.com> Reviewed-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: ldisc: add sysctl to prevent autoloading of ldiscsGreg Kroah-Hartman2019-04-27
| | | | | | | | | | | | | | | | | commit 7c0cca7c847e6e019d67b7d793efbbe3b947d004 upstream. By default, the kernel will automatically load the module of any line dicipline that is asked for. As this sometimes isn't the safest thing to do, provide a sysctl to disable this feature. By default, we set this to 'y' as that is the historical way that Linux has worked, and we do not want to break working systems. But in the future, perhaps this can default to 'n' to prevent this functionality. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Handle problem if line discipline does not have receive_bufGreg Kroah-Hartman2019-02-06
| | | | | | | | | | | | | commit 27cfb3a53be46a54ec5e0bd04e51995b74c90343 upstream. Some tty line disciplines do not have a receive buf callback, so properly check for that before calling it. If they do not have this callback, just eat the character quietly, as we can't fail this call. Reported-by: Jann Horn <jannh@google.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: check name length in tty_find_polling_driver()Miles Chen2018-11-21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | [ Upstream commit 33a1a7be198657c8ca26ad406c4d2a89b7162bcc ] The issue is found by a fuzzing test. If tty_find_polling_driver() recevies an incorrect input such as ',,' or '0b', the len becomes 0 and strncmp() always return 0. In this case, a null p->ops->poll_init() is called and it causes a kernel panic. Fix this by checking name length against zero in tty_find_polling_driver(). $echo ,, > /sys/module/kgdboc/parameters/kgdboc [ 20.804451] WARNING: CPU: 1 PID: 104 at drivers/tty/serial/serial_core.c:457 uart_get_baud_rate+0xe8/0x190 [ 20.804917] Modules linked in: [ 20.805317] CPU: 1 PID: 104 Comm: sh Not tainted 4.19.0-rc7ajb #8 [ 20.805469] Hardware name: linux,dummy-virt (DT) [ 20.805732] pstate: 20000005 (nzCv daif -PAN -UAO) [ 20.805895] pc : uart_get_baud_rate+0xe8/0x190 [ 20.806042] lr : uart_get_baud_rate+0xc0/0x190 [ 20.806476] sp : ffffffc06acff940 [ 20.806676] x29: ffffffc06acff940 x28: 0000000000002580 [ 20.806977] x27: 0000000000009600 x26: 0000000000009600 [ 20.807231] x25: ffffffc06acffad0 x24: 00000000ffffeff0 [ 20.807576] x23: 0000000000000001 x22: 0000000000000000 [ 20.807807] x21: 0000000000000001 x20: 0000000000000000 [ 20.808049] x19: ffffffc06acffac8 x18: 0000000000000000 [ 20.808277] x17: 0000000000000000 x16: 0000000000000000 [ 20.808520] x15: ffffffffffffffff x14: ffffffff00000000 [ 20.808757] x13: ffffffffffffffff x12: 0000000000000001 [ 20.809011] x11: 0101010101010101 x10: ffffff880d59ff5f [ 20.809292] x9 : ffffff880d59ff5e x8 : ffffffc06acffaf3 [ 20.809549] x7 : 0000000000000000 x6 : ffffff880d59ff5f [ 20.809803] x5 : 0000000080008001 x4 : 0000000000000003 [ 20.810056] x3 : ffffff900853e6b4 x2 : dfffff9000000000 [ 20.810693] x1 : ffffffc06acffad0 x0 : 0000000000000cb0 [ 20.811005] Call trace: [ 20.811214] uart_get_baud_rate+0xe8/0x190 [ 20.811479] serial8250_do_set_termios+0xe0/0x6f4 [ 20.811719] serial8250_set_termios+0x48/0x54 [ 20.811928] uart_set_options+0x138/0x1bc [ 20.812129] uart_poll_init+0x114/0x16c [ 20.812330] tty_find_polling_driver+0x158/0x200 [ 20.812545] configure_kgdboc+0xbc/0x1bc [ 20.812745] param_set_kgdboc_var+0xb8/0x150 [ 20.812960] param_attr_store+0xbc/0x150 [ 20.813160] module_attr_store+0x40/0x58 [ 20.813364] sysfs_kf_write+0x8c/0xa8 [ 20.813563] kernfs_fop_write+0x154/0x290 [ 20.813764] vfs_write+0xf0/0x278 [ 20.813951] __arm64_sys_write+0x84/0xf4 [ 20.814400] el0_svc_common+0xf4/0x1dc [ 20.814616] el0_svc_handler+0x98/0xbc [ 20.814804] el0_svc+0x8/0xc [ 20.822005] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [ 20.826913] Mem abort info: [ 20.827103] ESR = 0x84000006 [ 20.827352] Exception class = IABT (current EL), IL = 16 bits [ 20.827655] SET = 0, FnV = 0 [ 20.827855] EA = 0, S1PTW = 0 [ 20.828135] user pgtable: 4k pages, 39-bit VAs, pgdp = (____ptrval____) [ 20.828484] [0000000000000000] pgd=00000000aadee003, pud=00000000aadee003, pmd=0000000000000000 [ 20.829195] Internal error: Oops: 84000006 [#1] SMP [ 20.829564] Modules linked in: [ 20.829890] CPU: 1 PID: 104 Comm: sh Tainted: G W 4.19.0-rc7ajb #8 [ 20.830545] Hardware name: linux,dummy-virt (DT) [ 20.830829] pstate: 60000085 (nZCv daIf -PAN -UAO) [ 20.831174] pc : (null) [ 20.831457] lr : serial8250_do_set_termios+0x358/0x6f4 [ 20.831727] sp : ffffffc06acff9b0 [ 20.831936] x29: ffffffc06acff9b0 x28: ffffff9008d7c000 [ 20.832267] x27: ffffff900969e16f x26: 0000000000000000 [ 20.832589] x25: ffffff900969dfb0 x24: 0000000000000000 [ 20.832906] x23: ffffffc06acffad0 x22: ffffff900969e160 [ 20.833232] x21: 0000000000000000 x20: ffffffc06acffac8 [ 20.833559] x19: ffffff900969df90 x18: 0000000000000000 [ 20.833878] x17: 0000000000000000 x16: 0000000000000000 [ 20.834491] x15: ffffffffffffffff x14: ffffffff00000000 [ 20.834821] x13: ffffffffffffffff x12: 0000000000000001 [ 20.835143] x11: 0101010101010101 x10: ffffff880d59ff5f [ 20.835467] x9 : ffffff880d59ff5e x8 : ffffffc06acffaf3 [ 20.835790] x7 : 0000000000000000 x6 : ffffff880d59ff5f [ 20.836111] x5 : c06419717c314100 x4 : 0000000000000007 [ 20.836419] x3 : 0000000000000000 x2 : 0000000000000000 [ 20.836732] x1 : 0000000000000001 x0 : ffffff900969df90 [ 20.837100] Process sh (pid: 104, stack limit = 0x(____ptrval____)) [ 20.837396] Call trace: [ 20.837566] (null) [ 20.837816] serial8250_set_termios+0x48/0x54 [ 20.838089] uart_set_options+0x138/0x1bc [ 20.838570] uart_poll_init+0x114/0x16c [ 20.838834] tty_find_polling_driver+0x158/0x200 [ 20.839119] configure_kgdboc+0xbc/0x1bc [ 20.839380] param_set_kgdboc_var+0xb8/0x150 [ 20.839658] param_attr_store+0xbc/0x150 [ 20.839920] module_attr_store+0x40/0x58 [ 20.840183] sysfs_kf_write+0x8c/0xa8 [ 20.840183] sysfs_kf_write+0x8c/0xa8 [ 20.840440] kernfs_fop_write+0x154/0x290 [ 20.840702] vfs_write+0xf0/0x278 [ 20.840942] __arm64_sys_write+0x84/0xf4 [ 20.841209] el0_svc_common+0xf4/0x1dc [ 20.841471] el0_svc_handler+0x98/0xbc [ 20.841713] el0_svc+0x8/0xc [ 20.842057] Code: bad PC value [ 20.842764] ---[ end trace a8835d7de79aaadf ]--- [ 20.843134] Kernel panic - not syncing: Fatal exception [ 20.843515] SMP: stopping secondary CPUs [ 20.844289] Kernel Offset: disabled [ 20.844634] CPU features: 0x0,21806002 [ 20.844857] Memory Limit: none [ 20.845172] ---[ end Kernel panic - not syncing: Fatal exception ]--- Signed-off-by: Miles Chen <miles.chen@mediatek.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Don't call panic() at tty_ldisc_init()Tetsuo Handa2018-05-02
| | | | | | | | | | | | | | | | | | | commit 903f9db10f18f735e62ba447147b6c434b6af003 upstream. syzbot is reporting kernel panic [1] triggered by memory allocation failure at tty_ldisc_get() from tty_ldisc_init(). But since both tty_ldisc_get() and caller of tty_ldisc_init() can cleanly handle errors, tty_ldisc_init() does not need to call panic() when tty_ldisc_get() failed. [1] https://syzkaller.appspot.com/bug?id=883431818e036ae6a9981156a64b821110f39187 Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reported-by: syzbot <syzkaller@googlegroups.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jslaby@suse.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: make n_tty_read() always abort if hangup is in progressTejun Heo2018-04-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | commit 28b0f8a6962a24ed21737578f3b1b07424635c9e upstream. A tty is hung up by __tty_hangup() setting file->f_op to hung_up_tty_fops, which is skipped on ttys whose write operation isn't tty_write(). This means that, for example, /dev/console whose write op is redirected_tty_write() is never actually marked hung up. Because n_tty_read() uses the hung up status to decide whether to abort the waiting readers, the lack of hung-up marking can lead to the following scenario. 1. A session contains two processes. The leader and its child. The child ignores SIGHUP. 2. The leader exits and starts disassociating from the controlling terminal (/dev/console). 3. __tty_hangup() skips setting f_op to hung_up_tty_fops. 4. SIGHUP is delivered and ignored. 5. tty_ldisc_hangup() is invoked. It wakes up the waits which should clear the read lockers of tty->ldisc_sem. 6. The reader wakes up but because tty_hung_up_p() is false, it doesn't abort and goes back to sleep while read-holding tty->ldisc_sem. 7. The leader progresses to tty_ldisc_lock() in tty_ldisc_hangup() and is now stuck in D sleep indefinitely waiting for tty->ldisc_sem. The following is Alan's explanation on why some ttys aren't hung up. http://lkml.kernel.org/r/20171101170908.6ad08580@alans-desktop 1. It broke the serial consoles because they would hang up and close down the hardware. With tty_port that *should* be fixable properly for any cases remaining. 2. The console layer was (and still is) completely broken and doens't refcount properly. So if you turn on console hangups it breaks (as indeed does freeing consoles and half a dozen other things). As neither can be fixed quickly, this patch works around the problem by introducing a new flag, TTY_HUPPING, which is used solely to tell n_tty_read() that hang-up is in progress for the console and the readers should be aborted regardless of the hung-up status of the device. The following is a sample hung task warning caused by this issue. INFO: task agetty:2662 blocked for more than 120 seconds. Not tainted 4.11.3-dbg-tty-lockup-02478-gfd6c7ee-dirty #28 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. 0 2662 1 0x00000086 Call Trace: __schedule+0x267/0x890 schedule+0x36/0x80 schedule_timeout+0x23c/0x2e0 ldsem_down_write+0xce/0x1f6 tty_ldisc_lock+0x16/0x30 tty_ldisc_hangup+0xb3/0x1b0 __tty_hangup+0x300/0x410 disassociate_ctty+0x6c/0x290 do_exit+0x7ef/0xb00 do_group_exit+0x3f/0xa0 get_signal+0x1b3/0x5d0 do_signal+0x28/0x660 exit_to_usermode_loop+0x46/0x86 do_syscall_64+0x9c/0xb0 entry_SYSCALL64_slow_path+0x25/0x25 The following is the repro. Run "$PROG /dev/console". The parent process hangs in D state. #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include <time.h> #include <termios.h> int main(int argc, char **argv) { struct sigaction sact = { .sa_handler = SIG_IGN }; struct timespec ts1s = { .tv_sec = 1 }; pid_t pid; int fd; if (argc < 2) { fprintf(stderr, "test-hung-tty /dev/$TTY\n"); return 1; } /* fork a child to ensure that it isn't already the session leader */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { /* top parent, wait for everyone */ while (waitpid(-1, NULL, 0) >= 0) ; if (errno != ECHILD) perror("waitpid"); return 0; } /* new session, start a new session and set the controlling tty */ if (setsid() < 0) { perror("setsid"); return 1; } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (ioctl(fd, TIOCSCTTY, 1) < 0) { perror("ioctl"); return 1; } /* fork a child, sleep a bit and exit */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { nanosleep(&ts1s, NULL); printf("Session leader exiting\n"); exit(0); } /* * The child ignores SIGHUP and keeps reading from the controlling * tty. Because SIGHUP is ignored, the child doesn't get killed on * parent exit and the bug in n_tty makes the read(2) block the * parent's control terminal hangup attempt. The parent ends up in * D sleep until the child is explicitly killed. */ sigaction(SIGHUP, &sact, NULL); printf("Child reading tty\n"); while (1) { char buf[1024]; if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); return 1; } } return 0; } Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Alan Cox <alan@llwyncelyn.cymru> Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* pty: cancel pty slave port buf's work in tty_releaseSahara2018-03-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | [ Upstream commit 2b022ab7542df60021ab57854b3faaaf42552eaf ] In case that CONFIG_SLUB_DEBUG is on and pty is used, races between release_one_tty and flush_to_ldisc work threads may happen and lead to use-after-free condition on tty->link->port. Because SLUB_DEBUG is turned on, freed tty->link->port is filled with POISON_FREE value. So far without SLUB_DEBUG, port was filled with zero and flush_to_ldisc could return without a problem by checking if tty is NULL. CPU 0 CPU 1 ----- ----- release_tty pty_write cancel_work_sync(tty) to = tty->link tty_kref_put(tty->link) tty_schedule_flip(to->port) << workqueue >> ... release_one_tty ... pty_cleanup ... kfree(tty->link->port) << workqueue >> flush_to_ldisc tty = READ_ONCE(port->itty) tty is 0x6b6b6b6b6b6b6b6b !!PANIC!! access tty->ldisc Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b6b93 pgd = ffffffc0eb1c3000 [6b6b6b6b6b6b6b93] *pgd=0000000000000000, *pud=0000000000000000 ------------[ cut here ]------------ Kernel BUG at ffffff800851154c [verbose debug info unavailable] Internal error: Oops - BUG: 96000004 [#1] PREEMPT SMP CPU: 3 PID: 265 Comm: kworker/u8:9 Tainted: G W 3.18.31-g0a58eeb #1 Hardware name: Qualcomm Technologies, Inc. MSM 8996pro v1.1 + PMI8996 Carbide (DT) Workqueue: events_unbound flush_to_ldisc task: ffffffc0ed610ec0 ti: ffffffc0ed624000 task.ti: ffffffc0ed624000 PC is at ldsem_down_read_trylock+0x0/0x4c LR is at tty_ldisc_ref+0x24/0x4c pc : [<ffffff800851154c>] lr : [<ffffff800850f6c0>] pstate: 80400145 sp : ffffffc0ed627cd0 x29: ffffffc0ed627cd0 x28: 0000000000000000 x27: ffffff8009e05000 x26: ffffffc0d382cfa0 x25: 0000000000000000 x24: ffffff800a012f08 x23: 0000000000000000 x22: ffffffc0703fbc88 x21: 6b6b6b6b6b6b6b6b x20: 6b6b6b6b6b6b6b93 x19: 0000000000000000 x18: 0000000000000001 x17: 00e80000f80d6f53 x16: 0000000000000001 x15: 0000007f7d826fff x14: 00000000000000a0 x13: 0000000000000000 x12: 0000000000000109 x11: 0000000000000000 x10: 0000000000000000 x9 : ffffffc0ed624000 x8 : ffffffc0ed611580 x7 : 0000000000000000 x6 : ffffff800a42e000 x5 : 00000000000003fc x4 : 0000000003bd1201 x3 : 0000000000000001 x2 : 0000000000000001 x1 : ffffff800851004c x0 : 6b6b6b6b6b6b6b93 Signed-off-by: Sahara <keun-o.park@darkmatter.ae> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Drop krefs for interrupted tty lockPeter Hurley2017-06-14
| | | | | | | | | | | | | | | | commit e9036d0662360cd4c79578565ce422ed5872f301 upstream. When the tty lock is interrupted on attempted re-open, 2 tty krefs are still held. Drop extra kref before returning failure from tty_lock_interruptible(), and drop lookup kref before returning failure from tty_open(). Fixes: 0bfd464d3fdd ("tty: Wait interruptibly for tty lock on reopen") Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Cc: Jiri Slaby <jslaby@suse.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Fix unsafe ldisc reference via ioctl(TIOCGETD)Peter Hurley2016-02-17
| | | | | | | | | | | | | | | | | | | | commit 5c17c861a357e9458001f021a7afa7aab9937439 upstream. ioctl(TIOCGETD) retrieves the line discipline id directly from the ldisc because the line discipline id (c_line) in termios is untrustworthy; userspace may have set termios via ioctl(TCSETS*) without actually changing the line discipline via ioctl(TIOCSETD). However, directly accessing the current ldisc via tty->ldisc is unsafe; the ldisc ptr dereferenced may be stale if the line discipline is changing via ioctl(TIOCSETD) or hangup. Wait for the line discipline reference (just like read() or write()) to retrieve the "current" line discipline id. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Retry failed reopen if tty teardown in-progressPeter Hurley2016-02-17
| | | | | | | | | | | | | | | | | | commit 7f22f6c935cda600660e623a411fe380015d28d9 upstream. A small window exists where a tty reopen will observe the tty just prior to imminent teardown (tty->count == 0); in this case, open() returns EIO to userspace. Instead, retry the open after checking for signals and yielding; this interruptible retry loop allows teardown to commence and initialize a new tty on retry. Never retry the BSD master pty reopen; there is no guarantee the pty pair teardown is imminent since the slave file descriptors may remain open indefinitely. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Wait interruptibly for tty lock on reopenPeter Hurley2016-02-17
| | | | | | | | | | | | commit 0bfd464d3fdd5bb322f9cace4cc47f1796545cf7 upstream. Allow a signal to interrupt the wait for a tty reopen; eg., if the tty has starting final close and is waiting for the device to drain. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Fix tty_send_xchar() lock order inversionPeter Hurley2015-11-20
| | | | | | | | | | | The correct lock order is atomic_write_lock => termios_rwsem, as established by tty_write() => n_tty_write(). Fixes: c274f6ef1c666 ("tty: Hold termios_rwsem for tcflow(TCIxxx)") Reported-and-Tested-by: Dmitry Vyukov <dvyukov@google.com> Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Abstract tty buffer workPeter Hurley2015-10-17
| | | | | | | | Introduce API functions to restart and cancel tty buffer work, rather than manipulate buffer work directly. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Prevent tty teardown during tty_write_message()Peter Hurley2015-10-17
| | | | | | | | | | | | tty_write_message() allows the caller to directly write to a specific tty. Since the line discipline is bypassed for the direct write, nothing prevents the tty from being torn down after the tty count is checked. Hold the tty lock for the duration of the direct write. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: core: Use correct spinlock flavor in tiocspgrp()Peter Hurley2015-10-17
| | | | | | | | | tiocspgrp() is the ioctl handler for TIOCSPGRP, which runs in non-atomic context; use spin_lock/unlock_irq (since interrupt state is on). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Combine SIGTTOU/SIGTTIN handlingPeter Hurley2015-10-17
| | | | | | | | | | | | | | The job_control() check in n_tty_read() has nearly identical purpose and results as tty_check_change(). Both functions' purpose is to determine if the current task's pgrp is the foreground pgrp for the tty, and if not, to signal the current pgrp. Introduce __tty_check_change() which takes the signal to send and performs the shared operations for job control() and tty_check_change(). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* drivers/tty: require read access for controlling terminalJann Horn2015-10-04
| | | | | | | | | This is mostly a hardening fix, given that write-only access to other users' ttys is usually only given through setgid tty executables. Signed-off-by: Jann Horn <jann@thejh.net> Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: don't leak cdev in tty_cdev_add()Leon Yu2015-10-04
| | | | | | | | | | | | | | | | Commit a3a10ce3429e ("Avoid usb reset crashes by making tty_io cdevs truly dynamic") which mixes using cdev_alloc() and cdev_init() is problematic. Subsequent call to cdev_init() after cdev_alloc() sets kobj release method from cdev_dynamic_release() to cdev_default_release() and thus makes it impossible to free allocated cdev. This patch also consolidates error path of cdev_add() as cdev can also leak here if things went wrong. Signed-off-by: Leon Yu <chianglungyu@gmail.com> Fixes: a3a10ce3429e ("Avoid usb reset crashes by making tty_io cdevs truly dynamic") Acked-by: Richard Watts <rrw@kynesim.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* Avoid usb reset crashes by making tty_io cdevs truly dynamicRichard Watts2015-08-03
| | | | | | | | Avoid usb reset crashes by making tty_io cdevs truly dynamic Signed-off-by: Richard Watts <rrw@kynesim.co.uk> Reported-by: Duncan Mackintosh <DMackintosh@cbnl.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Replace #ifdef TTY_DEBUG_HANGUP with tty_debug_hangup()Peter Hurley2015-07-23
| | | | | | | | Add tty_debug_hangup() macro which uses tty_debug to print the debug message; remove inlined #ifdefs. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: core: Add tty_debug() for printk(KERN_DEBUG) messagesPeter Hurley2015-07-23
| | | | | | | | | | | Introduce tty_debug() macro to output uniform debug information for tty core debug messages (function name and tty name). Note: printk(KERN_DEBUG) is retained here over pr_debug() since messages can be enabled in non-DEBUG builds. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: core: Improve debug message contentPeter Hurley2015-07-23
| | | | | | | | | Output the function name, tty name, and invariant failure (if applicable). Add the tty count to the tty_open() message. Fix the disassociate_ctty() message, which printed the NULL pointer and the wrong message. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: add missing rcu_read_lock for task_pgrpPatrick Donnelly2015-07-23
| | | | | | | | | | task_pgrp requires an rcu or tasklist lock to be obtained if the returned pid is to be dereferenced, which kill_pgrp does. Obtain an RCU lock for the duration of use. Signed-off-by: Patrick Donnelly <batrick@batbytes.com> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: remove buf parameter from tty_name()Rasmus Villemoes2015-05-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | tty_name no longer uses the buf parameter, so remove it along with all the 64 byte stack buffers that used to be passed in. Mostly generated by the coccinelle script @depends on patch@ identifier buf; constant C; expression tty; @@ - char buf[C]; <+... - tty_name(tty, buf) + tty_name(tty) ...+> allmodconfig compiles, so I'm fairly confident the stack buffers weren't used for other purposes as well. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Jesper Nilsson <jesper.nilsson@axis.com> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: return tty->name directly from tty_nameRasmus Villemoes2015-05-06
| | | | | | | | | | | All users of tty_name pass the return value (the provided buffer) to some printf-like function. We can thus avoid the strcpy and, more importantly, later remove the buf parameter completely, eliminating the need for some 64 byte stack buffers. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: constify return type of tty_nameRasmus Villemoes2015-05-06
| | | | | | | | | | | | | | All users of tty_name pass the result directly to a printf-like function. This means we can actually let tty_name return the literal "NULL tty" or tty->name directly, avoiding the strcpy and a lot of medium-sized stack buffers. In preparation for that, make the return type const char*. While at it, we can also constify the tty parameter. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: clean up the tty time logic a bitGreg Kroah-Hartman2015-03-26
| | | | | | | | | | We only care if anything other than the lower 3 bits of the tty has changed, so just check that way, which makes it a bit faster, and more obvious what is going on. Also, document this for future developers to understand why we did this. Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
* tty: Use static attribute groups for sysfs entriesTakashi Iwai2015-03-26
| | | | | | | | | Instead of manual calls of device_create_file() and device_remove_file(), pass the static attribute groups using device_create_with_groups(). Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: fix up atime/mtime mess, take fourJiri Slaby2015-03-07
| | | | | | | | | | | | | | | | | | | | | | | | | | | | This problem was taken care of three times already in * b0de59b5733d18b0d1974a060860a8b5c1b36a2e (TTY: do not update atime/mtime on read/write), * 37b7f3c76595e23257f61bd80b223de8658617ee (TTY: fix atime/mtime regression), and * b0b885657b6c8ef63a46bc9299b2a7715d19acde (tty: fix up atime/mtime mess, take three) But it still misses one point. As John Paul correctly points out, we do not care about setting date. If somebody ever changes wall time backwards (by mistake for example), tty timestamps are never updated until the original wall time passes. So check the absolute difference of times and if it large than "8 seconds or so", always update the time. That means we will update immediatelly when changing time. Ergo, CAP_SYS_TIME can foul the check, but it was always that way. Thanks John for serving me this so nicely debugged. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Reported-by: John Paul Perry <john_paul.perry@alcatel-lucent.com> Cc: <stable@vger.kernel.org> # all, as b0b885657 was backported Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Prevent hw state corruption in exclusive mode reopenPeter Hurley2015-01-09
| | | | | | | | | | | | | Exclusive mode ttys (TTY_EXCLUSIVE) do not allow further reopens; fail the condition before associating the file pointer and calling the driver open() method. Prevents DTR programming when the tty is already in exclusive mode. Reported-by: Shreyas Bethur <shreyas.bethur@ni.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Shreyas Bethur <shreyas.bethur@ni.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Deletion of unnecessary checks before two function callsMarkus Elfring2014-11-26
| | | | | | | | | | | The functions put_device() and tty_kref_put() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring <elfring@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: warn on deprecated serial flagsJiri Slaby2014-11-06
| | | | | | | | | | | | | | | | | When somebody calls TIOCSSERIAL ioctl with serial flags to set one of * ASYNC_SESSION_LOCKOUT * ASYNC_PGRP_LOCKOUT * ASYNC_CALLOUT_NOHUP * ASYNC_AUTOPROBE nothing happens. We actually ignore the flags for over a decade at least (I checked 2.6.0). So start yelling at users who use those flags, that they shouldn't. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Peter Hurley <peter@hurleysoftware.com> Cc: Alan Cox <gnomes@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Call methods in modern stylePeter Hurley2014-11-05
| | | | | | | | The use of older function ptr calling style, (*fn)(), makes static analysis more error-prone; replace with modern fn() style. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* tty: Replace open-coded test with tty_hung_up_p()Peter Hurley2014-11-05
| | | | | | | tty_hung_up_p() is equivalent to the open-coded test in tty_open(). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* Merge branch 'tty-linus' into 'tty-testing'Greg Kroah-Hartman2014-11-05
|\ | | | | | | | | | | | | We need the fixes in drivers/tty/tty_io.c that were done in there for future patches in this branch. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| * tty: Prevent "read/write wait queue active!" log floodingPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | Only print one warning when a task is on the read_wait or write_wait wait queue at final tty release. Cc: <stable@vger.kernel.org> # 3.4.x+ Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| * tty: Fix high cpu load if tty is unreleaseablePeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Kernel oops can cause the tty to be unreleaseable (for example, if n_tty_read() crashes while on the read_wait queue). This will cause tty_release() to endlessly loop without sleeping. Use a killable sleep timeout which grows by 2n+1 jiffies over the interval [0, 120 secs.) and then jumps to forever (but still killable). NB: killable just allows for the task to be rewoken manually, not to be terminated. Cc: <stable@vger.kernel.org> # since before 2.6.32 Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Flush ldisc buffer atomically with tty flip buffersPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | tty_ldisc_flush() first clears the line discipline input buffer, then clears the tty flip buffers. However, this allows for existing data in the tty flip buffers to be added after the ldisc input buffer has been cleared, but before the flip buffers have been cleared. Add an optional ldisc parameter to tty_buffer_flush() to allow tty_ldisc_flush() to pass the ldisc to clear. NB: Initially, the plan was to do this automatically in tty_buffer_flush(). However, an audit of the behavior of existing line disciplines showed that performing a ldisc buffer flush on ioctl(TCFLSH) was not always the outcome. For example, some line disciplines have flush_buffer() methods but not ioctl() methods, so a ->flush_buffer() command would be unexpected. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Change tty lock order to master->slavePeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When releasing the master pty, the slave pty also needs to be locked to prevent concurrent tty count changes for the slave pty and to ensure that only one parallel master and slave release observe the final close, and proceed to destruct the pty pair. Conversely, when releasing the slave pty, locking the master pty is not necessary (since the master's state can be inferred by the slave tty count). Introduce tty_lock_slave()/tty_unlock_slave() which acquires/releases the tty lock of the slave pty. Remove tty_lock_pair()/tty_unlock_pair(). Dropping the tty_lock is no longer required to re-establish a stable lock order. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Simplify tty_release() state checksPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | The local o_tty variable in tty_release() is now accessed only when closing the pty master. Set o_tty to slave pty when closing pty master, otherwise NULL; use o_tty != NULL as replacement for pty_master. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Simplify tty_release_checks() interfacePeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | Passing the 'other' tty to tty_release_checks() only makes sense for a pty pair; make o_tty scope local instead. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Simplify tty_ldisc_release() interfacePeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | Passing the 'other' tty to tty_ldisc_release() only makes sense for a pty pair; make o_tty function local instead. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Fold pty pair handling into tty_flush_works()Peter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | Perform work flush for both ends of a pty pair within tty_flush_works(), rather than calling twice. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Simplify pty pair teardown logicPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When the slave side closes and its tty count is 0, the pty pair can be destroyed; the master side must have already closed for the slave side tty count to be 0. Thus, only the pty master close must check if the slave side has closed by checking the slave tty count. Remove the pre-computed closing flags and check the actual count(s). Regular ttys are unaffected by this change. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Document check_tty_count() requires tty_lock heldPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Holding the tty_lock() is necessary to prevent concurrent changes to the tty count that may cause it to differ from the open file list count. The tty_lock() is already held at all call sites. NB: Note that the check for the pty master tty count is safe because the slave's tty_lock() is held while decrementing the pty master tty count. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Don't release tty locks for wait queue sanity checkPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Releasing the tty locks while waiting for the tty wait queues to be empty is no longer necessary nor desirable. Prior to "tty: Don't take tty_mutex for tty count changes", dropping the tty locks was necessary to reestablish the correct lock order between tty_mutex and the tty locks. Dropping the global tty_mutex was necessary; otherwise new ttys could not have been opened while waiting. However, without needing the global tty_mutex held, the tty locks for the releasing tty can now be held through the sleep. The sanity check is for abnormal conditions caused by kernel bugs, not for recoverable errors caused by misbehaving userspace; dropping the tty locks only allows the tty state to get more sideways. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* | tty: Don't take tty_mutex for tty count changesPeter Hurley2014-11-05
| | | | | | | | | | | | | | | | | | | | Holding tty_mutex is no longer required to serialize changes to the tty_count or to prevent concurrent opens of closing ttys; tty_lock() is sufficient. Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>