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

dc_link_ddc: uninitialized type2_dongle_buf[0x20] hexdumped to the kernel log on dongle-detect i2c failure (drm.debug)

Summary

The 32-byte stack buffer is only written on i2c success; on the common failure path (every DP-DVI passive dongle - no responder at 0x40) all six detect branches hexdump all 32 uninitialized bytes via DRM_DEBUG_KMS - stale kernel stack (potentially pointers) to the log, unpriv-readable. Config+hardware gated. Zero-init fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4664 Β· 7 files
FileTypeDescriptionSize
README.md β€” 1.4 KB ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
fix.diff β€” 430 B view raw
run.log β€” 329 B view raw
env.txt β€” 329 B view raw
manifest.json β€” 619 B view raw
verdict.json β€” 2.5 KB view raw

DF-4664 β€” dc_link_ddc: uninitialized type2_dongle_buf[0x20] hexdumped to the kernel log on dongle-detect i2c failure

dal_ddc_service_query_dp_dual_mode_adaptor (dc_link_ddc.c:429-545) declares uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE] (:436, 32 bytes) and passes it to i2c_read() (:445-449). On i2c failure (no responder at DP_HDMI_DONGLE_ADDRESS 0x40 — the normal case for a plain DP→DVI passive dongle) the buffer is never written, and every failure/ mismatch branch then feeds it to CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), ...) (:453-455, :499-502, :507-510, :514-517, :530-533, :537-540), which hexdumps all 32 bytes via dc_conn_log_hex_linux → DC_LOG_DEBUG == DRM_DEBUG_KMS (include/logger_interface.h:102-107, basics/log_helpers.c:31-38, include/logger_types.h:35).

β‡’ 32 bytes of uninitialized kernel stack (whatever the previous frame left: potentially pointers/addresses) are emitted to the DRM debug log whenever drm.debug is enabled, on every hotplug of such a dongle.

Run / verification

Hardware-gated (needs an AMD DC GPU + DP passive dongle; audit guest has no 0x1002 device β€” run.log/env.txt). Defect code-provable: the buffer has no initializer and no write occurs on the failure path.

Fix

fix.diff (git-apply verified): zero-initialize the buffer β€” consistent with the file's own union hdmi_scdc_status_flags_data status_data = { {0} }; at :744.

VERDICT.md
↓ download raw

DF-4664 β€” VERDICT

not_reproduced (hardware-gated) β€” Info-severity uninit-read-to-log; defect code-provable.

Root cause (certain, from source)

  • uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE] (0x20 = 32 bytes) is declared uninitialized at dc_link_ddc.c:436.
  • i2c_read(ddc, DP_HDMI_DONGLE_ADDRESS, type2_dongle_buf, 32) (:445-449) fills it only on a successful i2c transaction; the read payload is filled by the engine, and on NACK/failure the buffer is untouched.
  • The failure branch (:450-457) and five subsequent branches all call CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), ...), which unconditionally hexdumps all 32 bytes: dc_conn_log_hex_linux (basics/log_helpers.c:31-38) β†’ DC_LOG_DEBUG β†’ DRM_DEBUG_KMS (include/logger_types.h:35).

So on a system with drm.debug enabled (operator debugging β€” a normal configuration when diagnosing display issues), each detection of a DP-DVI passive dongle (the no-responder-at-0x40 case is exactly what that dongle type produces) emits 32 bytes of stale kernel stack to the log. Stack residue can contain kernel pointers/addresses (the DC stack at that point has been through BIOS-object parsing, gpio/i2c structures, etc.).

Why not reproduced

Requires AMD DC GPU + DP passive dongle; the audit guest has zero 0x1002 PCI devices (run.log). The exposure channel is additionally gated on drm.debug being enabled at runtime.

Impact ceiling

Low/Info: 32-byte uninit kernel-stack disclosure to the kernel log (readable locally by unprivileged users via the msgbuffer when drm.debug is on). No memory corruption, no remote path.

Fix

fix.diff zero-initializes the buffer (= {0}), matching the file's own style at :744 (status_data = { {0} }). git-apply --check verified; not applied to sys/. No runtime fix validation possible on this guest (no AMD GPU); the patch is a total one-line initialization.

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 no→ patch + rebuild →patched clean

fix.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.
↓ fix.diffper-fix-DF-4664

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md citations (dc_link_ddc.c:436,:445-457; include/logger_interface.h:102-107; basics/log_helpers.c:31-38; include/logger_types.h:35); run.log hardware inventory.

PoC changes

No executable PoC (hardware-gated); source trace + guest hardware inventory documented.

Verified recommended fix

Zero-initialize type2_dongle_buf at declaration (fix.diff).

Verdict

Code-provable uninitialized-stack disclosure to the kernel log: type2_dongle_buf[0x20] (dc_link_ddc.c:436) is never initialized and is only written by i2c_read on success (:445-449); on the common failure path (no responder at 0x40 β€” the normal signature of a DP-DVI passive dongle) all six CONN_DATA_DETECT branches (:453,:499,:507,:514,:530,:537) hexdump all 32 bytes via dc_conn_log_hex_linux (log_helpers.c:31-38) -> DC_LOG_DEBUG == DRM_DEBUG_KMS (logger_types.h:35). With drm.debug enabled, each such hotplug emits 32 bytes of stale kernel stack to the log readable by unprivileged users. Not reproduced: audit guest has no AMD GPU (0x1002 count = 0) and no DP sink; exposure additionally gated on drm.debug.