| From 0c18a690c0a420b2772fcf779f0ed0c10ce58076 Mon Sep 17 00:00:00 2001 |
| From: Jiri Slaby <jslaby@suse.cz> |
| Date: Mon, 10 Feb 2020 09:11:30 +0100 |
| Subject: [PATCH] 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> |
| Cc: stable <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/r/20200210081131.23572-1-jslaby@suse.cz |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c |
| index 0233b34e49d5..d7d2e4b844bc 100644 |
| --- a/drivers/tty/vt/selection.c |
| +++ b/drivers/tty/vt/selection.c |
| @@ -30,6 +30,8 @@ |
| #include <linux/console.h> |
| #include <linux/tty_flip.h> |
| |
| +#include <linux/sched/signal.h> |
| + |
| /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ |
| #define isspace(c) ((c) == ' ') |
| |
| @@ -366,6 +368,7 @@ int paste_selection(struct tty_struct *tty) |
| unsigned int count; |
| struct tty_ldisc *ld; |
| DECLARE_WAITQUEUE(wait, current); |
| + int ret = 0; |
| |
| console_lock(); |
| poke_blanked_console(); |
| @@ -380,6 +383,10 @@ int paste_selection(struct tty_struct *tty) |
| mutex_lock(&sel_lock); |
| while (sel_buffer && sel_buffer_lth > pasted) { |
| set_current_state(TASK_INTERRUPTIBLE); |
| + if (signal_pending(current)) { |
| + ret = -EINTR; |
| + break; |
| + } |
| if (tty_throttled(tty)) { |
| mutex_unlock(&sel_lock); |
| schedule(); |
| @@ -398,6 +405,6 @@ int paste_selection(struct tty_struct *tty) |
| |
| tty_buffer_unlock_exclusive(&vc->port); |
| tty_ldisc_deref(ld); |
| - return 0; |
| + return ret; |
| } |
| EXPORT_SYMBOL_GPL(paste_selection); |
| -- |
| 2.7.4 |
| |