# DF-2955 — `DAY * day` 32-bit multiply wraps: valid FAT dates 2106-02-08..2107-12-31 decode as 1970/1971

## Where

`sys/kern/subr_fattime.c:251` (`fattime2timespec`):

```c
tsp->tv_sec += DAY * day;
```

`DAY` is an `int` (86400) and `day` is `unsigned` (32-bit), so the product is
computed in **32-bit unsigned arithmetic** and wraps modulo 2^32 before being
added to the 64-bit `tv_sec`. `day` (days since 1970) reaches 49711 on
**2106-02-08**, and `49711 * 86400 = 4,295,030,400 > 2^32-1`, so every FAT
timestamp from 2106-02-08 through the end of the representable range
(2107-12-31) is decoded ~2^32 seconds (~55.7 years) in the past.

This is *not* the known DF-0199 day-0 underflow: the input date is a fully
**valid, correctly encoded FAT date**; the encoder (`timespec2fattime`) stores
it correctly on disk (verified: `MDate=0xfc48` / `0xff9f`) and only the
decoder's multiply wraps.

## Impact

Any msdosfs file dated 2106-02-08..2107-12-31 — whether written by a future/
misdated system (a user can set this today with `utimes()`; there is no upper
bound on `tv_sec` in `itimespecfix`, kern_time.c:1047) or present on crafted
media mounted by root (the DF-2902 crafted-attach threat model) — stats with
an mtime in **1970/1971**: e.g. 2107-12-31 05:00 UTC reads back as
**1971-11-23 22:31:44**. Timestamp-integrity only: the produced timespec is
always canonical (tv_nsec in [0,1e9)), no memory-safety effect.

## Reproduce (guest, root)

```sh
dd if=/dev/zero of=/tmp/fat.img bs=1m count=8
vnconfig -c /dev/vn0 /tmp/fat.img
newfs_msdos /dev/vn0
mount_msdos /dev/vn0 /mnt
touch /mnt/W1 /mnt/W2
./fattime_poc /mnt/W1 4295030400     # 2106-02-08 -> 1970-01-01 17:31:44
./fattime_poc /mnt/W2 4354750800     # 2107-12-31 -> 1971-11-23 22:31:44
umount /mnt && ./findentry /tmp/fat.img W2   # MDate=0xff9f = valid 2107-12-31
```

Unprivileged variant (owner-mounted media, see run.sh): `mount_msdos -u 1001`
+ run as uid 1001 → same MISMATCH (poc_unpriv.log).

Expected: `MISMATCH`, stat mtime = requested − 2^32 s.
Fixed kernel: both cases `MATCH` exactly (poc_fixed.log).

## Fix

`fix.diff` (line 259 after patch): `tsp->tv_sec += (time_t)DAY * day;`
Validated on a rebuilt `X86_64_GENERIC` kernel (#1, 2026-09-04): baseline
bad behavior gone, 2106/2107 dates decode exactly.
