When allocating a new keyboard at vt_upgrade() time, unwind any cngrabs

done on the old keyboard and then do the corresponding number of grabs
on the new keyboard.

This fixes a race that can leave the system with a non-functioning
keyboard.  It goes like this...

 - The bios claims there is an AT keyboard, atkbd attaches.
 - SI_SUB_INT_CONFIG_HOOKS runs.
 - USB probes devices. Devices begin attaching, including disks.
 - GELI prompts for a password for a just-attached disk, which results
   in a cngrab() while atkbd is the keyboard.
 - A USB keyboard attaches.
 - vt_upgrade() runs and switches the keyboard to the new USB keyboard,
   but because cngrab was never called for it, it's not activated and
   keystrokes are ignored.
 - Now there is no functional keyboard and no way to get one; even
   plugging in a different USB keyboard doesn't help, because the console
   is still grabbed, still waiting for a GELI pw.

Discussed with:	     ray@
This commit is contained in:
ian 2018-12-31 01:09:23 +00:00
parent 8e6a06102c
commit 17962d0222

View File

@ -977,10 +977,22 @@ vt_kbdevent(keyboard_t *kbd, int event, void *arg)
static int
vt_allocate_keyboard(struct vt_device *vd)
{
int idx0, idx;
int grabbed, i, idx0, idx;
keyboard_t *k0, *k;
keyboard_info_t ki;
/*
* If vt_upgrade() happens while the console is grabbed, we are
* potentially going to switch keyboard devices while the keyboard is in
* use. Unwind the grabbing of the current keyboard first, then we will
* re-grab the new keyboard below, before we return.
*/
if (vd->vd_curwindow == &vt_conswindow) {
grabbed = vd->vd_curwindow->vw_grabbed;
for (i = 0; i < grabbed; ++i)
vtterm_cnungrab(vd->vd_curwindow->vw_terminal);
}
idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd);
if (idx0 >= 0) {
DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
@ -1012,6 +1024,11 @@ vt_allocate_keyboard(struct vt_device *vd)
vd->vd_keyboard = idx0;
DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
if (vd->vd_curwindow == &vt_conswindow) {
for (i = 0; i < grabbed; ++i)
vtterm_cngrab(vd->vd_curwindow->vw_terminal);
}
return (idx0);
}