⬢ DragonFlyBSD Kernel Audit
DF-2209 / fix.diff
← back to finding ↓ download raw
# DF-2208 + DF-2209 combined fix (same file, same two functions).
#
# DF-2208: drm_sysfs_connector_add() dereferenced kzalloc() and stored
# kasprintf() results without NULL checks and reported success
# unconditionally. With the checks in place a failed allocation returns
# -ENOMEM so drm_connector_register() (drm_connector.c:444-446) fails
# loudly instead of publishing a half-built connector device.
#
# DF-2209: drm_sysfs_connector_remove() left connector->kdev dangling
# after kfree(), so the `if (connector->kdev) return 0;` guard in
# drm_sysfs_connector_add() (drm_sysfs.c:35-36) turns any
# re-registration into a silent no-op returning success while every
# consumer (intel_dp.c:5251,5253, intel_sdvo.c:2198) operates on freed
# memory. NULLing the pointer closes the stale-pointer window; freeing
# the kasprintf'd name fixes the per-cycle string leak seen in the rig.
#
# NOTE (audit): on DragonFly GFP_KERNEL is M_WAITOK|M_CACHEALIGN
# (sys/dev/drm/include/linux/gfp.h:16) and _kmalloc() without M_NULLOK
# panics or blocks rather than returning NULL (sys/kern/kern_slaballoc.c:
# 869-878, 1722-1724, 1786-1800), so the DF-2208 NULL returns model the
# Linux OOM window; the checks are still correct hardening for the file
# as written and match the kvasprintf() NULL discipline the DFly drm
# shim itself already implements (drm_dragonfly.c:78-79).
--- a/sys/dev/drm/drm_sysfs.c
+++ b/sys/dev/drm/drm_sysfs.c
@@ -37,9 +37,16 @@
 
 	/* Linux uses device_create_with_groups() here */
 	connector->kdev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!connector->kdev)
+		return -ENOMEM;
 	connector->kdev->kobj.name = kasprintf(GFP_KERNEL, "card%d-%s",
 					       dev->primary->index,
 					       connector->name);
+	if (!connector->kdev->kobj.name) {
+		kfree(connector->kdev);
+		connector->kdev = NULL;
+		return -ENOMEM;
+	}
 	DRM_DEBUG("adding \"%s\" to sysfs\n", connector->name);
 
 	return 0;
@@ -49,8 +56,11 @@
 {
 	DRM_DEBUG("removing \"%s\" from sysfs\n", connector->name);
 
-	if (connector->kdev)
+	if (connector->kdev) {
+		kfree(connector->kdev->kobj.name);
 		kfree(connector->kdev);
+		connector->kdev = NULL;
+	}
 }
 
 void drm_sysfs_hotplug_event(struct drm_device *dev)