speakup: Fix clearing selection in safe context
speakup_cut() calls speakup_clear_selection() which calls console_lock. Problem is: speakup_cut() is called from a keyboard interrupt context. This would hang if speakup_cut is pressed while the console lock is unfortunately already held. We can however as well just defer calling clear_selection() until the already-deferred set_selection_kernel() call. This was spotted by the lock hardener: Possible unsafe locking scenario:\x0a CPU0 ---- lock(console_lock); <Interrupt> lock(console_lock); \x0a *** DEADLOCK ***\x0a [...] Call Trace: <IRQ> dump_stack+0xc2/0x11a print_usage_bug.cold+0x3e0/0x4b1 mark_lock+0xd95/0x1390 ? print_irq_inversion_bug+0xa0/0xa0 __lock_acquire+0x21eb/0x5730 ? __kasan_check_read+0x11/0x20 ? check_chain_key+0x215/0x5e0 ? register_lock_class+0x1580/0x1580 ? lock_downgrade+0x7a0/0x7a0 ? __rwlock_init+0x140/0x140 lock_acquire+0x13f/0x370 ? speakup_clear_selection+0xe/0x20 [speakup] console_lock+0x33/0x50 ? speakup_clear_selection+0xe/0x20 [speakup] speakup_clear_selection+0xe/0x20 [speakup] speakup_cut+0x19e/0x4b0 [speakup] keyboard_notifier_call+0x1f04/0x4a40 [speakup] ? read_all_doc+0x240/0x240 [speakup] notifier_call_chain+0xbf/0x130 __atomic_notifier_call_chain+0x80/0x130 atomic_notifier_call_chain+0x16/0x20 kbd_event+0x7d7/0x3b20 ? k_pad+0x850/0x850 ? sysrq_filter+0x450/0xd40 input_to_handler+0x362/0x4b0 ? rcu_read_lock_sched_held+0xe0/0xe0 input_pass_values+0x408/0x5a0 ? __rwlock_init+0x140/0x140 ? lock_acquire+0x13f/0x370 input_handle_event+0x70e/0x1380 input_event+0x67/0x90 atkbd_interrupt+0xe62/0x1d4e [atkbd] ? __kasan_check_write+0x14/0x20 ? atkbd_event_work+0x130/0x130 [atkbd] ? _raw_spin_lock_irqsave+0x26/0x70 serio_interrupt+0x93/0x120 [serio] i8042_interrupt+0x232/0x510 [i8042] ? rcu_read_lock_bh_held+0xd0/0xd0 ? handle_irq_event+0xa5/0x13a ? i8042_remove+0x1f0/0x1f0 [i8042] __handle_irq_event_percpu+0xe6/0x6c0 handle_irq_event_percpu+0x71/0x150 ? __handle_irq_event_percpu+0x6c0/0x6c0 ? __kasan_check_read+0x11/0x20 ? do_raw_spin_unlock+0x5c/0x240 handle_irq_event+0xad/0x13a handle_edge_irq+0x233/0xa90 do_IRQ+0x10b/0x310 common_interrupt+0xf/0xf </IRQ> Cc: stable@vger.kernel.org Reported-by: Jookia <contact@jookia.org> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Link: https://lore.kernel.org/r/20201107233310.7iisvaozpiqj3yvy@function Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
d7012df3c9
commit
640969a69c
|
@ -357,7 +357,6 @@ static void speakup_cut(struct vc_data *vc)
|
|||
mark_cut_flag = 0;
|
||||
synth_printf("%s\n", spk_msg_get(MSG_CUT));
|
||||
|
||||
speakup_clear_selection();
|
||||
ret = speakup_set_selection(tty);
|
||||
|
||||
switch (ret) {
|
||||
|
|
|
@ -22,13 +22,6 @@ struct speakup_selection_work {
|
|||
struct tty_struct *tty;
|
||||
};
|
||||
|
||||
void speakup_clear_selection(void)
|
||||
{
|
||||
console_lock();
|
||||
clear_selection();
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
static void __speakup_set_selection(struct work_struct *work)
|
||||
{
|
||||
struct speakup_selection_work *ssw =
|
||||
|
@ -51,6 +44,10 @@ static void __speakup_set_selection(struct work_struct *work)
|
|||
goto unref;
|
||||
}
|
||||
|
||||
console_lock();
|
||||
clear_selection();
|
||||
console_unlock();
|
||||
|
||||
set_selection_kernel(&sel, tty);
|
||||
|
||||
unref:
|
||||
|
|
|
@ -70,7 +70,6 @@ void spk_do_flush(void);
|
|||
void speakup_start_ttys(void);
|
||||
void synth_buffer_add(u16 ch);
|
||||
void synth_buffer_clear(void);
|
||||
void speakup_clear_selection(void);
|
||||
int speakup_set_selection(struct tty_struct *tty);
|
||||
void speakup_cancel_selection(void);
|
||||
int speakup_paste_selection(struct tty_struct *tty);
|
||||
|
|
Loading…
Reference in New Issue