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

apply_below_the_range: BTR min-frame-duration clamp uses wrong constant (dead clamp) and computed min_frame_duration_in_ns is never used

Summary

The clamp compares inserted_frame_duration_in_us against 1000000/max_refresh_in_uHz, which is 0 for every real refresh in uHz, so the clamp never fires; the correctly-computed min_frame_duration_in_ns (1e15/max) is never used. Upstream uses ns/1000 - a porting divergence. Effect: BTR can program below-minimum-refresh frame durations (flicker/stutter); no memory-safety impact (downstream v_total stays clamped), and the whole function is dead code in this port (zero callers of handle_preflight). Match-upstream fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4489 Β· 2 files
FileTypeDescriptionSize
VERDICT.md β€” 2.3 KB ↓ raw
verdict.json β€” 1.8 KB view raw
VERDICT.md
↓ download raw

DF-4489 β€” BTR minimum-frame-duration clamp uses the wrong constant (dead clamp) + dead min_frame_duration_in_ns

File: sys/dev/drm/amd/display/modules/freesync/freesync.c

Root cause (code-certain; AMD-GPU-gated, no AMD hardware on the audit guest): - :250-252 apply_below_the_range() computes min_frame_duration_in_ns = div64_u64((1000000000ULL * 1000000), in_out_vrr->max_refresh_in_uhz); and then NEVER USES the variable (dead). - :357-360 the clamp is written as if (inserted_frame_duration_in_us < (1000000 / in_out_vrr->max_refresh_in_uhz)) inserted_frame_duration_in_us = (1000000 / in_out_vrr->max_refresh_in_uhz); With refresh in Β΅Hz (e.g. 144 Hz = 144000000 Β΅Hz) the divisor yields 1000000/144000000 == 0 β€” the clamp NEVER fires for any refresh above 1 Β΅Hz encoded value > 1 MHz equivalent; i.e. it is dead for every real panel. - Correct arithmetic (matches upstream Linux amd display, which this port diverges from): duration_in_us = 1e12 / refresh_in_uhz, i.e. the clamp should compare against min_frame_duration_in_ns / 1000.

Impact: functional only β€” BTR frame insertion can program frame durations below the panel's minimum refresh, i.e. flicker/stutter in below-the-range operation. No memory-safety consequence: the resulting v_total computed via calc_v_total_from_duration() :146-160 is clamped into [min_duration_in_us, max_duration_in_us] and floor-clamped to the nominal v_total, so nothing out-of-range reaches hardware programming. Severity Info (hardening / correctness divergence from upstream).

Not runtime-verifiable on this audit guest (no AMD GPU β€” QEMU virtio-gpu only; pciconf -l shows no AMD vendor 0x1002 device), and the AMD DC freesync module is not reachable without amdgpu hardware. Static analysis only.

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

No AMD hardware on the audit guest; static arithmetic proof only.

per-fix-DF-4489

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (arithmetic proof: 1000000/144000000 == 0)

Verified recommended fix

Use min_frame_duration_in_ns/1000 (i.e. div64_u64(1000000000000ULL, max_refresh_in_uhz)) for the inserted_frame_duration_in_us clamp

Verdict

Porting divergence in apply_below_the_range (freesync.c:250-252,357-360): min_frame_duration_in_ns is computed then never used, and the clamp compares inserted_frame_duration_in_us against (1000000 / max_refresh_in_uhz) which is 0 for every real refresh in uHz (correct arithmetic is 1e12/refresh_uHz, cf. upstream Linux amd display 'min_frame_duration_in_ns / 1000'). The clamp is dead -> BTR may insert frames below the panel minimum refresh (flicker); no memory-safety impact (v_total is re-clamped to [min,max] duration and nominal v_total in calc_v_total_from_duration :146-160). AMD-GPU-gated: audit guest has no AMD device (virtio-gpu only), so not runtime-testable. Info severity.