β¬’ 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 1.0 KB ↓ raw
build.sh build-script N/A (source-only) 65 B view raw
run.sh run-script N/A (source-only) 89 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 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.

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)