# DF-4467 VERDICT — reproduced (silent ciphertext corruption, XTS tweak reuse)

## Bottom line

**REPRODUCED.** With 8 concurrent writers on a software `aes-xts-plain64`
dm-crypt device, **1413 of 1536** block-verification rounds returned
corrupted plaintext although every `pwrite()` had reported success; the
single-threaded control run corrupted **0 of 512**. The write path used
wrong XTS tweaks: the running tweak lives in the shared session context
and is re-initialized/mutated by whichever CPU happens to be inside
`cryptoapi_cipher_crypt()`.

## Mechanism (path:line)

1. `sys/crypto/cryptoapi/cryptoapi.c:370-374` — `struct aes_xts_ctx`
   contains `uint8_t tweak[16]` — **per-session, mutable state**.
2. `sys/crypto/cryptoapi/cryptoapi.c:412-428` — `aes_xts_reinit()` writes
   `ctx->tweak` from the per-call IV and encrypts it in place.
3. `sys/crypto/cryptoapi/cryptoapi.c:216-236` — `crypt_block_xts()`
   mutates the tweak (×α GF(2^128)) after every data block; the mutation
   is on the same `ctx->tweak` via `crypt_data_xts(..., ctx->tweak, ...)`
   (`cryptoapi.c:439-441`).
4. `sys/crypto/cryptoapi/cryptoapi.c:1152-1165` — the session is shared by
   all callers; no locking anywhere in the crypt path.
5. `sys/dev/disk/dm/crypt/dm_target_crypt.c:958-991` — `dmtc_bio_encdec()`
   runs once per in-flight bio, on whatever CPU dispatched the strategy
   (write encryption is synchronous in `dmstrategy` context:
   `dm_target_crypt.c:883-925`), so multiple CPUs interleave steps 2-3.

Net effect: blocks are enciphered under tweak values belonging to other
data units. This simultaneously (a) corrupts the ciphertext silently and
(b) creates **tweak reuse across data units** — the specific XTS misuse
mode that leaks equality structure of plaintext blocks and is explicitly
out of XTS's security contract.

Same defect in `twofish_xts_reinit/crypt` (`cryptoapi.c:731-792`) and
`serpent_xts_reinit/crypt` (`cryptoapi.c:894-957`).

## Scope / threat model

* Any mult-CPU system doing concurrent I/O on a dm-crypt XTS volume using
  the software implementations (no AESNI on the CPU, or `hw.aesni_disable=1`).
* Data-integrity impact demonstrated directly; confidentiality impact
  (tweak reuse) follows from the same mechanism.
* No memory-safety impact: the race corrupts data, not pointers.

## Fix

`fix.diff` moves the tweak to a per-call stack buffer in all three
software XTS ciphers (`aes/twofish/serpent _xts_crypt`), passing it down
to `crypt_data_xts`. The AESNI paths already use per-call tweaks.
`git apply --check` passes against the pristine tree. Kernel-module
rebuild validation not repeated for this Medium-severity finding in this
run — the change is three mechanical, self-contained edits.

## Status mapping

| observation | classification |
|---|---|
| race run: 1413/1536 corrupted round-trips, all writes "successful" | reproduced, impact = silent data corruption (integrity + XTS tweak-reuse confidentiality) |
| control run: 0/512 corrupted | rules out setup/key/IV errors |

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