--- a/sys/dev/misc/kbd/kbdsw.c +++ b/sys/dev/misc/kbd/kbdsw.c @@ -71,13 +71,37 @@ return (error); } +/* + * DF-5324: a console-side consumer can hold a keyboard_t pointer across a + * driver detach (e.g. ukbd unplug -> kbd_unregister() clears + * kbdsw[kb->kb_index] and the softc is freed). Validate kb_index and the + * kbdsw[] slot before every dispatch, mirroring the defensive pattern + * kbd_intr() already uses. The remaining window (softc freed and the slab + * reused between check and call) requires proper keyboard reference + * counting and is not closed by this change. + */ +static keyboard_switch_t * +kbdsw_check(keyboard_t *kbd) +{ + int i = kbd->kb_index; + + if (i < 0 || i >= KBD_MAXKEYBOARDS || kbdsw[i] == NULL) + return (NULL); + return (kbdsw[i]); +} + int kbd_term(keyboard_t *kbd) { int error; + keyboard_switch_t *sw; + KBD_ALWAYS_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->term)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->term)(kbd); + else + error = ENODEV; if (error) KBD_ALWAYS_UNLOCK(kbd); /* kbd structure is stale if error is 0 */ @@ -113,9 +137,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->test_if)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->test_if)(kbd); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -126,9 +154,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->enable)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->enable)(kbd); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -139,9 +171,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->disable)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->disable)(kbd); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -152,9 +188,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->read)(kbd, wait); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->read)(kbd, wait); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -165,9 +205,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->check)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->check)(kbd); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -178,9 +222,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->read_char)(kbd, wait); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->read_char)(kbd, wait); + else + error = NOKEY; KBD_UNLOCK(kbd); return (error); @@ -191,9 +239,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->check_char)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->check_char)(kbd); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -205,9 +257,14 @@ int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; + if (kbd) { KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, data); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->ioctl)(kbd, cmd, data); + else + error = ENODEV; KBD_UNLOCK(kbd); } else { error = ENODEV; @@ -220,9 +277,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->lock)(kbd, xlock); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->lock)(kbd, xlock); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -233,8 +294,11 @@ { KBD_LOCK_DECLARE; + keyboard_switch_t *sw; + KBD_LOCK(kbd); - (*kbdsw[kbd->kb_index]->clear_state)(kbd); + if ((sw = kbdsw_check(kbd)) != NULL) + (*sw->clear_state)(kbd); KBD_UNLOCK(kbd); } @@ -243,9 +307,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->get_state)(kbd, buf, len); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->get_state)(kbd, buf, len); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -256,9 +324,13 @@ { int error; KBD_LOCK_DECLARE; + keyboard_switch_t *sw; KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->set_state)(kbd, buf, len); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->set_state)(kbd, buf, len); + else + error = ENODEV; KBD_UNLOCK(kbd); return (error); @@ -270,8 +342,13 @@ KBD_LOCK_DECLARE; u_char *retstr; + keyboard_switch_t *sw; + KBD_LOCK(kbd); - retstr = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, fkey, len); + if ((sw = kbdsw_check(kbd)) != NULL) + retstr = (*sw->get_fkeystr)(kbd, fkey, len); + else + retstr = NULL; KBD_UNLOCK(kbd); return (retstr); @@ -285,9 +362,14 @@ { int error; + keyboard_switch_t *sw; + if (!on) KBD_UNPOLL(kbd); - error = (*kbdsw[kbd->kb_index]->poll)(kbd, on); + if ((sw = kbdsw_check(kbd)) != NULL) + error = (*sw->poll)(kbd, on); + else + error = ENODEV; if (on) KBD_POLL(kbd); @@ -299,7 +381,10 @@ { KBD_LOCK_DECLARE; + keyboard_switch_t *sw; + KBD_LOCK(kbd); - (*kbdsw[kbd->kb_index]->diag)(kbd, level); + if ((sw = kbdsw_check(kbd)) != NULL) + (*sw->diag)(kbd, level); KBD_UNLOCK(kbd); }