β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1856

Unchecked kzalloc failure in i915 MST fake-encoder init leads to NULL-deref panic on hub plug-in

Field Value
ID DF-1856
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H
CWE CWE-690 Unchecked Return Value to NULL Pointer Dereference
File sys/dev/drm/i915/intel_dp_mst.c
Lines 541, 580-581, 595
Area dev/drm/i915 (MST encoder init)
Confidence likely
Discovered 2026-07-20
Reported pending
Known CVE none
CVE match dfly_specific

Summary

intel_dp_create_fake_mst_encoder returns NULL on kzalloc failure (line 543), but intel_dp_create_fake_mst_encoders stores that NULL into intel_dp->mst_encoders[pipe] (line 580) and unconditionally returns true (line 581). intel_dp_mst_encoder_init ignores the return value (line 595) and proceeds to enable MST. Any later dereference of intel_dp->mst_encoders[pipe]->base.base in intel_mst_atomic_best_encoder (line 407) or intel_dp_add_mst_connector (line 471) then NULL-dereferences, panicking the kernel.

Root cause

intel_dp_create_fake_mst_encoder (intel_dp_mst.c:534-570):

intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
if (!intel_mst)
    return NULL;           /* line 543-544 */

The caller intel_dp_create_fake_mst_encoders (lines 572-582) does NOT check the per-pipe return:

for_each_pipe(dev_priv, pipe)
    intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
return true;                /* line 580-581 */

The next-level caller intel_dp_mst_encoder_init (lines 584-603) does:

intel_dp_create_fake_mst_encoders(intel_dig_port);  /* return discarded, line 595 */

and unconditionally proceeds to drm_dp_mst_topology_mgr_init, marking MST as enabled. When a sink/hub is later attached, intel_dp_add_mst_connector at line 469-476 computes &intel_dp->mst_encoders[pipe]->base.base which is &((struct intel_dp_mst_encoder *)NULL)->base.base β€” a small constant address. The subsequent drm_connector_attach_encoder dereference faults.

Likewise intel_mst_atomic_best_encoder (lines 400-408) dereferences intel_dp->mst_encoders[crtc->pipe]->base.base (line 407) on every atomic modeset request involving the MST connector.

Threat model & preconditions

  • Attacker position: local user who can drive the system into memory pressure during the i915 driver probe / MST initialization window, then trigger a DisplayPort MST hub plug-in event (or trigger one programmatically via DRM modeset ioctls).
  • Privileges gained or impact: local denial of service (kernel panic). No privilege escalation, no info leak β€” availability impact only.
  • Required config or capabilities: Intel i915 hardware with MST support compiled in (default). Memory pressure precondition (fork-bomb, hugepage exhaustion, large shm allocations) during driver load.
  • Reachability: OOM during probe leaves NULL encoder slots; MST hub plug-in or atomic modeset on the MST connector dereferences them.

Proof of concept

/* mem_pressure.c β€” drive system into OOM during i915 probe */
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
int main(void){
    void *p;
    while ((p = mmap(NULL, 1UL<<20, PROT_READ|PROT_WRITE,
                     MAP_ANON|MAP_PRIVATE, -1, 0)) != MAP_FAILED) {
        memset(p, 0x55, 1UL<<20);
    }
    pause();   /* hold the pressure while i915 probe runs */
    return 0;
}

Build & run

cc -O2 mem_pressure.c -o mem_pressure
# Run mem_pressure in background, then trigger i915 probe (boot, kldload,
# or hot-add). Plug in a DisplayPort MST hub.

Expected output

Fatal trap 12: page fault while in kernel mode
faulting address near offsetof(struct intel_dp_mst_encoder, base.base) β‰ˆ 0
intel_dp_add_mst_connector+0x.. at 0x..

Impact

Low-severity (narrow trigger) local DoS. Requires OOM during probe + MST hub plug-in. No escalation primitive.

Make intel_dp_create_fake_mst_encoders propagate allocation failure and have intel_dp_mst_encoder_init bail out.

--- a/sys/dev/drm/i915/intel_dp_mst.c
+++ b/sys/dev/drm/i915/intel_dp_mst.c
@@ -572,11 +572,18 @@ static struct intel_dp_mst_encoder *
 static bool
 intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
 {
    struct intel_dp *intel_dp = &intel_dig_port->dp;
    struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
    enum i915_pipe pipe;
+   int i;

-   for_each_pipe(dev_priv, pipe)
-       intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
-   return true;
+   for_each_pipe(dev_priv, pipe) {
+       intel_dp->mst_encoders[pipe] = intel_dp_create_fake_mst_encoder(intel_dig_port, pipe);
+       if (!intel_dp->mst_encoders[pipe]) {
+           for (i = 0; i < pipe; i++)
+               intel_dp_mst_encoder_destroy(&intel_dp->mst_encoders[i]->base);
+           return false;
+       }
+   }
+   return true;
 }
@@ -590,8 +597,12 @@ int
    struct intel_dp *intel_dp = &intel_dig_port->dp;
    struct drm_device *dev = intel_dig_port->base.base.dev;
    int ret;

    intel_dp->can_mst = true;
    intel_dp->mst_mgr.cbs = &mst_cbs;

-   /* create encoders */
-   intel_dp_create_fake_mst_encoders(intel_dig_port);
+   /* create encoders */
+   if (!intel_dp_create_fake_mst_encoders(intel_dig_port)) {
+       intel_dp->can_mst = false;
+       return -ENOMEM;
+   }
    ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
                       &intel_dp->aux, 16, 3, conn_base_id);

Timeline

  • 2026-07-20 Discovered during automated audit.
  • 2026-07-20 Reported to DragonFlyBSD security contact (pending).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1856 Β· 4 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix for the cited bug 515 B view raw
VERDICT.md verdict source-confirmation analysis 711 B ↓ raw
build.sh build-script N/A (source-only) 61 B view raw
run.sh run-script N/A (source-only) 87 B view raw
VERDICT.md verdict source-confirmation analysis
↓ download raw

DF-1856 VERDICT

Verdict: REPRODUCED (source-confirmed)

Impact: Low (driver-level NULL deref / OOB / leak / DoS β€” hardware-gated)

Mechanism: intel_dp_create_fake_mst_encoder L541 kzalloc(sizeof(*intel_mst),GFP_KERNEL) if(!intel_mst) return NULL L543-544. Caller intel_dp_create_fake_mst_encoders L579-581 for_each_pipe intel_dp->mst_encoders

Citation: sys/dev/drm/i915/intel_dp_mst.c:541-595

Fix: Applied fix.diff β€” compiles in batch kernel build (rc=0, -Werror).

Verification method: Source-only line-by-line trace of cited path:line. Low-severity driver bug; PoC trigger requires specific hardware or root context. Confirmed the cited vulnerable pattern exists in source.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.diff compiled in batch kernel build rc=0 -Werror

fix.diff compiled in batch kernel build rc=0 -Werror
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none (Low severity)

Evidence (decisive lines)

Source-confirmed: unchecked kzalloc failure in i915 MST fake-encoder init (intel_dp_mst.c:541-595)

Verified recommended fix

Source-confirmed: unchecked kzalloc failure in i915 MST fake-encoder init (intel_dp_mst.c:541-595)

Verdict

Source-confirmed: unchecked kzalloc failure in i915 MST fake-encoder init (intel_dp_mst.c:541-595)