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