# DF-4577 — intel_hdcp.c KSV→SHA_TEXT fill offset bug (fail-closed HDCP repeater auth)

## What this is

`intel_hdcp_validate_v_prime()` (sys/dev/drm/i915/intel_hdcp.c:216-254) feeds the
concatenated 5-byte KSVs to the HDCP repeater SHA-1 engine 32 bits at a time via
`HDCP_SHA_TEXT`. The fill loop

```c
sha_empty = sizeof(sha_text) - sha_leftovers;
for (j = 0; j < sha_empty; j++)
        sha_text |= ksv[j] << ((sizeof(sha_text) - j - 1) * 8);   /* DF/sys */
```

computes each new byte's shift slot **without offsetting for the leftover byte(s)
already parked in the high slots of `sha_text`** (parked there by the leftover
loop at intel_hdcp.c:237-239). On the second and subsequent KSVs, the first fill
byte `ksv[0]` is OR-ed into the same slot occupied by the previous KSV's leftover
byte, and the remaining bytes land one slot too high, with a zero in the low
slot. The byte stream hashed by the engine therefore diverges from the required
`KSV[0]||KSV[1]||…` concatenation at the first 4-byte boundary (stream byte 5).

Upstream fixed this in the v5.17 HDCP rework (drivers/gpu/drm/i915/display/
intel_hdcp.c:527-529, `(sizeof(sha_text) - j - 1 - sha_leftovers) * 8`);
DF carries the pre-v5.17 form (verified identical to Linux v4.17/v4.18/v5.4/
v5.15-era code).

## Impact

* The hardware SHA-1 over the KSV list can never match the sink's V' when the
  repeater reports **≥ 2 downstream devices** (N=1 is correct: its single
  leftover byte is consumed by the BSTATUS tail paths at intel_hdcp.c:262-360).
* Result: `intel_hdcp_validate_v_prime()` → -ENXIO (3 attempts) →
  `intel_hdcp_auth_downstream()` fails → `_intel_hdcp_enable()` fails all 3
  auth tries → `intel_hdcp_enable()` returns error → the Content Protection
  property never reaches ENABLED. **Fail-closed**: HDCP1.4 content protection
  simply cannot be enabled behind a multi-device repeater on this driver.
  No kernel memory-safety impact; no authentication bypass (a wrong hash can
  only fail the V' comparison, never pass it).

## Proof (arithmetic simulation, guest-compiled)

`df4577_sim.c` reproduces both the DF form and the upstream-fixed form exactly
and prints the byte stream each writes to HDCP_SHA_TEXT. Run on the audit QEMU
guest (DragonFly 6.5-DEVELOPMENT x86_64):

    ./build.sh && ./run.sh        # or see run.log for the captured output

Decisive lines (N=2, stream bytes are 1..10, divergence bolded in run.log):

    required   :  1  2  3  4  5  6  7  8  9 10
    DF (old)   :  1  2  3  4  7  7  8  0        <- byte5 = 5|6 = 7, byte6.. shifted
    upstream   :  1  2  3  4  5  6  7  8        <- exact concatenation

`7 = 5|6` — the leftover byte 5 OR-ed with the next KSV's first byte 6.

## Why no kernel-level PoC (status: untested)

Triggering in-kernel requires: Intel HSW/gen8+ display hardware (not present in
the QEMU guest), a connected HDCP repeater reporting ≥2 downstream devices, an
enabled CRTC, and a DRM master in group `video` (`DRM_IOCTL_MODE_OBJ_SETPROPERTY`
is DRM_MASTER-gated, sys/dev/drm/drm_ioctl.c:679; /dev/dri/card* is root:video
0660, etc/defaults/devfs.conf:7). Low-severity, fail-closed, hardware-gated →
kernel verification skipped per audit policy; the arithmetic proof above is
conclusive for the root cause.

## Fix

`fix.diff` — one line, matches upstream v5.17+:

```diff
-	sha_text |= ksv[j] << ((sizeof(sha_text) - j - 1) * 8);
+	sha_text |= ksv[j] << ((sizeof(sha_text) - j - 1 - sha_leftovers) * 8);
```

Fix validation at kernel level is not possible on this guest (no i915-class
hardware); the same simulation exercises the fixed expression and emits the
exact required stream (see run.log "upstream" rows).
