dc_link_ddc: unchecked dal_ddc_aux/i2c_payloads_create() NULL in dal_ddc_service_query_ddc_data β OOM-gated (and zero-size-deterministic) NULL deref
Summary
Both create results are dereferenced via payloads_get (reads container at offset 0) with no NULL check; the creators return NULL on kzalloc OOM or when the vector ctor rejects capacity==0 (deterministic when both sizes are 0 - no in-tree caller does). OOM-gated panic during DDC transactions on AMD DC hardware. DF-4555's still-unfixed ignored-acquire at :655 confirmed present and deliberately not re-filed (already claimed, fix.diff covers it). NULL-check fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4663 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.5 KB | β raw | |
| VERDICT.md | β | 2.5 KB | β raw | |
| fix.diff | β | 651 B | view raw | |
| run.log | β | 329 B | view raw | |
| env.txt | β | 329 B | view raw | |
| manifest.json | β | 627 B | view raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-4663 β dc_link_ddc: unchecked payloads_create() NULL in dal_ddc_service_query_ddc_data
dal_ddc_service_query_ddc_data() (dc_link_ddc.c:552-633) calls
dal_ddc_aux_payloads_create(ddc->ctx, payloads_num) (:580-581) or
dal_ddc_i2c_payloads_create(...) (:606-607) and immediately dereferences
the result via dal_ddc_aux_payloads_get(payloads) (:584) /
dal_ddc_i2c_payloads_get(payloads) (:610) β reading
payloads->payloads.container (offset 0, include/vector.h:29-35) β with no
NULL check.
Both creators return NULL when:
* the 16-byte kzalloc fails (GFP_KERNEL, OOM), or
* dal_vector_construct() rejects capacity == 0 (basics/vector.c:33-37)
β i.e. whenever write_size == 0 && read_size == 0 β or its kcalloc
fails.
The zero-size case is not reachable from the current in-tree callers (all pass non-empty write or read sizes: dc_link_ddc.c:712-754 SCDC, dc_link.c:1641/1694 retimer (1,1)), so today this is an OOM-gated latent NULL-deref panic inside the amdgpu display driver. Filed as hardening (defense-in-depth; the sibling engine paths DF-4555-series showed this subsystem's allocation/error discipline is security-relevant).
Run / verification
Hardware-gated: the code only executes on an AMD DC GPU. The audit guest
has none β pciconf -l | grep -c 1002 = 0 (run.log / env.txt), Bochs
VGA only. Not reproducible there; defect is code-provable (cited lines).
Fix
fix.diff (git-apply verified): check both create results, return false
on failure β consistent with the file's own bound check at :573-574.
DF-4663 β VERDICT
not_reproduced (hardware-gated) β Info-severity hardening finding; defect code-provable.
Root cause (certain, from source)
dal_ddc_service_query_ddc_data (sys/dev/drm/amd/display/dc/core/dc_link_ddc.c:552):
580: struct aux_payloads *payloads =
581: dal_ddc_aux_payloads_create(ddc->ctx, payloads_num);
...
584: .payloads = dal_ddc_aux_payloads_get(payloads), /* NULL->payloads.container */
and the i2c twin at :606-610. dal_ddc_aux_payloads_create (:170-185)
returns NULL when kzalloc(sizeof(struct aux_payloads)) fails or when
dal_vector_construct fails β which it deterministically does for
capacity == 0 (if (!struct_size || !capacity) ... return false,
basics/vector.c:33-37, i.e. write_size == 0 && read_size == 0) and when
its kcalloc fails. dal_ddc_aux_payloads_get(NULL) then reads
NULL->payloads.container (container is the first member of struct vector,
include/vector.h:29-35) β near-NULL read β panic.
Why not reproduced
The function only executes on amdgpu display hardware (driver core path).
The audit guest: pciconf -l | grep -c 1002 β 0 (no AMD device; Bochs
0x1234:0x1111 VGA) β run.log. Same gating as DF-4555/DF-4556.
Reachability analysis
- OOM path: any amdgpu DC system under extreme memory pressure during a DDC transaction (EDID read / SCDC write / retimer query) β NULL deref panic. Requires GFP_KERNEL failure of a 16-byte alloc β rare but real.
- Zero-size path:
payloads_num == 0requires write_size==0 AND read_size==0. All current callers pass non-zero sizes (SCDC paths :712-754; retimer dc_link.c:1641/:1694 pass (1,1)) β not reachable in-tree today; any future caller with both sizes zero panics deterministically. This makes the missing check a latent trap, hence Info severity.
Fix
fix.diff adds if (!payloads) return false; after both creators
(git-apply --check verified against the pristine tree; never applied to
sys/). No fix validation run: the defective path requires absent
hardware, and the patch is a two-line guard whose semantics are total.
fix_status: fixed (author-verified apply + logic), fix runs not testable
on this guest β fix_baseline_reproduced=0, fix_patched_reproduced=0.
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
fixedfix.diff is a total two-line/one-line guard (git-apply --check verified against the pristine tree; never applied to sys/). No runtime fix validation: the defective path requires AMD DC hardware absent from the audit guest (0x1002 PCI count = 0).
fix.diff in pack; run.log/env.txt hardware inventory.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md root-cause citations (dc_link_ddc.c:580-584,:606-610; basics/vector.c:33-37; include/vector.h:29-35); run.log hardware inventory (no AMD device).
PoC changes
No executable PoC (hardware-gated); evidence pack documents the source trace and the guest hardware absence.
Verified recommended fix
NULL-check both payloads create results and return false (fix.diff).
Verdict
Code-provable latent NULL deref: dal_ddc_service_query_ddc_data (dc_link_ddc.c:580-584 aux, :606-610 i2c) dereferences the result of dal_ddc_aux_payloads_create / dal_ddc_i2c_payloads_create without a NULL check. Both creators return NULL when the 16-byte kzalloc fails (OOM) or when dal_vector_construct rejects capacity==0 (write_size==0 && read_size==0 β basics/vector.c:33-37); the immediate dal_ddc_*_payloads_get(NULL) then reads NULL->payloads.container (struct vector first member, include/vector.h:29-35) -> near-NULL read -> panic. Zero-size case not reachable from current in-tree callers (SCDC :712-754, retimer dc_link.c:1641/:1694 all pass non-zero sizes), so today the path is OOM-gated inside the amdgpu DC driver. Not reproduced: the audit guest has no AMD GPU (pciconf 0x1002 count = 0, run.log) β same hardware gating as DF-4555/4556. Hardening finding; fix.diff adds the two missing NULL guards.
No comments yet.