guc_ctl_log_params_flags() NULL-derefs guc->log.vma: the port compiled out intel_guc_log_create() but left its consumer live β instant kernel panic whenever GuC is enabled (enable_guc!=0) on Gen9+
Summary
The flags computation dereferences guc->log.vma which is ALWAYS NULL on this port (the only assignment lives in intel_guc_log_create whose sole call site is #if 0); intel_uc_init_hw calls init_params unconditionally before firmware upload - page-0 fault in both debug and release builds. Admin enabling the supported GuC feature (root-only param, default 0) gets an immediate panic at GPU init. Same dead-code-divergence family as DF-4567/4568. Guard-the-NULL fix (git-apply-verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4729 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 4.3 KB | β raw | |
| VERDICT.md | β | 4.5 KB | β raw | |
| verify.sh | β | 1.7 KB | view raw | |
| static_proof.log | β | 3.0 KB | view raw | |
| env.txt | β | 609 B | view raw | |
| fix.diff | β | 686 B | view raw | |
| verdict.json | β | 3.0 KB | view raw |
DF-4729 β intel_guc: guc_ctl_log_params_flags() NULL-derefs guc->log.vma (log buffer is never created on this port)
File: sys/dev/drm/i915/intel_guc.c β pass 2 (GLM 5.3 re-audit)
Severity: Low Β· CWE-476 Β· confidence: certain (defect), reachability gated on i915.enable_guc
What
intel_guc_init_params() (intel_guc.c:340-379) unconditionally computes
params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc) (intel_guc.c:359),
and guc_ctl_log_params_flags() (intel_guc.c:294-333) starts with:
u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; // :296
On this DragonFly port intel_guc_log_create() is compiled OUT β its only
call site is inside #if 0 at intel_guc.c:202-206 (the same #if 0 also
guts intel_guc_log_init_early, intel_guc.c:71-73). The only assignment to
log->vma in the tree is inside intel_guc_log_create()
(intel_guc_log.c:489), which is never called. drm_i915_private is
zero-initialized, so guc->log.vma == NULL forever.
intel_guc_ggtt_offset(guc, NULL) β i915_ggtt_offset(NULL)
(i915_vma.h:202-208):
GEM_BUG_ON(!i915_vma_is_ggtt(vma)); /* vma->flags β NULL deref in debug builds */
...
return lower_32_bits(vma->node.start); /* NULL+offset read in release builds */
Either way: page-0 fault β kernel panic, in the driver-load / GPU-resume
path (intel_uc_init_hw() at intel_uc.c:377 β called from
i915_gem_init_hw, i915_gem.c:5746).
Reachability (why Low, not higher)
enable_gucdefaults to 0 on this port (i915_params.h:49,param(int, enable_guc, 0));USES_GUC()is false unless root setsi915.enable_guc=1/-1(module param / loader tunable, sysctl mode 0400 β root-only). The auto-enable branch (sanitize_options_early, intel_uc.c:110-111) only fires for the auto value -1, which is not the default here.- Requires Intel Gen9+ hardware with GuC (
HAS_GUC). - With GuC enabled, the panic is unconditional and immediate at
intel_uc_init_hwβ before firmware upload even matters: there is no fw-fetch-status check beforeintel_guc_init_params(guc)(intel_uc.c:377), so even a missing firmware blob does not save it.
Threat model: an admin who enables the (advertised, supported) GuC/HuC feature gets an instant kernel panic at load/resume. Not attacker-triggerable without root. Same dead-code-divergence family as the pass-2 intel_guc_ct hardening findings (DF-4567/4568): the port disabled a subsystem's setup but left its use compiled in.
Reproduce (static proof β runnable)
Run ./verify.sh in this directory (uses only rg/sed against the repo):
intel_guc_log_createhas no live call site (only#if 0at intel_guc.c:203).log->vmais assigned nowhere else.guc_ctl_log_params_flagsdereferences it, and is called unconditionally fromintel_guc_init_paramsβintel_uc_init_hw:377βi915_gem.c:5746.i915_ggtt_offset()derefsvmain both debug and release builds.enable_gucdefault is 0 β gate.
Why not verified on the QEMU guest
The audit guest (DragonFly 6.5-DEVELOPMENT, QEMU vgapci chip=0x11111234)
has no Intel Gen9+ display device; i915 never attaches, so the GuC path
cannot be exercised. No hardware emulation knob is available to inject an
Intel GPU. Status recorded as untested (permitted enum), impact would be
panic on target hardware.
Recommended fix
Guard the flags computation on the log buffer actually existing (consistent with this port having disabled GuC logging):
--- a/sys/dev/drm/i915/intel_guc.c
+++ b/sys/dev/drm/i915/intel_guc.c
@@ -291,9 +291,15 @@ static u32 guc_ctl_debug_flags(struct intel_guc *guc)
static u32 guc_ctl_log_params_flags(struct intel_guc *guc)
{
- u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT;
+ u32 offset;
u32 flags;
+ /* The port does not create the log buffer (intel_guc_log_create
+ * is compiled out); do not hand the firmware a bogus log params
+ * dword β and do not dereference a NULL vma. */
+ if (!guc->log.vma)
+ return 0;
+
+ offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT;
+
#if (((CRASH_BUFFER_SIZE) % SZ_1M) == 0)
(Returning 0 leaves GUC_LOG_VALID unset β GuC logging disabled, which
matches the port's intent. The alternative β re-enabling
intel_guc_log_create() β requires the relay/debugfs infrastructure this
port also removed.)
VERDICT β DF-4729
- status: untested (permitted enum; contract category would be "skipped/not_testable")
- reproduced: 0 Β· impact: none (demonstrated) β would be
panicon target hardware - confidence: certain (defect logic), reachability root/config-gated
Narrative
Pass-2 audit of sys/dev/drm/i915/intel_guc.c (known: DF-1826 shared_data_vaddr
dangling β not re-reported; verified not to have a second distinct lifetime
consumer: shared_data_vaddr is read only at intel_guc_submission.c:635, which
is DF-1826's manifestation).
New finding: a dead-code divergence panic. This port compiled out the GuC
log subsystem's construction (#if 0 at intel_guc.c:71-73 and :202-206 β
intel_guc_log_init_early and intel_guc_log_create) but kept its
consumption: guc_ctl_log_params_flags() dereferences guc->log.vma
(intel_guc.c:296). log->vma is assigned in exactly one place in the tree β
intel_guc_log_create() at intel_guc_log.c:489 β which has zero live call
sites. guc->log.vma is therefore NULL for the driver's lifetime.
Call chain (all verified live):
i915_gem.c:5746 i915_gem_init_hw() [driver load / resume]
ββ intel_uc.c:377 intel_uc_init_hw() β no fw-fetch-status guard before the call
ββ intel_guc.c:359 intel_guc_init_params()
ββ intel_guc.c:296 guc_ctl_log_params_flags()
ββ intel_guc.h:137-143 intel_guc_ggtt_offset(guc, NULL)
ββ i915_vma.h:202-208 i915_ggtt_offset(NULL)
β debug GEM build: GEM_BUG_ON(!i915_vma_is_ggtt(NULL)) β vma->flags read β page-0 fault
β release build: lower_32_bits(vma->node.start) β NULL+offset read β page-0 fault
Either build panics. The panic fires before firmware upload is attempted, so even a missing firmware file does not avoid it.
Why untested (not false_positive)
The defect is statically certain (run ./verify.sh, output in
static_proof.log). It is not false_positive: the cited path is live
whenever USES_GUC() is true. It is not verified at runtime because the
audit guest has no Intel Gen9+ display device (QEMU vgapci chip=0x11111234,
see env.txt) β i915 cannot attach, and no emulation knob exists to inject
one. The trigger precondition (i915.enable_guc=1/-1, default 0 at
i915_params.h:49, root-only to set) additionally gates it behind an admin
action, which is why this is filed Low rather than High.
Exploit chain
None β configuration-gated denial of service (kernel panic at GPU init) on hardware an attacker cannot summon. No path to uid=0.
Negative results (classes hunted and killed in this file)
intel_guc_initerror unwind double-intel_uc_fw_fini: killed βintel_uc_fw_finiisfetch_and_zero-based (intel_uc_fw.c:278-287), idempotent.guc_shared_data_createpin_map-failure unwind leaking the pin: released viai915_vma_unpin_and_release(&vma, 0)(intel_guc.c:177) β the helper unconditionally unpins; no leak.intel_guc_init_paramsSOFT_SCRATCH overflow: killed βGUC_CTL_MAX_DWORDS = SOFT_SCRATCH_COUNT - 2(intel_guc_fwif.h:132), writes SOFT_SCRATCH(1..14) β SOFT_SCRATCH(0..15).intel_guc_send_mmiolen/response bounds: GEM_BUG_ON-asserted only in debug builds, butlen/response_buf_sizecome solely from in-kernel constant action arrays (this file :504/:530/:544/:561, submission, huc) β not attacker-influenced;count = min(response_buf_size, send_regs.count-1)bounds the copyout.guc->send/guc->handlerpointer swap vs in-flight send race (suspend vs execbuf): upstream design; requires GuC submission (disabled by default,enable_guc=0); no memory-safety consequence demonstrated β noted, not filed.- IRQ path
intel_guc_to_host_event_handler_mmio(intel_guc.c:462-487): irq_lock-protected read-modify-write of SOFT_SCRATCH(15), mask-bounded β clean.
Fix validation
Not possible on this guest (no target hardware): fix_status: not_testable.
fix.diff guards the flags computation on guc->log.vma != NULL, returning
0 (GuC logging disabled β consistent with the port's removal of the log
subsystem).
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
not_testablefix.diff authored (NULL guard in guc_ctl_log_params_flags) but not build-validated: no Intel Gen9+ GPU on the audit guest, so neither baseline panic nor patched behaviour can be exercised.
findings/poc/DF-4729/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-4729/static_proof.log (steps 1-8: dead call site, sole assignment, deref :296, unconditional caller :359, live chain via intel_uc.c:377 <- i915_gem.c:5746, i915_ggtt_offset deref, enable_guc=0 default); VERDICT.md (full narrative + killed candidates); verify.sh (runnable)
PoC changes
No PoC seed existed; authored a runnable static proof script (verify.sh) instead of a hardware PoC since the finding is hardware-gated.
Verified recommended fix
Guard guc_ctl_log_params_flags() to return 0 when guc->log.vma is NULL (log subsystem compiled out on this port).
Verdict
Pass-2 finding: guc_ctl_log_params_flags() (intel_guc.c:296) dereferences guc->log.vma, which is provably always NULL on this port because intel_guc_log_create()'s only call site is compiled out (#if 0, intel_guc.c:202-206) and log->vma is assigned nowhere else (intel_guc_log.c:489 is dead). intel_uc_init_hw (intel_uc.c:377) calls intel_guc_init_params unconditionally before firmware upload, so any root-enabled GuC load (i915.enable_guc=1/-1; default 0 at i915_params.h:49) on Gen9+ hardware takes i915_ggtt_offset(NULL) -> NULL deref -> kernel panic in both debug and release builds. Runtime verification impossible on the audit guest (QEMU virtual VGA chip=0x11111234, i915 never attaches); the static chain is machine-checked by verify.sh/static_proof.log. Severity Low: panic-only, hardware- and root-config-gated.
No comments yet.