⬢ DragonFlyBSD Kernel Audit
DF-5324 / fix.diff
← back to finding ↓ download raw
--- 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);
 }