# DF-5713 VERDICT — reproduced (hardening failure; impact: none by itself)

**Bottom line:** every factual claim of the finding was demonstrated live on
the DragonFly 6.5-DEVELOPMENT X86_64_GENERIC guest. The kernel's only
stack-canary symbol, `__guard`, is a compile-time constant
(`sys/libkern/stack_protector.c:36`, `0x00000aff`) that is **never seeded
from any entropy source at any point in boot**; the modern
`__stack_chk_guard`/`__stack_chk_fail` ABI is **absent from the kernel
entirely**; and `sys/platform/pc64/conf/kern.mk:7` force-disables
`-fstack-protector` for all kernel and KLD code. The "security-critical
mitigation layer" therefore protects exactly nothing: it is 51 lines of dead
code force-linked into every pc64 kernel
(`sys/platform/pc64/conf/files:119`), whose only exported value is a
publicly-known constant.

## Mitigation-family checklist (as tasked)

### (a) Canary source / seeding vs first use
- Source: `sys/libkern/stack_protector.c:36` (`0x00000aff` LE) / `:38`
  (`0xff0a0000` BE) — a **link-time constant in .data**, not karc4random.
- Tree-wide grep for `__guard` writes: only lines 36/38. No SYSINIT, no
  reseed, nothing. The DF-5694/5695 (arc4 bias) and DF-2243 (zero-window)
  concerns are **moot but in the worst way**: the entropy path does not
  exist at all, so the canary is not "weakly random" — it is *known to
  everyone who can read the public source*.
- Live: `/dev/kmem` reads `ff 0a 00 00` on **two independent fresh boots**
  (run.2.log, run.4.log); the ELF `.data` cell at `0xffffffff8113bae0`
  holds the same bytes; KLD `guard_probe.ko` reads `0xaff` through the
  exported symbol. Constant from link time through runtime, forever.

### (b) Guard placement / infoleak surface
- Single **global `int`** in `.data` at a fixed link-time address
  (`ffffffff8113bae0` on this build), exported in the kernel symbol table
  (`nm`), readable by any loaded KLD and by root via `/dev/kem`//`/dev/mem`.
  Not per-CPU, not per-boot. There is nothing to leak, though — the value
  is public in the source. (`sys/libkern/stack_protector.c:36`)
- Notably the file is force-linked into every pc64 kernel via
  `sys/platform/pc64/conf/files:119` (`libkern/stack_protector.c standard`)
  even though **no in-tree code references `__guard` or
  `__stack_smash_handler`** (tree-wide grep) — pure dead weight.
  `sys/conf/files:2219` has the equivalent line commented out; pc32
  (i386) doesn't list the file at all.

### (c) Fail path
- `__stack_smash_handler()` panics with
  `stack overflow in function <name>` (`sys/libkern/stack_protector.c:49`;
  i386 variant at `:47` prints the caller PC from `4(%ebp)` — cosmetic
  only, and that asm is dead for amd64). Demonstrated live: loading
  `guard_panic.ko` → `panic: stack overflow in function
  guard_panic_smash_test` with a clean backtrace through
  `module_register_init` (panic2.txt). The handler works; it is simply
  connected to no instrumentation.

### (d) Terminator-canary property
- LE value bytes in memory: `ff 0a 00 00` — first NUL at **byte 2, not
  byte 0**. A proper terminator canary places the NUL in the lowest byte
  so an ascending `strcpy` stops *inside* the canary before touching
  anything past it. Here a byte-string overflow first clobbers `ff 0a`
  (both publicly known, so an attacker with a controlled copy simply
  re-writes them) and terminates inside the canary. With a *known
  constant* canary the property is irrelevant anyway: any
  arbitrary-content overflow primitive (memcpy/bcopy/read) forges all 4
  bytes. The BE variant (`0xff0a0000` → bytes `00 00 0a ff` low→high) has
  the NUL low, ironically correct — but pc64 is LE.

## The decisive live demonstration (why this is a real hardening failure)

The default-built KLD `ssp_smash.ko` (exactly what `bsd.kmod.mk` produces:
`-fno-stack-protector` forced by `sys/platform/pc64/conf/kern.mk:7`)
executes a textbook 48-byte `strcpy` into a 16-byte kernel-stack buffer:

```
Fatal trap 9: general protection fault while in kernel mode
frame pointer   = 0x10:0x4242424242424242
Stopped at      boom+0x2c:      ret
```

The saved RBP is `0x4242…` — the attacker payload — and the kernel dies at
`boom`'s `ret` on the way to the smashed return address. **There is no
canary anywhere in that frame**, because no kernel/KLD code is ever
instrumented. The identical module recompiled with `-fstack-protector-all`
(by hand; the build system silently strips the flag) cannot even load:
`link_elf_obj_obj: symbol __stack_chk_guard undefined` — the kernel
provides no modern ABI to link against.

## Exploit chain

None developed — none exists *through this file*. The finding is a missing
mitigation (CWE-693), not a corruption primitive: unprivileged attack
surface of the file itself is zero (it defines two symbols and a panic).
The impact is systemic: **every kernel stack-overflow bug in DragonFly
lands on unprotected frames**, so any such bug elsewhere in `sys/` is
strictly more exploitable than on a stack-protected kernel; and if SSP were
enabled without fixing the file, the only available canary
(`__guard`, propolice ABI) is a publicly-known constant — also decorative.

## Why not uid0 / why impact=none

The panics in the evidence were **root-deliberate** (kldload of a test
module). No unprivileged-reachable path through this file exists. Severity
Low (hardening/defense-in-depth), confidence certain.

## Fix validation

Not performed (`fix_status: not_testable`): the fix
(`fix.diff` — modern `__stack_chk_guard`/`__stack_chk_fail`, SYSINIT seeding
from `karc4random_buf()` after `arc4_init_pcpu()` has run, kern.mk switched
to `-fstack-protector-strong`) requires a full kernel rebuild/boot cycle
whose payoff is a hardening A/B, not a behavior A/B of a reproduced
corruption. `git apply --check` passes against the tree. Upstream should
build/boot-test `fix.diff` (especially the kern.mk hunk) before commit.

## Guest state

Guest panicked twice (both deliberate evidence runs), restored with
`vm.sh reset with-src` after each; final state: up, clean snapshot,
read-only `/dev/kmem` probe only after the last reset. `guest_dirty: 0`.

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