diff --git a/sys/dev/misc/kbd/kbdsw.c b/sys/dev/misc/kbd/kbdsw.c --- a/sys/dev/misc/kbd/kbdsw.c +++ b/sys/dev/misc/kbd/kbdsw.c @@ -52,6 +52,24 @@ #include "kbdreg.h" +/* + * Defense-in-depth (DF-2071): only kbd_intr() previously validated + * kb_index before indexing the global kbdsw[] dispatch table. The other + * 16 dispatch shims blindly dereferenced kbdsw[kbd->kb_index], which is + * unsafe if a caller hands us a stale keyboard_t whose switch has been + * unregistered (kbdsw[i] = NULL in kbd.c:282) or whose kb_index is + * corrupt. kb_index is assigned at kbd_register() time and validated + * against KBD_MAXKEYBOARDS, but nothing prevents a buggy or racing + * caller from passing a stale pointer after kbd_unregister() clears the + * slot. The bound + non-NULL check below mirrors the guard already + * present in kbd_intr() (kbdsw.c:103). + */ +static inline bool +kbdsw_index_valid(int i) +{ + return (i >= 0 && i < KBD_MAXKEYBOARDS && kbdsw[i] != NULL); +} + int sw_probe(keyboard_switch_t *sw, int unit, void *arg, int flags) { @@ -76,6 +94,8 @@ { int error; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_ALWAYS_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->term)(kbd); if (error) @@ -114,6 +134,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->test_if)(kbd); KBD_UNLOCK(kbd); @@ -127,6 +149,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->enable)(kbd); KBD_UNLOCK(kbd); @@ -140,6 +164,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->disable)(kbd); KBD_UNLOCK(kbd); @@ -153,6 +179,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->read)(kbd, wait); KBD_UNLOCK(kbd); @@ -166,6 +194,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->check)(kbd); KBD_UNLOCK(kbd); @@ -179,6 +209,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (NOKEY); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->read_char)(kbd, wait); KBD_UNLOCK(kbd); @@ -192,6 +224,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->check_char)(kbd); KBD_UNLOCK(kbd); @@ -205,13 +239,13 @@ int error; KBD_LOCK_DECLARE; - if (kbd) { - KBD_LOCK(kbd); - error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, data); - KBD_UNLOCK(kbd); - } else { - error = ENODEV; - } + if (kbd == NULL) + return (ENODEV); + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); + KBD_LOCK(kbd); + error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, data); + KBD_UNLOCK(kbd); return (error); } @@ -221,6 +255,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->lock)(kbd, xlock); KBD_UNLOCK(kbd); @@ -233,6 +269,8 @@ { KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return; KBD_LOCK(kbd); (*kbdsw[kbd->kb_index]->clear_state)(kbd); KBD_UNLOCK(kbd); @@ -244,6 +282,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->get_state)(kbd, buf, len); KBD_UNLOCK(kbd); @@ -257,6 +297,8 @@ int error; KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); KBD_LOCK(kbd); error = (*kbdsw[kbd->kb_index]->set_state)(kbd, buf, len); KBD_UNLOCK(kbd); @@ -270,6 +312,8 @@ KBD_LOCK_DECLARE; u_char *retstr; + if (!kbdsw_index_valid(kbd->kb_index)) + return (NULL); KBD_LOCK(kbd); retstr = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, fkey, len); KBD_UNLOCK(kbd); @@ -285,6 +329,8 @@ { int error; + if (!kbdsw_index_valid(kbd->kb_index)) + return (ENODEV); if (!on) KBD_UNPOLL(kbd); error = (*kbdsw[kbd->kb_index]->poll)(kbd, on); @@ -299,6 +345,8 @@ { KBD_LOCK_DECLARE; + if (!kbdsw_index_valid(kbd->kb_index)) + return; KBD_LOCK(kbd); (*kbdsw[kbd->kb_index]->diag)(kbd, level); KBD_UNLOCK(kbd);