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).
Recommended fix
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
sys/dev/drm/radeon/radeon_fb.c:224,230-238,149β partial initializationsys/dev/drm/radeon/radeon_display.c:1302β callsdrm_helper_mode_fill_fb_structsys/dev/drm/drm_modeset_helper.c:87-92β copies all fields verbatim into long-lived fb
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1971 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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
fixedVALIDATED: 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.
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.
No comments yet.