DF-4201 / verdict.json
{ "finding_id": "DF-4201", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "DF-4033 radeon twin in amdgpu: three sites dereference the result of best_encoder()/enc_priv without NULL checks \u2014 amdgpu_connector_get_monitor_bpc:139-143 (best_encoder NULL from amdgpu_connector_best_single_encoder :346-357 / dvi_encoder :1122-1148 on an empty possible-encoder list, plus enc_priv NULL because dce_v*_0_encoder_add initializes it to NULL and only fills it if get_lcd_info/get_dig_info kzallocs succeed, dce_v10_0.c:3494/3520), amdgpu_connector_set_property:583-594 and amdgpu_connector_set_lcd_property:792-803 (scaling-mode branch, deref rmx_type/native_mode). Possible encoders are attached only by amdgpu_link_encoder_connector (amdgpu_encoders.c:45-56) \u2014 a VBIOS connector whose device bits match no encoder stays encoder-less while remaining registered. The monitor-bpc path fires on every modeset (atombios_crtc.c:773); the property paths via DRM_MASTER-gated MODE_SETPROPERTY/OBJ_SETPROPERTY (drm_ioctl.c:667/679). to_amdgpu_encoder(NULL) deref = deterministic NULL-page panic. The same file guards enc_priv at :484 \u2014 the omission is provable in-source. Not reproduced at runtime: guest has no AMD GPU (env.txt); trigger built and ran on the guest. Identical unguarded code in upstream Linux.", "exploit_chain": "display-session owner (DRM master) writes a connectors scaling-mode property on an encoder-less amdgpu connector (VBIOS misconfiguration), or any modeset on an eDP/LVDS panel with bpc-less EDID and failed dig/lcd-info allocation -> NULL deref panic", "evidence": "VERDICT.md (NULL-source proof at both levels: encoder list and enc_priv allocation); trigger_df4201.c + run.log (guest run, hardware-gated); fix.diff (three guards); env.txt", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:137-147", "sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:577-604", "sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:789-808", "sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:346-357", "sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:484-485", "sys/dev/drm/amd/amdgpu/amdgpu_encoders.c:45-56", "sys/dev/drm/amd/amdgpu/dce_v10_0.c:3494", "sys/dev/drm/drm_ioctl.c:667" ], "poc_changes": "trigger written from scratch (raw ioctls, self-contained struct defs, no libdrm); __u32/__u64 typedefs added after first guest compile", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 10, "guest_dirty": 0, "build_cmd": "./build.sh (guest cc -O2 -Wall)", "run_cmd": "./run.sh", "code_hash": "aef2cf69333a29c09c4765b0307c70de1f208f192e5b34af38095eb639e8ba16", "notes": "Hardware-gated: guest has no amdgpu device (env.txt). Shared-DDC walk NULL ddc_bus at :1038 analyzed and killed: shared_ddc=true provably implies ddc_bus!=NULL (it is only set when an existing connector with a live ddc_bus matched, and the same-id lookup then succeeds for the new connector).", "recommended_fix": "NULL-check best_encoder() results at the two scaling-mode sites and both encoder and enc_priv in the monitor-bpc branch (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applies cleanly to a pristine copy of the real amdgpu_connectors.c (verified, cumulative with DF-4200/4202 diffs), consistent with the in-file guard pattern at :484; kernel-build validation not possible on this guest (no AMD GPU).", "fix_evidence": "fix.diff; local patch --dry-run + applied-copy verification noted in VERDICT.md" } |