# DF-4879 VERDICT — `drm_mode_config_init()` ignores property-creation failure

**Status: untested** (source-proven; not runnable on this guest — no DRM
device, no fault injection). **Impact if manifested: local kernel panic
(DoS), Low.** Not memory corruption (read-only NULL derefs).

## The defect (certain, source)

`sys/dev/drm/drm_mode_config.c:392`

```c
void drm_mode_config_init(struct drm_device *dev)
{
        ...
        drm_mode_create_standard_properties(dev);   /* ret discarded */
```

`drm_mode_create_standard_properties()` (same file, 212-356) creates
~20 properties through `drm_connector_create_standard_properties()`
(line 217) and then `drm_property_create_{range,signed_range,object,bool}`
/ `drm_property_create` calls (lines 221-353). Each returns NULL on
allocation failure; the helper bails with `-ENOMEM` at the first NULL.
On a mid-way failure the earlier `dev->mode_config.*_property` pointers
are set and the rest stay NULL (struct comes from kzalloc'd drm_device).

The failure is invisible to all three in-tree callers, which treat init
as infallible:

* `sys/dev/drm/i915/intel_display.c:15342` — `drm_mode_config_init(dev);`
* `sys/dev/drm/radeon/radeon_display.c:1579` — `drm_mode_config_init(rdev->ddev);`
* `sys/dev/drm/amd/amdgpu/amdgpu_device.c:2604` — `drm_mode_config_init(adev->ddev);`

## Propagation to NULL pointers stored in objects (certain)

`drm_universal_plane_init()` attaches the standard properties to every
plane without NULL checks — `sys/dev/drm/drm_plane.c:262-275`:

```c
        drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
        drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
        drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
        drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
        ...
```

`drm_object_attach_property()` (drm_mode_object.c) performs no NULL
validation. Atomic CRTC init attaches `config->prop_active` /
`config->prop_mode_id` the same way (`sys/dev/drm/drm_crtc.c:339-341`).
radeon marks `mode_config_initialized = true` unconditionally after init
(radeon_display.c:1580), i.e. even a half-failed init proceeds to
full registration (`drm_modeset_register_all()`).

## Unprivileged sink (certain reachability once state exists)

`drm_mode_object_get_properties()` — `sys/dev/drm/drm_mode_object.c:341-346`:

```c
        for (i = 0, count = 0; i < obj->properties->count; i++) {
                struct drm_property *prop = obj->properties->properties[i];
                ...
                if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)   /* NULL deref */
```

Reached from:
* `DRM_IOCTL_MODE_OBJ_GETPROPERTIES` → `drm_mode_obj_get_properties_ioctl()`
  (drm_mode_object.c:382-407), registered `DRM_UNLOCKED|DRM_RENDER_ALLOW`
  — **no authentication, render-node allowed** (drm_ioctl.c:678).
* `DRM_IOCTL_MODE_GETCONNECTOR` → drm_connector.c:1820.

Trigger: open /dev/dri/card0 (or renderD128), GETPLANERESOURCES /
GETRESOURCES to learn any plane/crtc/connector id, then
MODE_OBJ_GETPROPERTIES on it with count_props>0 → `prop->flags` read at
NULL+offset → kernel page fault → panic. All subsequent uses
(`__drm_object_property_get_value` at 296-304 compares pointers, then
`prop->base.id` at 353) are reads too — no write primitive, no kernel
memory disclosure (if the attacker mapped page zero, the reads return
their own bytes). DoS only.

## Why not reproduced on the guest

1. Guest has no DRM device: `/dev/dri` does not exist (QEMU std VGA;
   no i915/radeon/amdgpu attaches), so the trigger ioctl has no target.
2. The setup precondition (`-ENOMEM` inside
   `drm_mode_create_standard_properties` during driver load) cannot be
   forced: the guest has no memory-allocation fault-injection knob, and
   the DRM drivers cannot be meaningfully loaded without their GPUs.
3. Verified live on guest `dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54
   UTC 2026`: `ls -l /dev/dri/` → `No such file or directory`.

Classification: real defect, upstream-inherited, Low severity
("narrow trigger, requires already-privileged setup" per rubric).
Fix is cheap and local (see fix.diff): propagate the error.

## Fix validation

Not possible on this guest (same reasons as above) —
`fix_status: not_testable`. The diff is compile-logic-equivalent to
upstream's `drmm_mode_config_init()` handling (which fails device init
when standard property creation fails).

## Guest state notes (unrelated findings live-checked this run)

* `/dev/nvmm` does not exist on this guest: `kldload nvmm` loads
  nvmm.ko but MOD_LOAD fails with `nvmm: cpu not supported`
  (nvmm_dragonfly.c: `nvmm_ident() == NULL` — QEMU CPU exposes no
  SVM/VMX), `module_register_init: MOD_LOAD (nvmm) error 45`.
  When the backend does attach, the node is created `root:nvmm 0640`
  (nvmm_dragonfly.c:392) → NVMM is not an unprivileged surface by
  default (only root or members of group `nvmm` gid 90 can open it).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
