Files
AXP-Resurection/docs/009-hardening-signing-checklist.md
T
sunfish-adminandCursor 2d145c2878 009: Polish bacon fixes, OTA host scripts, and migration docs.
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>
2026-10-16 21:06:45 +02:00

266 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 009 — Userspace hardening / signing / AVB checklist (Gate G)
> **Closure measured 2026-10-09:** LAB ship is `user` + `release-keys` + AVB
> flags 0 + Magisk preroot + malloc. Prefer
> [`009-closure-parity-20261009.md`](009-closure-parity-20261009.md) over the
> 2026-09-29 baseline table below (kept for archaeology).
**Task:** T040.
**Companion:** kernel half = `docs/009-gate-g-kernel-attribution.md`.
**Policy:** project **release keys yes**; **bootloader relock no**
(AXP/LOS unlocked norm). See `specs/009-axp-los23-port/research.md`.
Secrets never enter Git. Host material lives under `/srv/rom/secrets/` on
`rom-dev01` only.
---
## Measured baseline (2026-09-29 — historical)
| Prop / fact | GOLDEN (AXP Pro) | LAB (Stage1 pack) | Target |
|-------------|------------------|-------------------|--------|
| `ro.build.type` | `user` | `userdebug` | `user` for ship; `userdebug` OK while developing |
| `ro.build.tags` | `release-keys` | `test-keys` | `release-keys` |
| `ro.build.flavor` | `lineage_sunfish-user` | `lineage_sunfish-userdebug` | `…-user` at ship |
| `ro.debuggable` | `0` | `0` on LAB measure wait — typically `1` on userdebug | `0` on ship |
| `ro.secure` | `1` | (LOS default) | `1` |
| `ro.boot.flash.locked` | `0` | `0` | `0` (unlocked — intentional) |
| `ro.boot.verifiedbootstate` | `orange` | `orange` | `orange` while unlocked |
| `ro.boot.vbmeta.device_state` | `unlocked` | (same class) | unlocked |
| `ro.boot.veritymode` | `enforcing` | expect enforcing | keep |
| SELinux | Enforcing (expect) | **Enforcing** | keep |
| OTA zip cert | AXP releasekey | **AOSP `testkey.x509.pem`** (byte-match on stage1 zip) | project releasekey |
| AVB signing key in tree | AXP custom | `external/avb/test/data/testkey_rsa2048.pem` | project AVB key |
| `BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS --flags 3` | AXP sets real AVB when enabled | LOS sunfish adds `--flags 3` unless `WITH_AVB=true` | keep flags 3 (signing infra only; not runtime harden) |
LAB adb sample (device `11231JEC207477`, Stage1 sideload):
`test-keys` / `userdebug` / `orange` / `flash.locked=0` / `getenforce=Enforcing`.
GOLDEN source: `/srv/rom/references/axp/golden/2026-09-13/getprop.txt`.
---
## What “done” means for Gate G userspace
1. Ship images/OTAs verify as **`release-keys`** (not AOSP test-keys).
2. Phonesky / microG keep **their** project JKS identities under
`/srv/rom/secrets/{phonesky,microg}-signing/` (already exist).
3. AVB *build* uses project keys where LOS23/sunfish allows; device stays
**unlocked** (`orange`). Relock is **out of scope**.
4. Userspace hardening stages are attributable (patch dir + map) or explicitly
deferred/skipped with reason.
5. Gaps written down — no silent omit.
---
## Stages (do in order)
### US-S0 — Inventory (this doc) — **done 2026-09-29**
- [x] Compare GOLDEN vs LAB signing/AVB props.
- [x] Confirm stage1 zip OTA cert == AOSP testkey.
- [x] Confirm no `~/.android-certs` / platform release keys on host yet
(only Phonesky + microG JKS).
- [x] Record bootloader-lock = wont.
### US-S1 — Generate project Android signing keys — **done 2026-09-29 (host)**
Host-only. Never commit `.pk8` / private PEM.
| Key | Role |
|-----|------|
| `releasekey` | Default APK/OTA (`PRODUCT_DEFAULT_DEV_CERTIFICATE`) |
| `platform` | `platform`-signed priv-apps |
| `shared` / `media` / `networkstack` / `sdk_sandbox` / `bluetooth` / `nfc` | AOSP partition signing set |
Procedure: `scripts/009-generate-release-keys.sh` on `rom-dev01`
→ prefers `/srv/rom/secrets/android-certs/` if writable, else
`$HOME/.android-certs` (Lineage default; used 2026-09-29 because secrets/
is root-owned 750 without group write).
**Mandatory before first signed ship bacon:** encrypted/offline backup of that
directory (constitution). Public `*.x509.pem` may later be copied into Git for
docs; private material must not.
Acceptance:
- [x] `$HOME/.android-certs/{releasekey,platform,…}.{pk8,x509.pem}` + `avb.pem`
exist on `rom-dev01` (2026-09-29T16:37Z)
- [x] Host tar backup: `/home/android-build/backups/android-certs-20260929T1637Z.tar.gz`
(mode 600; SHA256 in `.sha256`) — **still copy offline/encrypted**
- [x] `releasekey` DN = `O=AXP-Resurection, OU=sunfish-a16, CN=release`
(not AOSP testkey)
- [ ] Root later: `install -d` `/srv/rom/secrets/android-certs` and move keys there
- [ ] Owner offline encrypted copy confirmed
### US-S2 — Wire release keys into bacon — **in progress**
Lineage convention: `PRODUCT_DEFAULT_DEV_CERTIFICATE` → path without suffix
(e.g. `…/releasekey`). On LOS 23 / soong, **env export alone is ignored** —
must be a product makefile `PRODUCT_` (see `vendor/sunfish-a16/signing.mk`,
inherited via `magisk.mk`). Verified `get_build_var` → project releasekey.
Keys **present** on rom-dev01 (`$HOME/.android-certs/releasekey.pk8`, 2026-09-29).
First artifact `20261001T221102Z-…-cve-hi-releasekeys` was **still AOSP testkey**
(env-only wire). Rebacon after `signing.mk` (2026-10-01T22:12Z).
CVE LAB bacons keep test-keys. First real signed bacon stays **`userdebug`**.
**LAB 2026-10-02:** first signed sideload booted Wi‑Fi OK but Bluetooth
crash-looped — zygote `selinux_android_setcontext` failed with
`seinfo=default` for `com.android.bluetooth`. Cause: APK signed with project
`certs/bluetooth.pk8` while `MAINLINE_BLUETOOTH_SEPOLICY_DEV_CERTIFICATES`
stayed on AOSP `build/make/target/product/security/` (non-`com.google.android.bt`
default in `config.mk`). Fix: `PRODUCT_MAINLINE_BLUETOOTH_SEPOLICY_DEV_CERTIFICATES`
in `signing.mk` (rebacon required; boot-only flash insufficient).
Acceptance:
- [ ] Zip `META-INF/com/android/otacert` ≠ AOSP testkey
- [ ] `ro.build.tags=release-keys` on LAB after **sideload** (boot-only flash insufficient)
(note: first RK sideload still showed `dev-keys` on userdebug — recheck after BT fix)
- [x] Magisk preroot + microG + Wi‑Fi **and Bluetooth** OK on Stage1+combo4+CVE-hi ship pack
(`20261002T085915Z-…-cve-hi-releasekeys`, LAB 2026-10-02: BT ON, crashed 0)
- [x] `plat_mac_permissions.xml` embeds project `bluetooth.x509.pem` (`seinfo=bluetooth`)
- [ ] Minor: LOS SetupWizard after Wi‑Fi connect can bounce to language step
(Wi‑Fi stays connected; non-blocking; note only)
- [ ] Prior test-keys image retained for bisect
(`20261001T201836Z-…-cve-hi-batch2` / `#49`, or hi-batch3 when OK)
Script: `scripts/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh` +
`vendor/sunfish-a16/signing.mk` → `vendor/sunfish-a16/certs/releasekey`
(in-tree copy of `$HOME/.android-certs`; **gitignored** — soong rejects paths
outside `ANDROID_BUILD_TOP`).
### US-S3 — Project AVB key (unlocked device)
Today sunfish often signs with AOSP `testkey_rsa4096` (or rsa2048) and adds
`--flags 3` unless `WITH_AVB=true` (`BoardConfigLineage.mk` /
`BoardConfig-common.mk`). LAB `20261002T085915Z` vbmeta = AOSP testkey_rsa4096
+ flags 3 (not project `avb.pem`).
AXP ships custom AVB keys and documents AVB2; GOLDEN stays **unlocked/orange**.
Clone that *signing* posture, not IOdes lock.
**Bootloader / OEM unlocking (2026-10-02):** relock remains **wont** for this
Magisk track (orange + preroot). Locking with Magisk-patched boot is a brick
risk on Pixel unless the full AVB chain is enforced end-to-end — out of scope.
Keep `flash.locked=0` / `verifiedbootstate=orange`. Prefer leaving **OEM
unlocking** enabled in Developer options as a *best-effort* escape hatch for
future unlock attempts — it is **not** a guarantee of recovery, data
preservation, or rescue from every failure mode (AOSP: unlock ability is
conditional). Do **not** turn it off casually.
Wire: `vendor/sunfish-a16/BoardConfig.mk` overrides `BOARD_AVB_*` →
`vendor/sunfish-a16/certs/avb.pem` + `SHA256_RSA4096`. Leave `WITH_AVB`
unset so `--flags 3` stays (Magisk-friendly).
**What flags 3 means (libavb):** `HASHTREE_DISABLED (1) | VERIFICATION_DISABLED (2)`.
Descriptors are not enforced at boot; this is **AVB signing infrastructure**,
not “AVB-hardened verified boot”. Do not call US-S3 “AVB endurecido” while
flags stay 3. A later stage may measure `WITH_AVB=true` (flags 0) + Magisk
resign — separate acceptance.
Acceptance:
- [x] `BOARD_AVB_KEY_PATH` → project `vendor/sunfish-a16/certs/avb.pem`
- [x] Artifact gates **fail closed** on **target_files/IMAGES** (not OUT make
images): pubkey sha1 == `avb_pkmd.bin` (≠ AOSP `2597c218…`); Flags `3`;
`verify_image --key` vbmeta + `--expected_chain_partition` vbmeta_system;
Magisk boot hash matches vbmeta; `magiskboot cpio test` ≠ 0
- [x] Document clearly: runtime AVB enforce = **off** (flags 3) — not “AVB endurecido”
- [x] Device still boots unlocked; Magisk preroot intact (LAB 2026-10-02 sideload
+ boot/vbmeta reinforce; `magiskd`, `flash.locked=0`, orange)
- [x] No bootloader relock; OEM unlocking left enabled (escape hatch, not guarantee)
### Branding (no rebacon-only)
- [x] Wire `vendor/sunfish-a16/branding.mk` →
`TARGET_UNOFFICIAL_BUILD_ID=AXP-Resurection-Pro` (full Magisk track, not slim;
next bacon embeds it in `ro.lineage.version`)
- [x] Ship script publishes sibling `AXP-Resurection-Pro-*-sunfish.zip`
(hardlink/copy of Lineage bacon zip). Current artifact renamed the same way
without rebuild.
### US-S4 — Userspace hardening (first attributable pack)
See `docs/009-us-s4-userspace-hardening.md`.
- [x] Stage 0 LAB measure (Enforcing + FBE)
- [x] US-S4-1: strip Openssh/rsync/procmem packages from Lineage `common.mk`
(`apply_009_drop_openssh_packages.py`); keep `init.openssh.rc` (AXP PRO)
- [x] LAB 2026-10-02: ship `20261002T151944Z` sideloaded + reinforced;
see `docs/009-lab-acceptance-20261002-uss4.md`
- [ ] **US-S4-2** (wired, pending bacon): drop Jelly + Gallery2 (AXP PRO
product oracle — Fossify stays); `apply_009_drop_jelly_gallery2.py` +
`NoLineageJelly`; see `docs/009-axp-pro-product-apps-20260324.md`
| Candidate | Priority | Notes |
|-----------|----------|-------|
| Confirm SELinux Enforcing + encryption | **done** | LAB Enforcing + FBE |
| ptrace/Yama | **reverted 2026-10-10** | Yama off like GOLDEN; scope 2 broke PairIP (Wallapop) |
| Debug/bugreport surface trim | **done US-S4-1** | AXP PRO product oracle |
| Jelly + Gallery2 debloat | **US-S4-2 wired** | AXP PRO product; Fossify kept |
| mount flags / noexec where stock allows | early | don't break HW |
| hardened_malloc | later | Graphene/AXP; portability cost |
| Broad Graphene framework (scopes, etc.) | later / deferred | high UX cost; not Magisk-clone MVP |
Ship patches under `vendor/sunfish-a16/patches/009-axp-los23-port/hardening/` with README
attribution. One stage per bacon when risk is unclear.
### US-S5 — Kernel CVE mega / more Graphene (on boot-OK pack)
**Do not** flash old `20260918*-axp-kh-cve` / `kh-full` (logo hang).
- [x] CVE clean-offset 429 + hi-batch1–3 on Magisk ship (`151944Z` LAB OK)
- [x] **US-S5-1** LAB OK (`162840Z`): Yama since reverted to unset (PairIP) +
`CONFIG_SLAB_FREELIST_RANDOM=y` — see
`docs/009-lab-acceptance-20261002-uss5.md`
- [ ] **Next cycle after the user image is accepted** (owner 2026-10-06):
close kernel CVE + Graphene/AXP hardening + deblob on that baseline.
Boot-check each batch (full `cve-strict` ~503 and `CVE-2022-49980`
alone hang at the Google logo). Inventory: remaining high-offset KEEP,
`49980` lock-scope port, Stage1 probes that failed
(allocsize/0007, ro/0007+0034, slab/0010+0018), `hardened_malloc`,
AXP deblob that still leaves radio, GPS and Widevine working.
Still out: location lockdown, bootloader relock, KernelSU, IPA removal.
- [x] **Next-bacon recipe guard (2026-10-07):** Stage1 uses
`patch --forward`, omits already-present `misc/0021`, and fails unless
`KSYM_NAME_LEN=192`; full feature-008 call-recording apply is restored.
Quarantine the earlier `bacon00949980` build and do not flash it.
Map updates: `docs/009-kernel-hardening-map.md` + Gate G attribution.
### US-S6 — Optional later
- [ ] Confirm `lineage_sunfish-user` after flash
(bacon started 2026-10-06, tmux `009-user-bacon`, log
`/srv/rom/artifacts/detach-009-user-bacon-20261006T203157Z.log`.
PRO stays branding. Check `ro.build.type=user` and `release-keys` on LAB)
- [ ] GPG-sign published SHA sums (AXP does; nice-to-have)
- [ ] LOS23 nightly rebase (vanilla + re-apply Magisk/stage1/keys)
- [ ] Bootloader lock — **wont**
---
## Host paths
| What | Path |
|------|------|
| Platform / OTA / AVB secrets | `$HOME/.android-certs/` on rom-dev01 (2026-09-29); prefer `/srv/rom/secrets/android-certs/` after root relocate |
| Certs tar backup | `/home/android-build/backups/android-certs-20260929T1637Z.tar.gz` |
| Phonesky JKS | `/srv/rom/secrets/phonesky-signing/` |
| microG JKS | `/srv/rom/secrets/microg-signing/` |
| Keygen script (repo) | `scripts/009-generate-release-keys.sh` |
| Signing README (vendor) | `vendor/sunfish-a16/patches/009-axp-los23-port/signing/README.md` |
| GOLDEN props | `/srv/rom/references/axp/golden/2026-09-13/` |
| AXP docs (mirror) | `…/axpos.org/docs/knowledge/{signatures,verifiedboot}/` |
---
## Explicit non-goals
- Bootloader relock / green verified-boot for end users.
- Replacing Phonesky/microG keys with platform keys.
- Committing private keys or passphrases to Git.
- Treating missing lock as Gate G failure.