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

hwss1_plane_atomic_disconnect: `opp` NULL check placed after its own dereferences (dead guard, latent NULL-deref)

Summary

The function captures opp at :887, dereferences it at :889, and only afterwards tests opp!=NULL at :897 β€” dead guard. Currently unreachable (init_hw assigns stream_res.opp before its call; apply_ctx reaches the hook only for old pipes with OPP mapped). Linux v5.4 carries the byte-identical misplaced check β€” carried-in latent defect. Hoist the guard like dcn10_wait_for_mpcc_disconnect already does.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3980 Β· 5 files
FileTypeDescriptionSize
README.md β€” 1.4 KB ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
df3980_opp_order.c β€” 1.4 KB view raw
manifest.json β€” 622 B view raw
verdict.json β€” 1.8 KB view raw

DF-3980 β€” dcn10: opp NULL check placed after its dereference in hwss1_plane_atomic_disconnect (latent)

File: sys/dev/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c:889,897 Severity: Info (latent β€” currently unreachable; upstream-identical) Hardware: DCN10 β€” absent from the audit guest; source-level certainty.

hwss1_plane_atomic_disconnect() reads pipe_ctx->stream_res.opp into a local at :887, dereferences it at :889 (&(opp->mpc_tree_params), then get_mpcc_for_dpp/remove_mpcc on that pointer), and only afterwards tests if (opp != NULL) at :897 before touching it again. The check is dead code: it can never protect the earlier dereferences.

Unreachable today: the two callers both guarantee a non-NULL OPP β€” dcn10_init_hw sets pipe_ctx->stream_res.opp = dc->res_pool->opps[i] (:1076) immediately before invoking the hook (:1078), and dcn10_apply_ctx_for_surface calls it only for old pipes that had a plane attached (:2387-2391), which by resource mapping have stream_res.opp assigned. Upstream Linux v5.4 carries byte-identical code, so a future caller that relaxes the invariant trips the NULL deref.

Fix: hoist the check to the top of the function (if (opp == NULL) return;) β€” matching the style of dcn10_wait_for_mpcc_disconnect's if (!pipe_ctx->stream_res.opp) return; (:2579-2580).

Files

  • df3980_opp_order.c β€” documentation stub
  • VERDICT.md, manifest.json, verdict.json
VERDICT.md
↓ download raw

DF-3980 β€” VERDICT

Status: inconclusive (hardware-gated β€” no DCN10 GPU on the audit guest; additionally the defect is unreachable by construction today), source certainty only.

Root cause: hwss1_plane_atomic_disconnect() at sys/dev/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c:889 dereferences opp (&(opp->mpc_tree_params) and subsequent get_mpcc_for_dpp / remove_mpcc through that pointer) before the NULL guard at :897 (if (opp != NULL)), which is therefore dead. If any future caller invokes the hook with pipe_ctx->stream_res.opp == NULL, the kernel NULL-derefs at :889.

Current callers (both safe): 1. dcn10_init_hw :1078 β€” assigns pipe_ctx->stream_res.opp at :1076 first. 2. dcn10_apply_ctx_for_surface :2391 β€” only for old pipes with old_pipe_ctx->plane_state set (:2387), which have OPP resources mapped.

Upstream parity: Linux v5.4 hwss1_plane_atomic_disconnect is byte-identical in this respect (deref at its :986, dead check at :994) β€” a carried-in latent defect, not a port regression.

Fix: hoist if (opp == NULL) return; to the top of the function (same pattern as dcn10_wait_for_mpcc_disconnect :2579-2580 in this file).

Classification rationale: Info β€” latent NULL-deref, no reachable trigger today, no memory corruption; filed as hardening with the exact one-line fix.

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Info hardening finding; no fix validation applicable (no hardware, unreachable path).

n/a
per-fix-DF-3980

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md: caller-by-caller safety proof + upstream v5.4 byte-identical comparison.

PoC changes

n/a (documentation stub only)

Verified recommended fix

Hoist if (opp == NULL) return; to the top of hwss1_plane_atomic_disconnect (pattern already used by dcn10_wait_for_mpcc_disconnect :2579).

Verdict

hwss1_plane_atomic_disconnect dereferences stream_res.opp at dcn10_hw_sequencer.c:889 and only tests it for NULL afterwards at :897, so the guard is dead. Both current callers guarantee non-NULL (dcn10_init_hw assigns opp at :1076 before the :1078 call; dcn10_apply_ctx_for_surface only reaches the hook for old planes with mapped OPP resources at :2387-2391), and Linux v5.4 carries the identical misplaced check, so this is a latent carried-in defect rather than a port regression. No DCN10 GPU on the audit guest and no reachable trigger by construction: no runtime demonstration possible; Info hardening with a one-line fix (hoist the NULL check).