# 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)