⬢ DragonFlyBSD Kernel Audit
DF-2962 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_kobj.c	2026-06-29 12:51:19.000000000 +0000
+++ b/sys/kern/subr_kobj.c	2026-10-26 00:25:42.789042927 +0000
@@ -135,11 +135,15 @@
 }
 
 static kobj_method_t *
-kobj_lookup_method_mi(kobj_class_t cls, kobjop_desc_t desc)
+kobj_lookup_method_mi(kobj_class_t cls, kobjop_desc_t desc, int depth)
 {
 	kobj_method_t *ce;
 	kobj_class_t *basep;
 
+	/* cycle guard: cyclic baseclass graphs must not recurse forever */
+	if (depth > 8)
+		return(NULL);
+
 	ce = kobj_lookup_method_class(cls, desc);
 	if (ce)
 		return(ce);
@@ -147,7 +151,7 @@
 	basep = cls->baseclasses;
 	if (basep) {
 		for (; *basep; basep++) {
-			ce = kobj_lookup_method_mi(*basep, desc);
+			ce = kobj_lookup_method_mi(*basep, desc, depth + 1);
 			if (ce)
 				return(ce);
 		}
@@ -163,7 +167,7 @@
 {
 	kobj_method_t *ce;
 
-	ce = kobj_lookup_method_mi(cls, desc);
+	ce = kobj_lookup_method_mi(cls, desc, 0);
 	if (!ce)
 		ce = &desc->deflt;
 	*cep = ce;
@@ -256,6 +260,13 @@
 void
 kobj_init(kobj_t obj, kobj_class_t cls)
 {
+	/*
+	 * Re-initializing an already-initialized object used to leak a
+	 * permanent class reference (pinning a KLD class forever).
+	 * Release the previous reference instead.
+	 */
+	if (obj->ops != NULL)
+		kobj_class_uninstantiate(obj->ops->cls);
 	kobj_class_instantiate(cls);
 	obj->ops = cls->ops;
 }
@@ -263,7 +274,10 @@
 void
 kobj_delete(kobj_t obj, struct malloc_type *mtype)
 {
-	kobj_class_t cls = obj->ops->cls;
+	kobj_class_t cls;
+
+	KKASSERT(obj->ops != NULL);
+	cls = obj->ops->cls;
 
 	kobj_class_uninstantiate(cls);