# DF-5159 — bw_fixed.c range guards are ASSERT()=WARN_ON only: silent 64-bit wrap in release builds

File: `sys/dev/drm/amd/display/dc/calcs/bw_fixed.c` (pass 2, GLM 5.3)

## What

Every range/overflow guard in this translation unit is `ASSERT(expr)`, which in
this tree expands to `WARN_ON(!(expr))` (`sys/dev/drm/amd/display/dc/os_types.h:76`;
only `CONFIG_DEBUG_KERNEL_DC` builds upgrade it to ASSERT_CRITICAL). In a normal
release kernel, `WARN_ON` logs a splat and **execution continues with the
wrapped value** — the guards protect nothing:

- `bw_int_to_fixed_nonconst` (bw_fixed.c:49-55): `res.value = value << 24` with
  `|value| >= 2^39` (BW_FIXED_MAX_I32, bw_fixed.h:40) shifts bits out of the
  int64 — silent wrap (and signed-shift UB for negatives).
- `bw_frc_to_fixed` (bw_fixed.c:57-110):
  - `abs_i64(INT64_MIN)` (bw_fixed.c:41-47): `-arg` overflows int64 → UB /
    wraps back to 0x8000000000000000.
  - The 24-iteration long-division loop `res_value <<= 1` (bw_fixed.c:86)
    wraps mod 2^64 once the accumulated quotient exceeds 64 bits (integer part
    assert at bw_fixed.c:76 is WARN-only).
  - `res.value = -res.value` (bw_fixed.c:108) on an already-wrapped MIN.
- `bw_mul` (bw_fixed.c:143-191): `res.value = arg1_int * arg2_int`
  (bw_fixed.c:161) with integer parts up to 2^39-1 each produces up to ~2^78 —
  **unconditional u64 wrap** before the first assert (bw_fixed.c:163) even
  evaluates; the three subsequent summand asserts (169/175/184) are WARN-only.

Consequence: corrupted fixed-point values propagate into the DCE bandwidth
calculations (watermarks, latency hiding) and are programmed into display
hardware registers — wrong display configuration, WARN splats, potential
underflow/GPU-hang behavior. **No kernel memory unsafety is possible**: the file
performs pure arithmetic (no pointers, arrays, copies), so OOB/UAF/leak classes
are structurally absent; the ceiling is wrong-value propagation.

This is distinct from the known DF-2155 (unguarded div0 panics in
bw_frc_to_fixed/bw_floor2/bw_ceil2, lines 69-132), which is NOT re-reported.

## Reachability

Inputs derive from validated display-mode timings, ATOM-BIOS tables and DML
constants — not directly from unprivileged memory. No caller on the audit guest:
the box has a virtio/QXL VGA device (0x1234:1111), no AMD DC GPU, and no drm
modules loaded (env.txt). Severity **Info** (hardening), CWE-190.

## Fix direction (not shipped as a diff)

Convert the asserts into saturating clamps (return ±BW_FIXED_MAX_I32-shaped
values) or use full 64x64→128 multiplication and range-check before truncating;
upstream amdgpu carries the same WARN-only pattern, so semantics need an
upstream decision. `fix.diff` intentionally omitted: changing DML arithmetic
semantics with no hardware to validate against would be riskier than the defect.

## 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.)
