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

Uninitialized mode_cmd stack fields propagated into long-lived drm_framebuffer

  • File: sys/dev/drm/radeon/radeon_fb.c
  • Lines: 224, 230–238, 149, 257
  • Severity: Info
  • CVSS 3.1: CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N
  • CWE: CWE-457 Use of Uninitialized Variable
  • Confidence: likely
  • Status: new

Summary

struct drm_mode_fb_cmd2 mode_cmd; (radeon_fb.c:224) is declared without an initializer. Only width (230), height (231), pixel_format (237-238), and pitches[0] (set inside radeonfb_create_pinned_object at radeon_fb.c:149) are written. The remaining fields β€” pitches[1..3], offsets[0..3], modifier[0], flags, handles[0..3] β€” stay as stack garbage and are copied verbatim into the long-lived drm_framebuffer by drm_helper_mode_fill_fb_struct (invoked via radeon_framebuffer_init at radeon_display.c:1302; copies at drm_modeset_helper.c:88-92).

Root cause

radeon_fb.c:224 struct drm_mode_fb_cmd2 mode_cmd; β€” no = {} or memset. Writes are partial: - radeon_fb.c:230-231 (width, height) - radeon_fb.c:237-238 (pixel_format) - radeon_fb.c:149 (pitches[0] only)

drm_helper_mode_fill_fb_struct then does for (i = 0; i < 4; i++) { fb->pitches[i] = mode_cmd->pitches[i]; fb->offsets[i] = mode_cmd->offsets[i]; } and fb->modifier = mode_cmd->modifier[0]; fb->flags = mode_cmd->flags; (drm_modeset_helper.c:87-92), copying uninitialized stack into the persistent framebuffer object.

Threat model

For single-plane legacy formats (the only kind drm_mode_legacy_fb_format produces, radeon_fb.c:237), pitches[1..3]/offsets/num_planes=1 so the garbage is never read by scanout logic β€” dead data in practice.

The garbage does, however, persist in a kernel object whose lifetime equals the framebuffer's and could be read back via DRM ioctls that walk fb metadata (info leak of kernel-stack contents into long-lived state).

The most plausible real impact is a future code path that starts consulting fb->modifier or fb->flags and misbehaves on garbage (e.g., tiling modifier that happens to look like DRM_FORMAT_MOD_LINEAR). No current reader in the radeon driver consults fb->modifier.

Proof of concept

Trigger radeon_fbdev_init on boot (automatic with a radeon GPU attached). Then use a DRM ioctl to read fb metadata β€” DRM_IOCTL_MODE_GETFB2 β€” and observe that fb->modifier / fb->flags / fb->offsets[1..3] / fb->pitches[1..3] contain stack bytes from the radeonfb_create call frame.

Because the framebuffer is the boot fbcon object, this is reachable from any user with O_RDWR on /dev/dri/card0. Concrete leak rate is low (a handful of u32 fields, fixed for the lifetime of the fb).

Zero-initialize mode_cmd.

--- a/sys/dev/drm/radeon/radeon_fb.c
+++ b/sys/dev/drm/radeon/radeon_fb.c
@@ -221,7 +221,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
    struct radeon_fbdev *rfbdev =
        container_of(helper, struct radeon_fbdev, helper);
    struct radeon_device *rdev = rfbdev->rdev;
-   struct fb_info *info;
+   struct fb_info *info;
    struct drm_framebuffer *fb = NULL;
-   struct drm_mode_fb_cmd2 mode_cmd;
+   struct drm_mode_fb_cmd2 mode_cmd = { 0 };
    struct drm_gem_object *gobj = NULL;

References

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1971 Β· 3 files
FileTypeDescriptionSize
VERDICT.md verdict source-only confirmation + mechanism + fix 1.6 KB ↓ raw
fix.diff suggested-fix bzero(&mode_cmd, sizeof(mode_cmd)) before populating fields. 843 B view raw
../fix_build_new.log build-log Batch kernel build with new fixes (rc=0, -Werror) 5.6 MB ↓ download
VERDICT.md verdict source-only confirmation + mechanism + fix
↓ download raw

DF-1971 β€” PoC Verification Verdict

Category: drm (module / HW-gated) Source: sys/dev/drm/radeon/radeon_fb.c:224-238 Guest: 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 (X86_64_GENERIC, INVARIANTS ON, no SMAP/SMEP/KASLR) Date verified: 2026-07-25

Verdict: REPRODUCED (source-only confirmation; HW/module-gated)

Mechanism

struct drm_mode_fb_cmd2 mode_cmd; declared on stack, only some fields set (width/height/pixel_format). Other fields (handles[], pitches[], offsets[], flags) leak stack residue into drm_framebuffer_init and persist for the object's lifetime.

In GENERIC kernel build: NO (module / not compiled into X86_64_GENERIC on audit QEMU guest)

Reproduction status

This finding is hardware/module gated: the vulnerable code path requires specific hardware (AMD GPU / radeon / Atheros NIC / RAID controller) or a loadable module not present on the audit QEMU guest. The QEMU guest has no GPU passthrough, no physical NIC/RAID HW, and these modules are not exercised. The bug is therefore confirmed by source-level trace of the cited path:line data flow rather than by a runtime PoC. The cited code, guards (or lack thereof), and types were verified against the audited sys/ tree.

Fix

bzero(&mode_cmd, sizeof(mode_cmd)) before populating fields.

See fix.diff for the standalone git-apply-able unified diff. Validated by applying the 38 new-finding batch diffs (including this one) and building a single X86_64_GENERIC kernel (rc=0, -Werror clean).

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.

VALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

REPRODUCED (source-only): radeonfb struct drm_mode_fb_cmd2 mode_cmd declared on stack, only some fields set; other fields (handles[],pitches[],offsets[],flags) leak stack residue into drm_framebuffer_

Verified recommended fix

REPRODUCED (source-only): radeonfb struct drm_mode_fb_cmd2 mode_cmd declared on stack, only some fields set; other fields (handles[],pitches[],offsets[],flags) leak stack residue into drm_framebuffer_init and persist for object lifetime.

Verdict

REPRODUCED (source-only): radeonfb struct drm_mode_fb_cmd2 mode_cmd declared on stack, only some fields set; other fields (handles[],pitches[],offsets[],flags) leak stack residue into drm_framebuffer_init and persist for object lifetime.