Restore disable_configstore, EuiccDisabler and thermal CDEV guards, branding and rebuild/sync helpers; document device roles, laptop migration, and Gitea. Co-authored-by: Cursor <cursoragent@cursor.com>
132 lines
6.6 KiB
Markdown
132 lines
6.6 KiB
Markdown
<!-- Status: historical — Magisk 009 ship resume: docs/009-handoff-20261008.md -->
|
|
|
|
> **Status: historical.** Do not use as execution order. Resume: [`009-handoff-20261008.md`](009-handoff-20261008.md).
|
|
|
|
# FORTIFY family bisection — 2026-09-27
|
|
|
|
## Why this experiment
|
|
|
|
The two-phase X-then-C experiment establishes loss of an adb-verified record
|
|
somewhere in the panic/reboot sequence. Further recovery-channel engineering
|
|
has not identified the original FORTIFY boot failure. This experiment instead
|
|
isolates the protection families while leaving panic behavior intact.
|
|
|
|
This is diagnostic-only: a boot with one family is not a completed FORTIFY port
|
|
and must not be promoted into the shipping hardening configuration.
|
|
|
|
## Independent analysis before build
|
|
|
|
- Reconstructed symbols from the saved failed bounds kernel #19, rather than
|
|
inspecting the live output overwritten by later no-FORTIFY diagnostic builds.
|
|
- Found 372 direct branches to fortify_panic, including its CFI jump-table
|
|
entry. Their presence alone does not prove execution. Inspected early
|
|
start_kernel/setup_arch checks; no demonstrated unconditional failure found.
|
|
- Recompiled init/main.c, arch/arm64/kernel/setup.c and lib/string.c in scratch
|
|
space with the actual Clang 21 flags and the ported header; this is not a
|
|
replacement for whole-kernel LTO or a device boot.
|
|
- The selector's full, memory and strings variants compile for init/main.c and
|
|
lib/string.c with those flags. No overflow stubs are added.
|
|
|
|
## Source and build isolation
|
|
|
|
`scripts/009-fortify-select-family.py` selects complete wrapper functions from
|
|
the existing port and verifies the expected inventory of 15 wrappers. Memory
|
|
keeps memset, memcpy, memmove, memscan, memcmp, memchr, memchr_inv and kmemdup.
|
|
Strings keeps strncpy, strcat, strlen, strnlen, strlcpy, strncat and strcpy.
|
|
Disabled wrappers use the existing raw declarations, not a returning panic stub.
|
|
|
|
`scripts/009-build-fortify-family-isolated.sh` archives kernel commit
|
|
28f9290ae067d3e7857126eb6312720dbe9c7c80 to its own source directory. It applies
|
|
the existing Clang port and the already-tested audio/WLAN bounds patch, then
|
|
selects a family. It never resets Cursor's live source or writes its output.
|
|
|
|
The input .config is extracted from the saved failing bounds kernel. olddefconfig
|
|
must leave it byte-identical or the job aborts. Clang r563880c, LLVM tools and
|
|
Android host build flags are reused. Kernel release suffix is preserved for
|
|
installed modules. Full module linking is required even though only boot will
|
|
be packaged. The raw new Image is injected into GOODMAKE; ramdisk and DTB stay
|
|
from GOODMAKE. Local unpack, metadata, payload and module-version checks remain
|
|
required before device use.
|
|
|
|
## First run
|
|
|
|
Remote root: `/srv/rom/artifacts/009-fortify-family-20260927/`.
|
|
|
|
Detached session: `009-codex-fortify-memory-20260927`.
|
|
|
|
Log: `/srv/rom/artifacts/detach-009-codex-fortify-memory-20260927-20260927T193643Z.log`.
|
|
|
|
Status: `/srv/rom/artifacts/detach-009-codex-fortify-memory-20260927.status`.
|
|
|
|
The memory-only build started at 19:36:43 UTC. Configuration drift check passed
|
|
(empty memory/config.diff). Build finished exit=0 at 19:58:48 UTC
|
|
(`memory/boot-make.img`).
|
|
|
|
**LAB boot (2026-09-27 ~22:00 local):** flashed both slots → `sys.boot_completed=1`
|
|
on kernel `#1` `Sun Sep 27 19:45:25 UTC 2026`. Memory-only family **boots**.
|
|
|
|
**Strings-only build:** session `009-codex-fortify-strings-20260927`, finished
|
|
exit=0 at 20:51:38 UTC (`strings/boot-make.img`).
|
|
|
|
**LAB boot (strings):** flashed both slots → returned to **fastboot** (~100s,
|
|
no `boot_completed`). Recovered combo4. Strings-only family **fails to boot**.
|
|
|
|
**Family result:** memory boots, strings does not → narrow toward string
|
|
wrappers (`strncpy`/`strcpy`/`strlen`/…), not the memcpy family. Still
|
|
diagnostic-only; not a shippable FORTIFY subset.
|
|
|
|
**Strings split (LAB):**
|
|
- `strings-copy` → **boots**
|
|
- `strings-len` (strlen, strnlen) → **boots**
|
|
- full `strings` (copy+len together) → **fails**
|
|
|
|
Implication: neither half alone is sufficient to reproduce; failure is in the
|
|
**interaction** of fortified copy + fortified len (or LTO/CFI coupling of
|
|
both). Next: smaller cross products (e.g. strcpy+strlen only), same baseline.
|
|
|
|
**Cross products (LAB):**
|
|
- `strings-strcpy-strlen` → **boots**
|
|
- `strings-copy-strlen` (5 copy + strlen) → **fails**
|
|
- `strings-copy-strnlen` → **boots** (strlen is the critical len partner)
|
|
- `strings-strlen-restcopy` (strlen+strncpy/strlcpy/strcat/strncat) → **fails**
|
|
- `strings-strlen-ncopy` (strlen+strncpy+strlcpy) → **fails**
|
|
- `strings-strlen-cat` (strlen+strcat+strncat) → **boots**
|
|
- `strings-strlen-strncpy` → **boots**
|
|
- `strings-strlen-strlcpy` → **fails**
|
|
- **Smoking gun:** fortified `strlcpy` + fortified `strlen` together.
|
|
- **Root cause:** 4.14 `strlcpy` does `ret = strlen(q)`. With Clang
|
|
`__pass_object_size`, nested fortified `strlen` panics on known-size
|
|
sources; GCC usually saw bos==-1 and skipped. Fix in
|
|
`apply_fortify_clang.py`: `strlcpy`/`strcpy` use `__underlying_strlen`.
|
|
|
|
**Fix verification (LAB 2026-09-28):**
|
|
- Rebuilt `strings-strlen-strlcpy` + full `strings` with fixed apply → both
|
|
`exit=0` (~18:24 / 18:26 UTC).
|
|
- Flashed both slots: `strlen+strlcpy` → `boot_completed=1`; full `strings`
|
|
→ `boot_completed=1` (`CONFIG_FORTIFY_SOURCE=y`, kernels `#1` 18:06 / 18:10 UTC).
|
|
- Pre-fix pair archived as `strings-strlen-strlcpy-broken/` on the host.
|
|
|
|
**Full family (LAB 2026-09-28):** rebuilt `full` (15 wrappers) with nested-strlen
|
|
fix → `exit=0` 19:31 UTC → flashed both slots → **`boot_completed=1`**
|
|
(`CONFIG_FORTIFY_SOURCE=y`, kernel `#1` 19:18 UTC). Port wrappers alone are
|
|
no longer the brick.
|
|
|
|
**combo4+FORTIFY (LAB 2026-09-28):** ksync
|
|
`20260928T201655Z-bisect-ksync-combo4-fortify-fix` → flashed both slots →
|
|
**`boot_completed=1`** with `FORTIFY` + `INIT_ON_*` + `DMESG` +
|
|
`SLAB_FREELIST_HARDENED`. Nested-strlen fix unblocked the previous ship
|
|
candidate pack.
|
|
|
|
## Interpretation
|
|
|
|
- A memory-only boot would narrow investigation toward the string wrappers or
|
|
their interaction with memory wrappers. It would not prove a specific string
|
|
operation or driver is faulty.
|
|
- A memory-only failure would keep the memory family, common port machinery and
|
|
build/runtime interactions in scope; it would not clear the string family.
|
|
- Complementary/control builds should follow the observation, changing only the
|
|
selector. If behavior is deterministic, continue by splitting the implicated
|
|
group, then its caller set. Do not restart from an unrelated build baseline.
|
|
- Preserve vmlinux, source, effective config, command, compiler version, hashes
|
|
and the exact boot result for each variant.
|