| From: Jiri Slaby <jslaby@suse.cz> |
| Date: Mon, 10 Feb 2020 09:11:30 +0100 |
| Subject: vt: selection, handle pending signals in paste_selection |
| |
| commit 687bff0cd08f790d540cfb7b2349f0d876cdddec upstream. |
| |
| When pasting a selection to a vt, the task is set as INTERRUPTIBLE while |
| waiting for a tty to unthrottle. But signals are not handled at all. |
| Normally, this is not a problem as tty_ldisc_receive_buf receives all |
| the goods and a user has no reason to interrupt the task. |
| |
| There are two scenarios where this matters: |
| 1) when the tty is throttled and a signal is sent to the process, it |
| spins on a CPU until the tty is unthrottled. schedule() does not |
| really echedule, but returns immediately, of course. |
| 2) when the sel_buffer becomes invalid, KASAN prevents any reads from it |
| and the loop simply does not proceed and spins forever (causing the |
| tty to throttle, but the code never sleeps, the same as above). This |
| sometimes happens as there is a race in the sel_buffer handling code. |
| |
| So add signal handling to this ioctl (TIOCL_PASTESEL) and return -EINTR |
| in case a signal is pending. |
| |
| Signed-off-by: Jiri Slaby <jslaby@suse.cz> |
| Link: https://lore.kernel.org/r/20200210081131.23572-1-jslaby@suse.cz |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| [bwh: Backported to 3.16: |
| - No need to include <linux/sched/signal.h> |
| - Adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/drivers/tty/vt/selection.c |
| +++ b/drivers/tty/vt/selection.c |
| @@ -341,6 +341,7 @@ int paste_selection(struct tty_struct *t |
| unsigned int count; |
| struct tty_ldisc *ld; |
| DECLARE_WAITQUEUE(wait, current); |
| + int ret = 0; |
| |
| console_lock(); |
| poke_blanked_console(); |
| @@ -352,6 +353,10 @@ int paste_selection(struct tty_struct *t |
| add_wait_queue(&vc->paste_wait, &wait); |
| while (sel_buffer && sel_buffer_lth > pasted) { |
| set_current_state(TASK_INTERRUPTIBLE); |
| + if (signal_pending(current)) { |
| + ret = -EINTR; |
| + break; |
| + } |
| if (test_bit(TTY_THROTTLED, &tty->flags)) { |
| schedule(); |
| continue; |
| @@ -367,5 +372,5 @@ int paste_selection(struct tty_struct *t |
| |
| tty_buffer_unlock_exclusive(&vc->port); |
| tty_ldisc_deref(ld); |
| - return 0; |
| + return ret; |
| } |