009: Magisk ship pack through US-S5-1 + US-S4 OpenSSH/Jelly/Gallery2.
Release-keys/AVB, CVE clean+hi batches, Yama/slabrand, Pro branding, bundled apps, and AXP-class product surface docs/scripts.
This commit is contained in:
1 parent
fd793b9471
commit
deaaf42caa
129 files changed
+11769
-141
No files matched your search
@@ -48,3 +48,7 @@ aosp-webview*.apk
|
||||
# 004 proprietary / large prebuilts (host-only)
|
||||
vendor/sunfish-a16/prebuilt/
|
||||
*.apk
|
||||
|
||||
# Local AXP OTA extracts (payload.bin ~1GB+)
|
||||
AXP.OS-*/
|
||||
*.bin
|
||||
@@ -25,6 +25,28 @@ unless the owner explicitly asks.
|
||||
Magisk, microG, and related projects — prefer these over secondary blogs
|
||||
or guesses. KernelSU docs are reference-only here (optional recycle).
|
||||
|
||||
## Clone AXP first (mandatory)
|
||||
|
||||
This track is an **AXP.OS → LOS23/A16** resurrection (~clone). Default method:
|
||||
|
||||
1. Find how AXP / EXTENDROM / GOLDEN did it **before inventing a local policy**:
|
||||
shipped PRO/GOLDEN zips (`payload.bin` → partition images),
|
||||
`/srv/rom/references/axp/` + EXTENDROM on `rom-dev01`, GOLDEN `adb`
|
||||
oracle, and real AXP product trees — **not** only Lineage-looking
|
||||
`upstream_*` mirrors on disroot.
|
||||
2. **Copy that method** into this tree (same flags, same packaging shape, same
|
||||
virgin/activation UX where applicable).
|
||||
3. Only invent or diverge when LOS 23.2, Android 16, or a newer dependency
|
||||
**breaks** the AXP path — then document why and the minimal fix.
|
||||
|
||||
Do **not** redesign Magisk, microG, Phonesky, DNS, connectivity, hardening
|
||||
package sets, or other AXP-class features “our way” for convenience.
|
||||
KernelSU/SusFS (`007`) stays **standby** — never mix into Magisk ship boots.
|
||||
|
||||
Magisk specifically: EXTENDROM `EXTENDROM_PREROOT_BOOT` (boot patch, Magisk
|
||||
**not** a `PRODUCT_PACKAGE`, dormant until Additional Setup). See
|
||||
`docs/009-magisk-preinstall-runbook.md`.
|
||||
|
||||
## Working rules
|
||||
|
||||
- Do not invent unresolved technical decisions; investigate them in the relevant
|
||||
|
||||
@@ -66,8 +66,13 @@ Checked packages (package-level; process expand not fully visible in shots):
|
||||
|
||||
Visible unchecked (partial): Aegis, Amarok, Amaze, Aosmium.
|
||||
|
||||
Owner notes: most DenyList banking apps still pass; **Yuh fails** for ~weeks.
|
||||
Extra Magia DenyList/host checks + Island uninstall/reclone did **not** fix Yuh.
|
||||
Owner notes (2026-09-13): most DenyList banking apps still pass; **Yuh failed**
|
||||
for ~weeks. Extra Magia DenyList/host checks + Island uninstall/reclone did
|
||||
**not** fix Yuh at that time.
|
||||
|
||||
**Owner update 2026-10-02:** Yuh works again on GOLDEN after enabling Vector’s
|
||||
**bootloader spoofer** module (`zygisk_vector` / Vector manager). DenyList alone
|
||||
was never enough for that HA path.
|
||||
|
||||
## Compatibility / attestation (observational)
|
||||
|
||||
@@ -75,14 +80,15 @@ Extra Magia DenyList/host checks + Island uninstall/reclone did **not** fix Yuh.
|
||||
|-------|--------|----------|
|
||||
| Swissquote | **PASS** (owner report) | Still used; on DenyList |
|
||||
| Other DenyList banks (N26, DKB, …) | **PASS** (owner: “casi todos”) | UI DenyList |
|
||||
| Yuh | **FAIL** — hardware attestation / “certificate is invalid” | Owner UI + logcat ~21:51–21:52 |
|
||||
| Yuh | **PASS again** (owner 2026-10-02) via Vector bootloader spoofer | Was **FAIL** 2026-09-13 (HA / “certificate is invalid”) |
|
||||
| Play Integrity token path | Client path still runs | `Finsky requestIntegrityToken() finished for com.yuh`; DroidGuard `pia_attest_e1` for `com.yuh` |
|
||||
| KeyMint / TEE | Errors concurrent with Yuh attempt | `keystore2`: `HARDWARE_TYPE_UNAVAILABLE` (IRPC / `TRUSTED_ENVIRONMENT`); `addRngEntropy` → `DEAD_OBJECT` / KeyMint `-1000` |
|
||||
| KeyMint / TEE | Errors concurrent with 2026-09-13 Yuh FAIL | `keystore2`: `HARDWARE_TYPE_UNAVAILABLE` (IRPC / `TRUSTED_ENVIRONMENT`); `addRngEntropy` → `DEAD_OBJECT` / KeyMint `-1000` |
|
||||
|
||||
Interpretation for later `006`/`007` (not a GOLDEN fix): DenyList alone is
|
||||
insufficient for Yuh’s hardware-attestation path; KeyMint/TEE remote-provisioning
|
||||
errors correlate with the failure window. Project production root path remains
|
||||
**KernelSU-Next (+ SusFS) or ReSukiSU evaluation** — Magisk/Magia is oracle-only.
|
||||
Interpretation for Gate E / LAB: GOLDEN banking stack = Magisk DenyList +
|
||||
`playintegrityfix` + `teesim` + **Vector bootloader spoofer** (owner-proven for
|
||||
Yuh). Ship ROM still does **not** bake those modules (`009-magisk-preinstall-runbook`);
|
||||
owner installs post-flash. Wrong PIF prints (e.g. `comet` CANARY on sunfish LAB)
|
||||
break the same surface. Magisk/Magia remains the AXP oracle path for `009`.
|
||||
|
||||
Call recording: GOLDEN Secure dump shows native EXTENDROM
|
||||
`extendrom_call_recording=1` (see `008` — port `er.sh` F_CALLREC, not Magisk
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# 009 — Remaining path to AXP / Graphene-class ship (post clean-429)
|
||||
|
||||
Non-normative roadmap after LAB **BOOT_OK** on Stage1+combo4+FORTIFY+Magisk+
|
||||
**CVE clean-offset 429** (denylist `CVE-2022-49980`), kernel `#47`
|
||||
(`20261001T180955Z-axp-stage1-combo4-cve-clean`). Authoritative requirements
|
||||
remain `specs/009-axp-los23-port/spec.md` + constitution.
|
||||
|
||||
Goal (owner): **almost all** applicable AXP.OS / Graphene-class behaviour on
|
||||
LOS 23.2 sunfish Magisk track — not a blind dump, not bootloader lock.
|
||||
|
||||
## Already landed (kernel / Magisk core)
|
||||
|
||||
| Layer | Status |
|
||||
|-------|--------|
|
||||
| Stage1 Graphene/AH | Ship |
|
||||
| Combo4 + Clang FORTIFY | Ship |
|
||||
| Magisk preroot EXTENDROM-class | Ship |
|
||||
| CVE clean-offset 429 | Ship (LAB OK) |
|
||||
| `CVE-2022-49980` | Denylist until lock-scope port |
|
||||
| High-offset CVE (~73) | Quarantine — triage started |
|
||||
|
||||
Recover/bisect baseline: `20260929T123401Z-axp-stage1-combo4` (`#32`).
|
||||
|
||||
## Kernel remaining (toward “AXP CVE / Graphene depth”)
|
||||
|
||||
1. **High-offset quarantine** — KEEP batches 1–3 **shipped** (`151944Z`).
|
||||
nf_tables leftovers still skipped. Next kernel depth: **US-S5-1** defconfig
|
||||
(Yama + `SLAB_FREELIST_RANDOM`), not more bulk CVE.
|
||||
2. **`CVE-2022-49980` proper port** — keep UAF fix without recursive
|
||||
`udc_lock` (mainline lock-scope series). Optional; denylist is safe.
|
||||
3. Failed Stage1 probes (allocsize/ro/slab) — low priority vs high-offset.
|
||||
4. Graphene modern techniques / `hardened_malloc` — backlog (`docs/hardening-backlog.md`);
|
||||
evaluate after CVE depth is stable.
|
||||
|
||||
## Userspace / product remaining (AXP surface)
|
||||
|
||||
From `docs/009-capability-matrix.md` / Gate G (still open or partial):
|
||||
|
||||
| Item | Notes |
|
||||
|------|--------|
|
||||
| Release keys + AVB (unlocked) | US-S2/S3 — leave test-keys |
|
||||
| Private DNS / connectivity check | Patches exist; keep AXP-class, no axp.os endpoints |
|
||||
| Call-rec / FLAG_SECURE | `008` — selectable unlock |
|
||||
| Bundled apps (Aurora, Droidify, gallery, …) | Packaging |
|
||||
| Disable-app UX on A16 | Restore classic Disable |
|
||||
| Hosts / DNS privacy helpers | Magisk module vs ROM-native TBD |
|
||||
| WebView | LOS default (Aosmium exception) |
|
||||
| Banking / Island | Deferred |
|
||||
| Bootloader lock | Wont |
|
||||
| KernelSU swap | Optional later; do not mix Magisk ship boots |
|
||||
|
||||
## Suggested execution order (default if owner has no preference)
|
||||
|
||||
1. Finish high-offset **relevance filter** → small apply batches (≤10) with
|
||||
strict applicator + LAB boot each batch.
|
||||
2. Wire **release keys** bacon of current ship pack; keep Magisk/preroot OK.
|
||||
3. Land remaining **Settings/UX** AXP clones (DNS, connectivity, disable-app)
|
||||
if not already on LAB zip.
|
||||
4. Optional: 49980 lock-scope port; Graphene userspace / hardened_malloc spikes.
|
||||
|
||||
## Do-not
|
||||
|
||||
- Reflash full-503 / old kh-cve zips.
|
||||
- Bulk-apply high-offset without manual review.
|
||||
- Mix KernelSU into Magisk ship boots.
|
||||
- Treat “almost AXP/Graphene” as requiring locked bootloader.
|
||||
@@ -0,0 +1,54 @@
|
||||
# AXP.OS PRO sunfish product/app surface — 20260324 zip
|
||||
|
||||
Oracle: `AXP.OS-22.2-20260324-PRO-sunfish.zip` (`payload.bin` → partitions).
|
||||
Extracted 2026-10-02 (local `payload-dumper-go`). Authoritative for **debloat**
|
||||
vs Lineage product defaults — not the disroot `upstream_*` lineage mirror.
|
||||
|
||||
## `product/app` (present)
|
||||
|
||||
Aperture, ApertureLensLauncher, Backgrounds, Camelot, DeskClock,
|
||||
ExactCalculator, LatinIME, LocalContactsBackup, ModuleMetadata, PhotoTable,
|
||||
Recorder, ThemesStub, Twelve, messaging, uimremoteclient, uimremoteserver
|
||||
|
||||
## `product/app` (absent vs typical LOS product)
|
||||
|
||||
| LOS / our prior ship | AXP PRO |
|
||||
|----------------------|---------|
|
||||
| Jelly | **absent** (browser stub on system_ext) |
|
||||
| Gallery2 | **absent** (Fossify only) |
|
||||
| Etar | **absent** (uses `Etar_ER` on system_ext) |
|
||||
| AuroraStore / Droidify / Fossify | not on product — on **system_ext** |
|
||||
| VZWAPNLib / PixelCameraServices* | absent here (device packs may differ) |
|
||||
|
||||
## `product/priv-app`
|
||||
|
||||
Contacts, Dialer, SettingsIntelligence
|
||||
|
||||
## `product/bin`
|
||||
|
||||
**No** `/bin` tree (no sshd/ssh/rsync). `etc/init/init.openssh.rc` **present**.
|
||||
|
||||
## `system_ext/app` (bundled AXP extras)
|
||||
|
||||
AuroraStore, Etar_ER, F-Droid, FossifyGallery_FD, GsfProxy_GH,
|
||||
MicrogGmsCore_GH_presigned, Profiles, AccessibilityMenu,
|
||||
QtiTelephonyService, SimpleSettingsConfig,
|
||||
`noDefaultBrowserWebView`, `noeSpeakNG`
|
||||
|
||||
## `system_ext/priv-app` (selected)
|
||||
|
||||
AOSLauncher (NeoLauncher — **wont** for 009), AOSmium_webview64
|
||||
(**exception** — we ship LOS WebView), OpenEUICC_AXP-OS, Seedvault,
|
||||
TrebuchetQuickStep, Updater, Lineage*, Settings, SystemUI, ims, …
|
||||
|
||||
## 009 mapping
|
||||
|
||||
| AXP | Our ship policy |
|
||||
|-----|-----------------|
|
||||
| AuroraStore | product `AuroraStore` (already) |
|
||||
| F-Droid | **Droidify** substitute (owner) |
|
||||
| FossifyGallery_FD | product `FossifyGallery` + override Gallery2 |
|
||||
| noDefaultBrowserWebView | **US-S4-2**: drop Jelly |
|
||||
| Gallery2 absent | **US-S4-2**: ensure Gallery2 gone (override alone left dir) |
|
||||
| NeoLauncher / Aosmium | wont / exception — keep Launcher3 + LOS WebView |
|
||||
| OpenSSH bins | US-S4-1 done |
|
||||
@@ -0,0 +1,58 @@
|
||||
# 009 AXP capability matrix (resurrection track)
|
||||
|
||||
Maps GOLDEN/`002` + `docs/axp-pro-parity.md` → ship status for **Magisk AXP
|
||||
clone on LOS23**. Authoritative requirements remain `specs/009-axp-los23-port/spec.md`.
|
||||
|
||||
Status: `required` | `exception` | `deferred` | `impossible`
|
||||
|
||||
| category | golden_ref | status | notes |
|
||||
|----------|------------|--------|-------|
|
||||
| Base LOS 23.2 sunfish | `003` | required | Vanilla baseline before AXP integrate |
|
||||
| microG + GSF | `002` / `004` | required | Newest stable |
|
||||
| Phonesky (project patched) | `002` / `004` | required | Host artifact; FakeStore forbidden |
|
||||
| Selectable signature spoofing | `005` / GOLDEN `allow_signature_fake` | required | Restricted; DO toggle |
|
||||
| Selectable call-recording unlock | `008` / GOLDEN `extendrom_call_recording` | required | EXTENDROM key |
|
||||
| Magisk preroot + DenyList-class | GOLDEN Magisk 29.0 / Magia | required | Newest Magisk; EXTENDROM-class boot patch |
|
||||
| Bundled usability apps (Aurora, Droidify, gallery, …) | `002` / parity | required | Newest workable; **Droidify** (light + many default repos); **no NeoLauncher** |
|
||||
| Private DNS presets (AXP-class provider list) | AXP Settings | required | Clone AXP private-DNS entries; no AXP OTA/repos |
|
||||
| Internet connectivity / INTERNET special permission UX | AXP/Graphene-class | required | Keep behaviour; **do not** integrate `axp.os` endpoints/branding |
|
||||
| Disable app (classic) vs Archive | AOSP/LOS A16 Archive | required | Restore usable **Disable** on A16; Archive alone disliked by owner |
|
||||
| DNS/hosts privacy helpers | parity / GOLDEN modules `hosts` | required | If in AXP surface; Magisk module vs ROM-native TBD |
|
||||
| Userspace hardening / AVB (unlocked) | parity `011`–`012` pulled into `009` | required | Staged; gaps documented; no bootloader lock |
|
||||
| Release / definitive signing keys | GOLDEN / plan `/srv/rom/secrets` | required | Ship off test-keys; Phonesky same identity |
|
||||
| Bootloader lock / relock | IOdes-class | wont | AXP/LOS unlocked norm; Magisk preroot assumes unlocked |
|
||||
| Kernel update + hardening | parity / FR-017 | required | LOS23 sunfish kernel + attributable patches |
|
||||
| WebView | GOLDEN Aosmium | exception | LOS23 WebView default; chooser unlocked; no Aosmium |
|
||||
| Banking / Island / Swissquote / Yuh | `002` Gate E | deferred | Owner future (2026-09-17); not MVP |
|
||||
| Localization / location hardening AXP vs LOS | owner complaint | deferred | FR-018 — **do not extra-cap** vs LOS for ship (2026-09-18); no MVP toggle; compare doc later only |
|
||||
| NeoLauncher | AXP default | wont | Owner: do not integrate; LOS Launcher3 |
|
||||
| F-Droid client (`org.fdroid.fdroid`) | GOLDEN | substitute | Prefer **Droidify** |
|
||||
| AXP external market repos / AXP OTA servers | AXP EOL infra | wont | Servers down / EOL — do not wire |
|
||||
| Sideloadable system package refresh (microG, Magisk, Phonesky, …) | owner cadence ~2–3 mo | required | FR-019 — same-signer / PRESIGNED / Magisk update path; no OTA |
|
||||
| KernelSU / SusFS | `007` | deferred | Out of ship; optional recycle FR-016 |
|
||||
| AXP backup ROM feature | parity | impossible / wont | External NeoBackup only |
|
||||
| FLAG_SECURE global override | project `008` | deferred | Nice-to-have; not AXP hard gate |
|
||||
|
||||
## Bundled packages observed on GOLDEN (2026-09-17 `pm list packages -s`)
|
||||
|
||||
| package | role | matrix |
|
||||
|---------|------|--------|
|
||||
| `com.aurora.store` | Aurora | required (pin newest) |
|
||||
| `com.looker.droidify` | Droidify (F-Droid client) | required — preferred over `org.fdroid.fdroid` |
|
||||
| `org.fdroid.fdroid` | F-Droid | substitute / skip unless packaging forces it |
|
||||
| `org.fossify.gallery` | Fossify Gallery | required |
|
||||
| `com.stevesoltys.seedvault` | Seedvault | often los-provides |
|
||||
| `com.android.launcher3` | Launcher | los-provides — **no NeoLauncher** |
|
||||
| `org.axpos.aosmium` / `_wv` | Aosmium | exception — do not ship; LOS WebView |
|
||||
| `com.google.android.gsf` | GSF | required |
|
||||
| `com.android.vending` | Phonesky | required (project artifact) |
|
||||
|
||||
User-installed (not system): Island, banks, Magisk manager (hidden pkg), etc.
|
||||
|
||||
## Build oracle note
|
||||
|
||||
Prefer AXP **build tree + docs** on `rom-dev01` (see axpos.org developer
|
||||
building / EXTENDROM preroot) to learn Magisk/product packaging. GOLDEN `adb`
|
||||
is for runtime behaviour, not the first compile reference. Host currently has
|
||||
rendered docs under `/srv/rom/references/axp/archive/…`; full AXP `build`
|
||||
checkout still to stage.
|
||||
@@ -0,0 +1,171 @@
|
||||
# 009 CVE bisect plan (after full CVE Google-logo hang)
|
||||
|
||||
**Baseline GOOD:** Stage1 + combo4 + Clang FORTIFY
|
||||
Artifact: `20260929T123401Z-axp-stage1-combo4` (LAB recovered 2026-09-29 via
|
||||
`fastboot flash boot` of that pack’s Magisk `boot.img`).
|
||||
|
||||
**BAD:** Stage1+combo4+FORTIFY + full `cve-strict.list` (503)
|
||||
Artifact: `20260929T181525Z-axp-stage1-combo4-cve` — compiles, wlan CRC OK,
|
||||
**hangs at Google logo**. **Do not** re-flash the full 503 set.
|
||||
|
||||
## Audit before more flashes (2026-09-29 evening)
|
||||
|
||||
Owner review correctly flagged the applicator and asked for reject/partial
|
||||
review **before** bisect flashes.
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| Patch `FAIL` count on BAD build | **0** (`OK=503`) — no `.rej` from that run |
|
||||
| Continue-on-fail + delete `.rej` | **Procedural defect** (fixed in `apply_cve_strict.sh`) — would hide incomplete applies on future drift |
|
||||
| GNU patch “Succeeded with fuzz≥2” | **0** |
|
||||
| Hunks with **\|offset\| ≥ 200 lines** | **168** of 503 — strong mis-apply risk even when `patch` exits 0 |
|
||||
| \|offset\| ≥ 200 list | `cve-high-offset-ge200.txt` (**73 unique** paths in report extract; full 168 in host fuzz report) |
|
||||
| Host report | `/srv/rom/artifacts/009-axp-los23-port/cve-stage/apply-cve-strict-20260929T173037Z-fuzz-report.txt` |
|
||||
|
||||
Logo hang alone does **not** identify a CVE id; “Additional Setup” is unrelated.
|
||||
USB loss after sideload does **not** mean the zip was not installed.
|
||||
|
||||
### Applicator fix (`apply_cve_strict.sh`)
|
||||
|
||||
- Default: **abort** on first FAIL (no partial tree).
|
||||
- Keep `*.rej` / `*.orig` under `CVE_REJECT_DIR` (no silent delete).
|
||||
- **QUALITY_FAIL** if fuzz ≥ `CVE_MAX_FUZZ` (default 1) or
|
||||
\|offset\| ≥ `CVE_MAX_ABS_OFFSET` (default **200**).
|
||||
- Forensic only: `CVE_STRICT_CONTINUE=1`.
|
||||
|
||||
H1 bacon (`009-bacon-cve-h1`) **stopped** — do not flash that half until a
|
||||
strict re-apply (offsets gated) produces a clean tree.
|
||||
|
||||
## Next method (revised)
|
||||
|
||||
1. Build allowlist = `cve-strict.list` **minus** high-offset (≥200) suspects
|
||||
(and existing denylist).
|
||||
2. Re-apply with new applicator (must finish with QUALITY_FAIL=0 / abort).
|
||||
3. Bacon that “clean-offset” set → LAB boot test (**fastboot flash boot** only;
|
||||
recover with Stage1 boot if needed).
|
||||
4. If still BAD → classic binary bisect on the **clean** list only.
|
||||
5. Separately, quarantine high-offset patches for manual review / port
|
||||
(do not bulk-apply with huge offsets).
|
||||
|
||||
## Flash rules (LAB)
|
||||
|
||||
1. sunfish recovery is in `boot` — bad kernel ⇒ Recovery looks like logo loop.
|
||||
2. Unbrick: `fastboot -s 11231JEC207477 flash boot <GOOD boot.img>` → reboot.
|
||||
**Always** pin LAB serial. Never flash “any” fastboot device (GOLDEN risk).
|
||||
3. No reboot-loop automation. No unscoped recover watchers.
|
||||
4. One reboot after a deliberate flash.
|
||||
|
||||
## Diagnostic limits (owner review 2026-09-30)
|
||||
|
||||
- A BAD half **reproduces** the hang; it does **not** prove a single CVE is the
|
||||
root cause (interactions / order / mis-apply semantics still possible).
|
||||
- Applicator had **0 FAIL** on the original full set; abort/offset gates were
|
||||
still required, but they did **not** clear this logo hang.
|
||||
- Bisect flashes are **`boot.img` only** on `boot_a` (serial-pinned). No slot /
|
||||
download / flash miss seen on H1a2: hang tracks what H1a2 changes vs Stage1
|
||||
base. **No** demonstrated need to re-sideload full zip or wipe data for this
|
||||
bisect.
|
||||
- “CRC wlan OK” so far = host-side `kmalloc_caches` only (kernel
|
||||
`Module.symvers` vs pack `wlan.ko`). Does **not** check all symbols nor the
|
||||
on-device installed module (adb pull denied without root). Narrows one
|
||||
suspicion; does **not** rule out module ABI skew.
|
||||
- Next interpretation: if H1a2a boots, still test H1a2b. If **both** boot alone
|
||||
but H1a2 fails → interaction/dependency, not a single-patch proof.
|
||||
- **Applicability (owner 2026-10-01):** AXP A15 success ≠ correct port to
|
||||
LOS23/A16 sunfish. Per [kernel CVE process](https://cdn.kernel.org/doc/html/latest/process/cve.html),
|
||||
each CVE must be judged for *this* tree/config/modules — not bulk-trusted.
|
||||
H1a2b includes useful fixes (USB gadget UAF, QC audio DSP bounds, F2FS
|
||||
state, QRTR) but also arch/drivers off in our defconfig (x86/AMD, s390,
|
||||
CAN/ATA/SAS/kprobes/brcmfmac, …). These are mostly **bugfixes**, not
|
||||
transversal hardening like FORTIFY/allocator. Concrete hypothesis (unproven):
|
||||
`CVE-2022-49980` (`udc_lock` on gadget events) — check whether this tree
|
||||
already holds that lock on the same paths (possible deadlock). Also re-audit
|
||||
F2FS patches vs exact sunfish F2FS version/deps. **In H1a2b1b list**
|
||||
(not H1a2b1a).
|
||||
|
||||
### Code review: CVE-2022-49980 vs msm-4.14 (2026-10-01)
|
||||
|
||||
Patch only wraps `udc->driver` read in `usb_udc_uevent()` with
|
||||
`mutex_lock(&udc_lock)`. On **our** `msm-4.14` `udc/core.c` (base
|
||||
`28f9290ae067`, pre-CVE apply), `kobject_uevent()` is still invoked **while
|
||||
holding `udc_lock`**:
|
||||
|
||||
- `usb_gadget_remove_driver()` → `KOBJ_CHANGE` (called from
|
||||
`usb_del_gadget_udc` / `usb_gadget_unregister_driver` under lock)
|
||||
- `udc_bind_to_driver()` → `KOBJ_CHANGE` (called from
|
||||
`usb_gadget_probe_driver` under lock)
|
||||
|
||||
`dev_uevent` / `class->dev_uevent` run **synchronously** inside
|
||||
`kobject_uevent`. `udc_lock` is a non-recursive `mutex`. Applying 49980 alone
|
||||
⇒ same thread: lock → uevent → `usb_udc_uevent` → lock again ⇒ **deadlock**.
|
||||
|
||||
This matches community reports that backporting CVE-2022-49980 to older trees
|
||||
(e.g. 5.10.y) introduces deadlock; mainline later needed **lock-scope**
|
||||
changes (unbind/bind outside `udc_lock`), not the one-liner alone.
|
||||
|
||||
sunfish_defconfig: `CONFIG_USB_GADGET=y`, rich `CONFIG_USB_CONFIGFS_*` (ADB /
|
||||
MTP / etc.) — gadget bind/unbind at boot is plausible. Still **hypothesis**
|
||||
until H1a2b1b (or a 49980-only build) is LAB-tested; do **not** ship 49980
|
||||
without the companion lock-order fix (or omit it from the allowlist).
|
||||
|
||||
**2026-10-01 evening:** 49980-only LAB = BAD (logo). Deadlock paths on this
|
||||
tree include both (a) `device_add` / uevent under `udc_lock` at UDC register
|
||||
and (b) `kobject_uevent` from remove/bind while lock held. Serial console /
|
||||
pstore stack not captured yet — would confirm hang site; denylist stands.
|
||||
|
||||
## GPS
|
||||
|
||||
FR-018: no location lockdown.
|
||||
|
||||
## Status
|
||||
|
||||
- [x] Full CVE = BAD (logo); documented do-not-reflash
|
||||
- [x] Audit apply log (0 FAIL, many huge offsets)
|
||||
- [x] Fix applicator abort + keep rejects + offset/fuzz gate
|
||||
- [x] Stop premature H1 bacon (full-503 halves archived `*.full503.bak`)
|
||||
- [x] Clean-offset allowlist bacon + LAB boot
|
||||
Artifact `20260929T203844Z-axp-stage1-combo4-cve-clean` (430 patches,
|
||||
QUALITY_FAIL=0) — **BAD** 2026-09-29T20:42Z: `fastboot flash boot`
|
||||
OK on `boot_a`, then Google-logo hang / USB dark (~4+ min). Recover =
|
||||
Stage1 `20260929T123401Z-axp-stage1-combo4` boot only.
|
||||
- [x] Clean H1 (215) bacon + LAB boot — artifact
|
||||
`20260929T213532Z-axp-stage1-combo4-cve-h1` — **BAD** 2026-09-30
|
||||
(logo). H1 **reproduces**; H2 untested; not a single-CVE ID yet.
|
||||
- [x] H1a (108) — `20260930T075006Z-…-cve-h1a` **BAD** (logo). H1a
|
||||
**reproduces**; interaction possible; module coherence not yet checked
|
||||
for CVE boots.
|
||||
- [x] H1a1 (54) — `20260930T084048Z-…-cve-h1a1` **BOOT_OK** 2026-09-30T19:21Z
|
||||
(kernel `#38`, slot `_a`). Build-tree `wlan`/`kmalloc_caches` CRC
|
||||
`0xe7ccd971` matches Stage1 Gate G (device pull of `wlan.ko` denied
|
||||
without root; intra-pack CRC OK). H1a1 set alone does **not** reproduce
|
||||
the hang.
|
||||
- [x] H1a2 (54) — `20260930T200752Z-…-cve-h1a2` **BAD** (owner: Google logo
|
||||
after flash; reproduces). H1a1 GOOD + H1a2 BAD ⇒ hang associated with
|
||||
H1a2 set (still not a single id; module CRC intra-pack was Stage1-class
|
||||
on prior boots).
|
||||
- [x] H1a2a (27) — `20260930T213106Z-…-cve-h1a2a` **BOOT_OK** 2026-09-30T21:36Z
|
||||
(kernel `#40`). Host `kmalloc_caches` match. Alone does **not** reproduce.
|
||||
- [x] H1a2b (27) — `20260930T222148Z-…-cve-h1a2b` **BAD** (logo alone).
|
||||
H1a2a GOOD + H1a2b BAD ⇒ hang associated with H1a2b set (not proven
|
||||
single patch). Note: owner phrasing “combi” = this half failed on LAB;
|
||||
interaction check already satisfied by testing halves separately.
|
||||
- [x] H1a2b1 (14) — `20260930T231324Z-…-cve-h1a2b1` **BAD** (logo). Includes
|
||||
`CVE-2022-49980` (udc_lock hypothesis). Set of 14 reproduces.
|
||||
- [x] H1a2b1a (7) — `20261001T001808Z-…-cve-h1a2b1a` **BOOT_OK** 2026-10-01
|
||||
(kernel `#43`). No `CVE-2022-49980` in this half.
|
||||
- [x] H1a2b1b (7, includes `CVE-2022-49980`) —
|
||||
`20261001T010705Z-…-cve-h1a2b1b` **BAD** 2026-10-01 (logo). H1a2b1a
|
||||
GOOD + H1a2b1b BAD ⇒ hang associated with this 7-set (49980 still
|
||||
unproven alone).
|
||||
- [x] **49980-only** — `20261001T160836Z-…-cve-49980-only` **BAD** 2026-10-01
|
||||
(logo). Single-patch reproduce on LAB. Added to `cve-denylist.txt`.
|
||||
Do not re-apply without lock-scope companion fix.
|
||||
- [x] H1a2b1b **without** 49980 (6) —
|
||||
`20261001T170442Z-…-cve-h1a2b1b-no49980` **BOOT_OK** 2026-10-01
|
||||
(kernel `#46`, LAB `11231JEC207477`). Confirms 49980 was the **sole**
|
||||
hang trigger in the H1a2b→…→H1a2b1b BAD lineage (other six alone OK).
|
||||
- [x] Clean-offset **minus 49980** (429) —
|
||||
`20261001T180955Z-axp-stage1-combo4-cve-clean` **BOOT_OK** 2026-10-01
|
||||
(kernel `#47`). List md5 `e05056f6…`; apply OK=429. Prior BAD 430 pack
|
||||
`20260929T203844Z-…` kept. **49980 was the only logo hang** found in the
|
||||
clean-offset set so far. 15m poll loop stopped after flash.
|
||||
@@ -0,0 +1,83 @@
|
||||
# high-offset triage 2026-10-01T18:18:58+00:00
|
||||
# list=/srv/rom/src/lineage/vendor/sunfish-a16/patches/009-kernel-hardening/cve-high-offset-ge200.txt count=73
|
||||
mmfs, CVE-2020-29372/^5.7/0001.patch mm: check that mm is still valid in madvise() mm/madvise.c,
|
||||
other, CVE-2021-47209/^5.15/0001.patch sched/fair: Prevent dead task groups from regaining cfs_rq's kernel/sched/autogroup.c,kernel/sched/core.c,kernel/sched/fair.c,kernel/sched/rt.c,kernel/sched/sched.h,
|
||||
net, CVE-2021-47299/^5.13/0001.patch xdp, net: Fix use-after-free in bpf_xdp_link_release net/core/dev.c,
|
||||
offarch, CVE-2022-48825/^5.17/0001.patch scsi: qedf: Add stag_work to all the vports drivers/scsi/qedf/qedf_main.c,
|
||||
net, CVE-2022-48969/^6.1/0001.patch xen-netfront: Fix NULL sring after live migration drivers/net/xen-netfront.c,
|
||||
net, CVE-2022-49086/ANY/0001.patch net: openvswitch: fix leak of nested actions net/openvswitch/flow_netlink.c,
|
||||
net, CVE-2022-49341/ANY/0001.patch bpf, arm64: Clear prog->jited_len along prog->jited arch/arm64/net/bpf_jit_comp.c,
|
||||
mmfs, CVE-2022-49412/ANY/0001.patch bfq: Avoid merging queues with different parents block/bfq-iosched.c,
|
||||
other, CVE-2022-49641/ANY/0001.patch sysctl: Fix data races in proc_douintvec(). kernel/sysctl.c,
|
||||
net, CVE-2022-49687/ANY/0001.patch virtio_net: fix xdp_rxq_info bug after suspend/resume drivers/net/virtio_net.c,
|
||||
net, CVE-2022-49695/ANY/0001.patch igb: fix a use-after-free issue in igb_clean_tx_ring drivers/net/ethernet/intel/igb/igb_main.c,
|
||||
other, CVE-2022-49715/ANY/0001.patch irqchip/gic-v3: Fix refcount leak in gic_populate_ppi_partitions drivers/irqchip/irq-gic-v3.c,
|
||||
usb, CVE-2022-50246/ANY/0001.patch usb: typec: tcpci: fix of node refcount leak in tcpci_register_port() drivers/usb/typec/tcpm/tcpci.c,
|
||||
other, CVE-2022-50304/ANY/0001.patch mtd: core: fix possible resource leak in init_mtd() drivers/mtd/mtdcore.c,
|
||||
net, CVE-2023-3777/^6.5/0001.patch netfilter: nf_tables: skip bound chain on rule flush net/netfilter/nf_tables_api.c,
|
||||
other, CVE-2023-52486/^6.7/0001.patch drm: Don't unref the same fb many times by mistake due to deadlock drivers/gpu/drm/drm_plane.c,
|
||||
other, CVE-2023-52676/^6.7/0001.patch bpf: Guard stack limits against 32bit overflow kernel/bpf/verifier.c,
|
||||
other, CVE-2023-52707/^6.2/0001.patch sched/psi: Fix use-after-free in ep_remove_wait_queue() kernel/sched/psi.c,
|
||||
other, CVE-2023-52847/^6.6/0001.patch media: bttv: fix use after free error due to btv->timeout timer drivers/media/pci/bt8xx/bttv-driver.c,
|
||||
other, CVE-2023-53594/ANY/0001.patch driver core: fix resource leak in device_add() drivers/base/core.c,
|
||||
net, CVE-2023-53669/ANY/0001.patch tcp: fix skb_copy_ubufs() vs BIG TCP net/core/skbuff.c,
|
||||
other, CVE-2023-53709/ANY/0001.patch ring-buffer: Handle race between rb_move_tail and rb_check_pages kernel/trace/ring_buffer.c,
|
||||
offarch, CVE-2024-2201/^6.9/0001.patch x86/bugs: Change commas to semicolons in 'spectre_v2' sysfs file arch/x86/kernel/cpu/bugs.c,
|
||||
offarch, CVE-2024-24855/^6.4/0001.patch scsi: lpfc: Fix a possible data race in lpfc_unregister_fcf_rescan() drivers/scsi/lpfc/lpfc_hbadisc.c,
|
||||
net, CVE-2024-26643/^6.8/0001.patch netfilter: nf_tables: mark set as dead when unbinding anonymous set net/netfilter/nf_tables_api.c,
|
||||
other, CVE-2024-26900/^6.8/0001.patch md: fix kmemleak of rdev->serial drivers/md/md.c,
|
||||
net, CVE-2024-39296/^6.9/0001.patch bonding: fix oops during rmmod drivers/net/bonding/bond_main.c,
|
||||
mmfs, CVE-2024-40917/^6.10/0001.patch memblock: make memblock_set_node() also warn about use of mm/memblock.c,
|
||||
net, CVE-2024-40923/^6.10/0001.patch vmxnet3: disable rx data ring on dma allocation failure drivers/net/vmxnet3/vmxnet3_drv.c,
|
||||
net, CVE-2024-40954/^6.10/0001.patch net: do not leave a dangling sk pointer, when socket creation fails net/core/sock.c,
|
||||
mmfs, CVE-2024-41014/^6.10/0001.patch xfs: add bounds checking to xlog_recover_process_data fs/xfs/xfs_log_recover.c,
|
||||
net, CVE-2024-43879/^6.10/0001.patch wifi: cfg80211: handle 2x996 RU allocation in net/wireless/util.c,
|
||||
net, CVE-2024-46754/^6.10/0001.patch bpf: Remove tst_run from lwt_seg6local_prog_ops. net/core/filter.c,
|
||||
offarch, CVE-2024-46830/^6.11/0001.patch KVM: x86: Acquire kvm->srcu when handling KVM_SET_VCPU_EVENTS arch/x86/kvm/x86.c,
|
||||
net, CVE-2024-50186/^6.12/0001.patch net: explicitly clear the sk pointer, when pf->create fails net/socket.c,
|
||||
mmfs, CVE-2024-50273/^6.11/0001.patch btrfs: reinitialize delayed ref list after deleting it from the list fs/btrfs/delayed-ref.c,
|
||||
mmfs, CVE-2024-53066/^6.12/0001.patch nfs: Fix KMSAN warning in decode_getfattr_attrs() fs/nfs/inode.c,
|
||||
mmfs, CVE-2024-53173/ANY/0002.patch NFSv4.0: Fix a use-after-free problem in the asynchronous open() fs/nfs/nfs4proc.c,
|
||||
mmfs, CVE-2024-53217/ANY/0002.patch NFSD: Prevent NULL dereference in nfsd4_process_cb_update() fs/nfsd/nfs4callback.c,
|
||||
net, CVE-2024-53240/ANY/0001.patch xen/netfront: fix crash when removing device drivers/net/xen-netfront.c,
|
||||
mmfs, CVE-2024-56558/ANY/0001.patch nfsd: make sure exp active before svc_export_show fs/nfsd/export.c,
|
||||
other, CVE-2024-56569/ANY/0001.patch ftrace: Fix regression with module command in stack_trace_filter kernel/trace/ftrace.c,
|
||||
mmfs, CVE-2024-56596/ANY/0002.patch jfs: fix array-index-out-of-bounds in jfs_readdir fs/jfs/jfs_dtree.c,
|
||||
mmfs, CVE-2024-56598/ANY/0002.patch jfs: array-index-out-of-bounds fix in dtReadFirst fs/jfs/jfs_dtree.c,
|
||||
net, CVE-2024-56605/ANY/0002.patch Bluetooth: L2CAP: do not leave dangling sk pointer on error in net/bluetooth/l2cap_sock.c,
|
||||
mmfs, CVE-2024-56779/ANY/0002.patch nfsd: fix nfs4_openowner leak when concurrent nfsd4_open occur fs/nfsd/nfs4state.c,
|
||||
offarch, CVE-2024-57849/ANY/0002.patch s390/cpum_sf: Handle CPU hotplug remove during sampling arch/s390/kernel/perf_cpum_sf.c,
|
||||
net, CVE-2024-58009/ANY/0001.patch Bluetooth: L2CAP: handle NULL sock pointer in l2cap_sock_alloc net/bluetooth/l2cap_sock.c,
|
||||
other, CVE-2024-58083/ANY/0001.patch KVM: Explicitly verify target vCPU is online in kvm_get_vcpu() include/linux/kvm_host.h,
|
||||
mmfs, CVE-2025-21671/ANY/0001.patch zram: fix potential UAF of zram table drivers/block/zram/zram_drv.c,
|
||||
net, CVE-2025-21909/ANY/0001.patch wifi: nl80211: reject cooked mode if it is set along with other flags net/wireless/nl80211.c,
|
||||
net, CVE-2025-37789/ANY/0001.patch net: openvswitch: fix nested key length validation in the set() net/openvswitch/flow_netlink.c,
|
||||
net, CVE-2025-37795/ANY/0001.patch wifi: mac80211: Update skb's control block key in net/mac80211/tx.c,
|
||||
mmfs, CVE-2025-37839/ANY/0001.patch jbd2: remove wrong sb->s_sequence check fs/jbd2/journal.c,
|
||||
other, CVE-2025-37923/ANY/0001.patch tracing: Fix oob write in trace_seq_to_buffer() kernel/trace/trace.c,
|
||||
net, CVE-2025-37932/ANY/0001.patch sch_htb: make htb_qlen_notify() idempotent net/sched/sch_htb.c,
|
||||
other, CVE-2025-38034/ANY/0001.patch btrfs: correct the order of prelim_ref arguments in btrfs__prelim_ref include/trace/events/btrfs.h,
|
||||
other, CVE-2025-38044/ANY/0001.patch media: cx231xx: set device_caps for 417 drivers/media/usb/cx231xx/cx231xx-417.c,
|
||||
net, CVE-2025-38200/ANY/0001.patch i40e: fix MMIO write access to an invalid page in i40e_clear_hw drivers/net/ethernet/intel/i40e/i40e_common.c,
|
||||
mmfs, CVE-2025-38204/ANY/0001.patch jfs: fix array-index-out-of-bounds read in add_missing_indices fs/jfs/jfs_dtree.c,
|
||||
mmfs, CVE-2025-38218/ANY/0001.patch f2fs: fix to do sanity check on sit_bitmap_size fs/f2fs/super.c,
|
||||
other, CVE-2025-38285/ANY/0001.patch bpf: Fix WARN() in get_bpf_raw_tp_regs kernel/trace/bpf_trace.c,
|
||||
net, CVE-2025-38473/ANY/0001.patch Bluetooth: Fix null-ptr-deref in l2cap_sock_resume_cb() net/bluetooth/l2cap_sock.c,
|
||||
other, CVE-2025-38495/ANY/0001.patch HID: core: ensure the allocated report buffer can contain the drivers/hid/hid-core.c,
|
||||
mmfs, CVE-2025-38498/ANY/0002.patch do_change_type(): refuse to operate on unmounted/not ours mounts fs/namespace.c,
|
||||
other, CVE-2025-39742/ANY/0001.patch RDMA: hfi1: fix possible divide-by-zero in find_hw_thread_mask() drivers/infiniband/hw/hfi1/affinity.c,
|
||||
audio, CVE-2025-39751/ANY/0001.patch ALSA: hda/ca0132: Fix buffer overflow in add_tuning_control sound/pci/hda/patch_ca0132.c,
|
||||
other, CVE-2025-39824/ANY/0001.patch HID: asus: fix UAF via HID_CLAIMED_INPUT validation drivers/hid/hid-asus.c,
|
||||
net, CVE-2025-39847/ANY/0001.patch ppp: fix memory leak in pad_compress_skb drivers/net/ppp/ppp_generic.c,
|
||||
net, CVE-2025-39874/ANY/0001.patch macsec: sync features on RTM_NEWLINK drivers/net/macsec.c,
|
||||
other, CVE-2025-39998/ANY/0001.patch scsi: target: target_core_configfs: Add length check to avoid buffer drivers/target/target_core_configfs.c,
|
||||
net, CVE-2025-40078/ANY/0001.patch bpf: Explicitly check accesses to bpf_sock_addr net/core/filter.c,
|
||||
mmfs, CVE-2025-40080/ANY/0001.patch nbd: restrict sockets to TCP and UDP drivers/block/nbd.c,
|
||||
--- counts ---
|
||||
27 net,
|
||||
21 other,
|
||||
18 mmfs,
|
||||
5 offarch,
|
||||
1 usb,
|
||||
1 audio,
|
||||
1 --- counts ---
|
||||
@@ -0,0 +1,123 @@
|
||||
# FORTIFY: auditoría del build 20260926T183144Z
|
||||
|
||||
Revisión de solo lectura en rom-dev01. Sin compilaciones ni flasheos nuevos.
|
||||
El dueño confirma arranque de ksync-slab y fallo del último FORTIFY.
|
||||
|
||||
## Artefactos y empaquetado
|
||||
|
||||
Raíz remota: `/srv/rom/artifacts/009-axp-los23-port/`.
|
||||
|
||||
- Referencia: `20260926T171215Z-bisect-ksync-slab-only`.
|
||||
- Fallido: `20260926T183144Z-bisect-ksync-fortify-only/boot-make.img`.
|
||||
- SHA-256 registrado del fallido:
|
||||
`89734e6a34f99bfdc2d334e06e1ff49da46dac311139b7dc54f25ae7af0f0641`.
|
||||
- Ambos ramdisks desempaquetados tienen SHA-256
|
||||
`c9ebabdcec875c896530214c5f2988e30a6bc37754855e4cba4863692d7db519`.
|
||||
- Ambos DTB tienen SHA-256
|
||||
`2fca15709ff6d9f48fea938952439e8d00c2b998c73e7a216172ae3965b07566`.
|
||||
- El header del FORTIFY conserva Android 16 y parche `2026-09`.
|
||||
- El script usa breakfast y exige TARGET_RELEASE=bp4a.
|
||||
|
||||
El problema anterior de cambiar la release/ramdisk no aparece en esta comparación.
|
||||
La config embebida del fallido tiene FORTIFY=y, SLAB_FREELIST_HARDENED=n;
|
||||
la referencia slab tiene las dos opciones al revés. Ambos conservan LTO y CFI.
|
||||
|
||||
## Hallazgo principal: la exclusión de Clang es ineficaz
|
||||
|
||||
En `/srv/rom/src/lineage/kernel/google/msm-4.14/security/Kconfig:190-195`:
|
||||
|
||||
```text
|
||||
config FORTIFY_SOURCE
|
||||
bool "Harden common str/mem functions against buffer overflows"
|
||||
depends on ARCH_HAS_FORTIFY_SOURCE
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=50322
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=41459
|
||||
depends on !CC_IS_CLANG
|
||||
```
|
||||
|
||||
`git grep` no encuentra una definición de `CC_IS_CLANG` en ese árbol.
|
||||
La config generada tampoco contiene CONFIG_CC_IS_CLANG. La restricción usa
|
||||
un símbolo no definido y por ello no detecta el compilador real.
|
||||
|
||||
`obj/KERNEL_OBJ/include/generated/compile.h` identifica **Clang 21.0.0,
|
||||
r563880c, LLD 21**, no GCC. El commit que introdujo la restricción es
|
||||
`eb4c4383950d`, «fortify: Explicitly disable Clang support».
|
||||
|
||||
Esto demuestra un defecto de integración/configuración. No demuestra por sí
|
||||
solo la instrucción concreta que provoca el fallo de arranque. Un Clang más
|
||||
nuevo no sustituye automáticamente las adaptaciones del código FORTIFY.
|
||||
|
||||
Referencia primaria de las adaptaciones upstream: Kees Cook,
|
||||
[fortify: Add Clang support, v7 8/8](https://lists.openwall.net/linux-kernel/2022/02/08/1547).
|
||||
La serie adapta wrappers y atributos de tamaño de objeto; no consiste en
|
||||
añadir cuerpos BUG a símbolos sin resolver. El parche AXP
|
||||
`0008-Graphene-Kernel_Hardening-fortify/4.14/0004.patch`, inspeccionado, añade
|
||||
comprobaciones intra-object; no aporta por sí solo ese soporte Clang.
|
||||
|
||||
## Segundo defecto: el error de enlace se convirtió en código ejecutable
|
||||
|
||||
Primer intento, log remoto
|
||||
`/srv/rom/artifacts/detach-009-bisect-ksync-fortify-20260926T172516Z.log`:
|
||||
|
||||
```text
|
||||
ERROR: "__read_overflow2" [techpack/audio/dsp/q6_dlkm.lto.ko] undefined!
|
||||
ERROR: "__read_overflow" [drivers/staging/qcacld-3.0/wlan.lto.ko] undefined!
|
||||
```
|
||||
|
||||
El script `scripts/009-bisect-ksync-one.sh` añade después a `lib/string.c`
|
||||
cuatro funciones exportadas (`__read_overflow`, `__read_overflow2`,
|
||||
`__read_overflow3`, `__write_overflow`) con cuerpo `BUG()`.
|
||||
Así consigue enlazar, pero no resuelve por qué el compilador emite llamadas
|
||||
a esos helpers, declarados para diagnóstico en `include/linux/string.h:241`.
|
||||
|
||||
El objeto generado `techpack/audio/dsp/q6_dlkm.ko`, desensamblado, contiene:
|
||||
|
||||
```text
|
||||
rtac_remove_voice + 0x1d0, offset 0x673ec:
|
||||
R_AARCH64_CALL26 __read_overflow2
|
||||
```
|
||||
|
||||
El código asociado incluye la copia de elementos en `shift_voice_devices`
|
||||
(`techpack/audio/dsp/rtac.c:638-644`). Falta resolver si el diagnóstico indica
|
||||
un acceso real fuera de límites o un problema de los wrappers/compilador.
|
||||
No convertirlo en un no-op ni aceptar BUG como solución.
|
||||
|
||||
**Límite importante:** el ensayo despliega solo boot y conserva los módulos
|
||||
vendor previos. Esta llamada existe en el módulo recién compilado, pero no
|
||||
se ha demostrado que ese módulo se cargue en LAB. Tampoco se encontraron
|
||||
llamadas directas desde funciones ordinarias de vmlinux a los cuatro stubs
|
||||
en la búsqueda realizada (sí sus entradas CFI y sus bucles internos).
|
||||
Por tanto, no se atribuye el fallo de arranque específicamente a ese stub.
|
||||
Las llamadas normales a `fortify_panic` son parte de FORTIFY y su presencia
|
||||
no prueba que ninguna se ejecute durante el arranque fallido.
|
||||
|
||||
## Siguiente paso justificado
|
||||
|
||||
1. Conservar ksync-slab como referencia que arranca. No encadenar más opciones
|
||||
sobre el build FORTIFY fallido.
|
||||
2. Tratar FORTIFY como un port con dependencias: estudiar la implementación
|
||||
AXP y adaptar soporte Clang al kernel 4.14, incluyendo detección de compilador
|
||||
y pruebas de los wrappers. Corregir la detección sola bloquearía esta
|
||||
opción; no equivaldría a implementar FORTIFY.
|
||||
3. Retirar los stubs BUG de la receta candidata y resolver los diagnósticos
|
||||
de audio/WLAN, validando la causa de cada llamada. Mantener LTO/CFI como
|
||||
referencia; desactivarlos globalmente introduce otra variable y pierde
|
||||
protecciones ya funcionales.
|
||||
4. Archivar .config, diff, vmlinux y Module.symvers por build. Comprobar
|
||||
compatibilidad con los módulos realmente desplegados, no solo uname.
|
||||
5. Obtener una traza del intento fallido que distinga FORTIFY, CFI, carga de
|
||||
módulos y montaje de datos. En esta revisión ADB no detecta teléfonos,
|
||||
por lo que no se han leído registros actuales de LAB.
|
||||
|
||||
Conclusión: hay un defecto concreto de habilitación y un arreglo de enlace
|
||||
inadecuado. La causa exacta en ejecución sigue pendiente; no anunciar otro
|
||||
boot como reparado únicamente porque vuelva a compilar.
|
||||
|
||||
Plan de port (siguiente documento): `docs/009-fortify-clang-port.md`.
|
||||
|
||||
## Logs LAB post-fallo (2026-09-26, Cursor)
|
||||
|
||||
Teléfono en fastboot tras FORTIFY. Reflasheo slab-only (`boot_a`/`boot_b`) y reboot.
|
||||
`/sys/fs/pstore/` vacío (0 ficheros); sin `console-ramoops` ni `last_kmsg`.
|
||||
Misma ausencia de traza que en hangs Stage1/CVE previos. No hay dmesg del intento fallido.
|
||||
Artefacto local vacío: `.local-artifacts/009-fortify-crash-20260926/`.
|
||||
@@ -0,0 +1,87 @@
|
||||
# FORTIFY bounds: enlace correcto, arranque fallido
|
||||
|
||||
Artefacto remoto: `20260926T223246Z-bisect-ksync-fortify-bounds` bajo
|
||||
`/srv/rom/artifacts/009-axp-los23-port/`.
|
||||
El dueño informa logo Google, reinicios y finalmente fastboot. El proceso
|
||||
de build terminó exit=0 a las 22:32:52 UTC del 26 de septiembre.
|
||||
|
||||
## Verificaciones realizadas
|
||||
|
||||
- Los dos parches de límites están en las fuentes actuales. Audio/WLAN
|
||||
ya no tienen los símbolos sin resolver `__read_overflow*` en sus objetos
|
||||
LTO. Sí usan `fortify_panic`, que el kernel define y exporta normalmente.
|
||||
- `lib/string.c` no tiene modificaciones/stubs; `vmlinux` no contiene los
|
||||
cuatro helpers artificiales de overflow de los intentos anteriores.
|
||||
- El boot descargado tiene SHA-256
|
||||
`ba5ac99eb2873dac4c3c8b108753bb89e5aa7a7d71972361e32b39f6ed9ef136`,
|
||||
igual al registro remoto.
|
||||
- Desempaquetado local correcto: Android 16, parche 2026-09, header v2.
|
||||
El kernel extraído tiene SHA-256
|
||||
`99348e4f21a46c3bf95dde3a97995cd97375a6792427c5d497b3296fa0c0a906`,
|
||||
idéntico al kernel nuevo y al kernel verificado en el servidor.
|
||||
- Los ramdisks en los directorios remotos work/check del fallido y combo4
|
||||
tienen el mismo SHA-256. Se conserva el método ksync.
|
||||
|
||||
## Error ignorado por el empaquetador
|
||||
|
||||
El log muestra que el último `magiskboot unpack` (línea 91 del script)
|
||||
terminó con `Illegal instruction (core dumped)`. El `|| true` permitió
|
||||
continuar y declarar DONE. Es un defecto de verificación que debe corregirse.
|
||||
No demuestra que la imagen sea inválida: la copia con el mismo hash se ha
|
||||
desempaquetado correctamente en el portátil y contiene el kernel esperado.
|
||||
No confundir el fallo de la herramienta host con una traza del teléfono.
|
||||
|
||||
## Estado de LAB durante esta revisión
|
||||
|
||||
ADB disponible como usuario shell, sin privilegios root. LAB ya ejecuta
|
||||
combo4, kernel #16, `sys.boot_completed=1`. Pstore vacío. Propiedades de
|
||||
motivo de arranque: ro.boot.bootreason=reboot, sys.boot.reason=bootloader.
|
||||
No identifican el fallo previo. El tramo de logcat consultado no contiene
|
||||
una traza FORTIFY/CFI del intento fallido.
|
||||
|
||||
Intentos de leer módulos instalados en vendor devolvieron Permission denied.
|
||||
Por tanto, no se ha podido comparar su ABI/CRC con el kernel fallido.
|
||||
No se ha ejecutado adb root, cambiado Magisk, reiniciado ni flasheado LAB.
|
||||
|
||||
## Prueba adicional de eficacia de wrappers
|
||||
|
||||
Se extrajo el bloque FORTIFY del string.h actual a un harness temporal,
|
||||
con sus wrappers y macros, tipos auxiliares y libc host. Clang r563880c,
|
||||
`-O2 -flto -fuse-ld=lld`. No se añadieron stubs overflow. El handler de
|
||||
fortify del harness termina con código 77 para observar el rechazo.
|
||||
|
||||
Directorio remoto: `/tmp/axp-fortify-runtime-9t4hrer_`.
|
||||
|
||||
13 casos dieron el resultado esperado:
|
||||
|
||||
- strlen/strnlen sobre una cadena válida, strcpy válido;
|
||||
- memcpy, memmove, memset, memcmp y strncpy: tamaño 8 sobre buffers de 8
|
||||
aceptado, tamaño dinámico 9 rechazado por fortify_panic.
|
||||
|
||||
**Límites:** ejecución host x86_64, no kernel ARM64; no prueba CFI del kernel,
|
||||
wrappers restantes, todos los call sites, módulos ni arranque. El caso memcmp
|
||||
usa el mismo buffer a ambos lados; no es una prueba exhaustiva de comparación.
|
||||
Estas pruebas muestran protección efectiva en los casos probados, no que el
|
||||
port completo sea correcto.
|
||||
|
||||
## Lo que falta para atribuir el fallo
|
||||
|
||||
La corrección de límites resolvió el enlace, que era su alcance probado.
|
||||
No se ha identificado la instrucción que detiene el arranque. Encontrar
|
||||
llamadas a fortify_panic en el binario (incluso en funciones de inicio) es
|
||||
normal y no demuestra que se ejecuten durante el fallo.
|
||||
|
||||
Prioridad: preparar una captura de fallo utilizable antes del próximo ensayo.
|
||||
Comprobar en la referencia funcional el acceso y funcionamiento de pstore/
|
||||
ramoops, incluido el mecanismo del dispositivo que procesa sus registros.
|
||||
Un arranque de diagnóstico puede instrumentar fortify_panic para registrar
|
||||
caller/backtrace conservando su comportamiento de fallo; también debe poder
|
||||
distinguir una caída CFI, un watchdog y un fallo de módulos. Esa instrumentación
|
||||
sin un canal persistente/serial verificado no garantiza obtener evidencia.
|
||||
|
||||
Conservar combo4 como referencia aceptada. No habilitar FORTIFY para ship,
|
||||
ni atribuir el fallo a un controlador concreto, ni reintroducir stubs/no-ops
|
||||
a partir del solo síntoma del logo. Revisar después compatibilidad de módulos
|
||||
y los call sites identificados por una traza real.
|
||||
|
||||
Plan de captura (siguiente documento): `docs/009-fortify-diag-capture-plan.md`.
|
||||
@@ -0,0 +1,98 @@
|
||||
# FORTIFY + Clang en msm-4.14 (plan de port)
|
||||
|
||||
Documento de preparación. No es un parche listo. Relacionado:
|
||||
`docs/009-fortify-boot-audit-20260926.md` (diagnóstico del fallo LAB).
|
||||
|
||||
## Hechos ya cerrados
|
||||
|
||||
| Hecho | Evidencia |
|
||||
|-------|-----------|
|
||||
| Packaging ksync OK | Ramdisk/DTB idénticos a slab; patch `2026-09` |
|
||||
| FORTIFY one-CONFIG tumba arranque | LAB → reinicios → fastboot; pstore vacío |
|
||||
| DMESG / SLAB / INIT_ON_ALLOC / INIT_ON_FREE solos OK | Bisect ksync 2026-09-26 |
|
||||
| `depends on !CC_IS_CLANG` es inútil aquí | `CC_IS_CLANG` **no existe** en msm-4.14; el build usa Clang 21 + LTO/CFI |
|
||||
| Stubs `__read_overflow*` + `BUG()` | Anti-patrón: enlazan pero dejan llamadas reales (p.ej. `q6_dlkm` → `__read_overflow2`). **No reutilizar** |
|
||||
| AXP `fortify/4.14/0004.patch` | Solo intra-object (`FORTIFY_SOURCE_STRICT_STRING` / Micay). **No** aporta soporte Clang |
|
||||
|
||||
## Qué hace falta (upstream, no inventado)
|
||||
|
||||
Serie Kees Cook *fortify: Add Clang support* (v7, 2022-02), mergeada en kernels
|
||||
modernos. Idea central:
|
||||
|
||||
1. Atributos Clang: `__pass_object_size`, `__overloadable`, `__diagnose_as`
|
||||
(en `compiler_attributes.h`).
|
||||
2. Wrappers FORTIFY adaptados para que `__builtin_object_size(p, 1)` funcione
|
||||
desde inlines (en kernels nuevos: `include/linux/fortify-string.h`).
|
||||
3. Kconfig: `depends on !CC_IS_CLANG || CLANG_VERSION >= 120001` (y exclusiones
|
||||
arch específicas). Clang 21 cumple la versión; falta el código.
|
||||
|
||||
Referencias:
|
||||
|
||||
- Cover: <https://lists.openwall.net/linux-hardening/2022/02/08/7>
|
||||
- Commit ilustrativo: `281d0c962752` (*fortify: Add Clang support*)
|
||||
- Antecedente del disable: `a52f8a59aef4` / bugs LLVM 41459, 50322
|
||||
|
||||
En **4.14** el FORTIFY vive todavía dentro de `include/linux/string.h` (no hay
|
||||
`fortify-string.h`). El backport no es un cherry-pick limpio: hay que adaptar
|
||||
los wrappers al layout 4.14 o traer la separación de headers con cuidado.
|
||||
|
||||
## Detección de compilador (paso previo pequeño)
|
||||
|
||||
Sin `CC_IS_CLANG` / `CLANG_VERSION` en Kconfig, cualquier `depends on !CC_IS_CLANG`
|
||||
es no-op. Antes o junto al port de wrappers:
|
||||
|
||||
1. Backport mínimo de los símbolos Kconfig que usan árboles Android/comunes
|
||||
modernos (`CC_IS_CLANG`, `CLANG_VERSION`) **o** equivalencia documentada
|
||||
vía `scripts/Kconfig.include` / Makefile del árbol.
|
||||
2. Con eso solo + `depends on !CC_IS_CLANG`: FORTIFY queda **apagado** con
|
||||
Clang — correcto, pero no da hardening. Sirve como red de seguridad para
|
||||
no volver a activarlo “por accidente”.
|
||||
|
||||
## Camino de implementación propuesto (orden)
|
||||
|
||||
1. **Quitar stubs** de `009-bisect-ksync-one.sh` (o dejarlos detrás de un
|
||||
flag explícito `ALLOW_FORTIFY_BUG_STUBS=1` no usado por defecto). Un
|
||||
FORTIFY que no enlace sin stubs = señal de que el port está incompleto.
|
||||
2. **Introducir detección Clang** en Kconfig (paso pequeño, testeable).
|
||||
3. **Port wrappers Clang** al `string.h` 4.14 (o split a `fortify-string.h`
|
||||
si el diff queda más limpio), tomando la serie Kees como fuente, no stubs.
|
||||
4. **Build ksync** solo `CONFIG_FORTIFY_SOURCE=y` (sin STRICT_STRING al
|
||||
principio). Criterio de éxito: modpost **sin** undefined
|
||||
`__read_overflow*` y sin exportar cuerpos `BUG()`.
|
||||
5. Si aparecen llamadas residuales en audio/WLAN: tratar cada una como bug
|
||||
de tamaño/objeto o fallo del wrapper — no enmascarar.
|
||||
6. Flash LAB (mismo método ksync / GOODMAKE). Solo entonces valorar
|
||||
`FORTIFY_SOURCE_STRICT_STRING` (AXP 0004) encima.
|
||||
7. Reintroducir FORTIFY en el combo defconfig OK (DMESG+SLAB+INIT_ON_*).
|
||||
|
||||
Fuera de alcance de este port: desactivar LTO/CFI globales “para que compile”
|
||||
(introduce otra variable y pierde protecciones ya validadas).
|
||||
|
||||
## Qué no es “clonar AXP” aquí
|
||||
|
||||
AXP aporta el parche Graphene de **strict string** sobre un FORTIFY que ya
|
||||
debe ser válido con el toolchain del producto. En LOS23/sunfish el toolchain
|
||||
es Clang+LTO; el vacío es el **soporte Clang de FORTIFY**, no el 0004.
|
||||
Hasta tener (3)+(4), no marcar FR-017 FORTIFY como listo.
|
||||
|
||||
Nota (búsqueda host): el `0008-…-fortify/5.15/0006.patch` AXP (*rewrite
|
||||
fortify source for 5.15 gki*) también es strict-string sobre
|
||||
`fortify-string.h` ya existente — no sustituye la serie Kees de Clang.
|
||||
|
||||
## Estado
|
||||
|
||||
- **LAB combo4 OK** (2026-09-26): `#16`, DMESG+SLAB+INIT_ON_ALLOC+INIT_ON_FREE, sin FORTIFY.
|
||||
- Stubs BUG gated off en ksync (`ALLOW_FORTIFY_BUG_STUBS`).
|
||||
- Port en curso: `vendor/.../fortify-clang/apply_fortify_clang.py`.
|
||||
- **fortify-pos0 FAIL 2026-09-26T21:54Z:** modpost
|
||||
`__read_overflow*` undefined en `q6_dlkm.lto.ko` / `wlan.lto.ko`.
|
||||
**vmlinux/Image.lz4 sí generaron** (sin esos U en el núcleo). El port POS0
|
||||
no basta aún para módulos LTO; no reintroducir stubs.
|
||||
Siguiente: localizar call sites (p.ej. rtac) o `__NO_FORTIFY` puntual /
|
||||
más del port Kees — no ACCEPT hasta harness + link limpio.
|
||||
- **Ensayo 2026-09-26T22:06Z:** POS0 + bounds (`rtac`/`lim_process_fils`) en
|
||||
job `009-bisect-ksync-fortify-bounds`. Log:
|
||||
`detach-009-bisect-ksync-fortify-bounds-20260926T220634Z.log`.
|
||||
**Build OK / LAB FAIL:** logo Google → reboot. Reflasheo a combo4.
|
||||
Bounds resolvieron el link; no bastan para arrancar. FORTIFY sigue
|
||||
aparcado para ship hasta traza o port más completo + harness.
|
||||
@@ -0,0 +1,240 @@
|
||||
# Plan: captura verificable del fallo FORTIFY
|
||||
|
||||
> Revisión posterior: [auditoría del diagnóstico del 27/09](009-fortify-diag-review-20260927.md).
|
||||
> El «canal VERIFICADO» de abajo solo demuestra parte de la persistencia:
|
||||
> SysRq-x puede dejar la misma marca que se observa tras SysRq-c. Además, el
|
||||
> escritor no funciona antes de ramoops_probe. La ausencia de AXPDIAG1 tras
|
||||
> fortify-diag **no descarta fortify_panic**, ni demuestra watchdog. Se conserva
|
||||
> abajo el historial original de las pruebas.
|
||||
|
||||
Parte de `docs/009-fortify-bounds-boot-failure-20260927.md`.
|
||||
Referencia LAB: combo4 `#16` (sin FORTIFY). No flashear diagnóstico hasta
|
||||
tener canal de captura comprobado en esa referencia.
|
||||
|
||||
## Hallazgos en combo4 (2026-09-27, solo lectura)
|
||||
|
||||
| Señal | Valor |
|
||||
|-------|--------|
|
||||
| boot_completed | 1 |
|
||||
| pstore montado | sí, vacío |
|
||||
| last_kmsg / debugfs | no accesibles como shell |
|
||||
| Magisk / su | no activos (virgin AXP) |
|
||||
| cmdline | `console=null`, `androidboot.ramdump=disabled` |
|
||||
| config | `CONFIG_PSTORE=y`, `PSTORE_RAM`, `PSTORE_CONSOLE`, `ACCESS_RAMOOPS` |
|
||||
| bootreason tras recover | `reboot` / `bootloader` (no identifica el panic FORTIFY) |
|
||||
|
||||
Conclusión: el kernel **tiene** pstore/ramoops, pero LAB no entrega traza
|
||||
útil tras el reboot a fastboot. Cambiar más CONFIGs sin canal de evidencia
|
||||
repite el bucle anterior.
|
||||
|
||||
## Objetivo del arranque de diagnóstico
|
||||
|
||||
Distinguir, con registro persistente o serial:
|
||||
|
||||
1. `fortify_panic` (caller + backtrace)
|
||||
2. fallo CFI
|
||||
3. watchdog / softlockup
|
||||
4. fallo de carga de módulos / ABI
|
||||
|
||||
Sin eso, no atribuir el logo Google a audio/WLAN ni a FORTIFY genérico.
|
||||
|
||||
## Pasos (orden)
|
||||
|
||||
1. **Canal de captura en combo4 (sin FORTIFY)**
|
||||
- Confirmar cómo Pixel 4a/sunfish expone ramoops tras panic
|
||||
(`ACCESS_RAMOOPS`, partición `klog`/`logfs`, `ramdump=disabled`).
|
||||
- Probar un panic controlado mínimo en un boot **solo diagnóstico**
|
||||
(no ship) y verificar que shell/root puede leer
|
||||
`/sys/fs/pstore/console-ramoops*` tras el siguiente arranque bueno.
|
||||
- Alternativa: UART/serial o `androidboot.console` no-null si el lab lo
|
||||
permite. Si el canal falla, no flashear FORTIFY otra vez.
|
||||
|
||||
2. **Instrumentar `fortify_panic`** (solo en árbol de ensayo)
|
||||
- Antes del `BUG()`: `pr_emerg` con `%pS` del return address + stack.
|
||||
- Mantener el panic (no convertir en no-op).
|
||||
- Misma receta ksync (GOODMAKE + kernel FORTIFY+POS0+bounds).
|
||||
|
||||
3. **Marcas CFI / módulos**
|
||||
- Si el log muestra CFI: seguir esa vía.
|
||||
- Si aparece durante `insmod`/init de vendor: comparar CRC/ABI de
|
||||
módulos (requiere root o dump desde recovery).
|
||||
- Si watchdog sin fortify/CFI: otra clase de hang.
|
||||
|
||||
4. **Empaquetador**
|
||||
- Quitar el `|| true` que traga el SIGILL de `magiskboot` en VERIFY, o
|
||||
verificar el header en el laptop con el mismo SHA. Defecto de script,
|
||||
no causa del reboot (imagen unpack OK en laptop).
|
||||
|
||||
5. **Solo después** de una traza atribuible: cambio mínimo (call site,
|
||||
excepción justificada, o más port). No stubs. No ship FORTIFY.
|
||||
|
||||
## Estado 2026-09-27 (tras Rooted debugging)
|
||||
|
||||
- `adb root` OK.
|
||||
- `vendor.ramoops.decryption.error=1` en boot normal.
|
||||
- Causa 1: `/vendor/bin/ramoops` hardcodea
|
||||
`/sys/devices/soc/.../size` pero el kernel expone
|
||||
`/sys/devices/platform/soc/...` (y vía `/sys/class/misc/.../size`).
|
||||
Binario parcheado en `/data/local/tmp/ramoops.fix` para class paths.
|
||||
- Causa 2: tras eso, kernel log `ramoops: Failed to set key, -22` (EINVAL)
|
||||
al escribir AES en sysfs. pstore sigue vacío. Remount pstore denegado por SELinux.
|
||||
- Claves RSA sí existen en `/data/vendor_ce/0/ramoops/{priv,pub}.pem`.
|
||||
- `boot_debug/crash.txt` es basura userspace antigua, no kernel FORTIFY.
|
||||
- Build `fortify-diag` (panic instrumentado) sigue en curso.
|
||||
|
||||
## Captura post fortify-diag (2026-09-27 ~01:36)
|
||||
|
||||
Tras flash diag → fallo → recover combo4 `#16` + `adb root`:
|
||||
|
||||
- pstore vacío; `boot_debug/kernel.txt` vacío; sin `FORTIFY_DIAG` en claro.
|
||||
- Dump `/dev/access-ramoops` (4 MiB): entropía alta (cifrado); 0 strings útiles.
|
||||
- Decrypt sigue fallando (`Failed to set key, -22`).
|
||||
|
||||
Prueba de canal con **SysRq-c** en combo4:
|
||||
|
||||
- Bootloader registró `androidboot.bootreason=kernel_panic` (panic real).
|
||||
- **Aun así** pstore vacío y alt cifrado sin plaintext.
|
||||
|
||||
Conclusión: en este LAB un `kernel_panic` **no** produce traza legible vía pstore
|
||||
hasta arreglar el pipeline AES/ramoops. El síntoma FORTIFY (antes del SysRq)
|
||||
había dejado `bootreason=reboot`/`bootloader`, no `kernel_panic` — hipótesis
|
||||
abierta: reset/wdog distinto de `fortify_panic`, o el bootloader reescribe el
|
||||
motivo al pasar por fastboot.
|
||||
|
||||
Siguiente trabajo de captura: diag **sin cifrado** (pstore/ramoops plaintext)
|
||||
o arreglo del setkey; no más flashes FORTIFY hasta tener canal verificado con
|
||||
SysRq → fichero legible en pstore.
|
||||
|
||||
## Captura plaintext (2026-09-27 ~01:45)
|
||||
|
||||
Hallazgos en combo4 tras Rooted debugging + reboot sin unlock:
|
||||
|
||||
| Señal | Valor |
|
||||
|-------|--------|
|
||||
| `dumpsys user` | `RUNNING_LOCKED`, Unlock time unknown |
|
||||
| `sys.user.0.ce_available` | vacío |
|
||||
| `/data/vendor_ce/0/ramoops` | `Required key not available` |
|
||||
| `mount \| grep pstore` | vacío tras `on boot` umount |
|
||||
| Remount manual `pstore` + `use_alt=0` | monta OK, **sigue sin ficheros** |
|
||||
| `/dev/pmsg0` + reboot | no aparece `pmsg-ramoops-*` |
|
||||
| SysRq-c | `bootreason=kernel_panic`, alt cifrado, primary vacío |
|
||||
|
||||
Causa de sistema (no solo FORTIFY):
|
||||
|
||||
1. `init-ramoops.rc` hace `umount /sys/fs/pstore` en `on boot` y solo remonta
|
||||
cuando `vendor.ramoops.decrypted=true` (tras CE unlock + `ramoops -D`).
|
||||
2. Binario `/vendor/bin/ramoops` usa paths sysfs pre-`platform/` → size=-1;
|
||||
con binario parcheado a class paths, CE locked → sin `priv.pem`.
|
||||
3. Writes de pstore van al **primary**; el carveout que sobrevive/lee userspace
|
||||
tras decrypt es el **alt** cifrado (`/dev/access-ramoops`).
|
||||
4. `ramoops_init_prz` hace `persistent_ram_zap(primary)` tras `save_old` en
|
||||
console/pmsg — el pipeline asume encrypt-on-shutdown a alt.
|
||||
|
||||
Canal de evidencia (sin CE / sin AES): patch diag
|
||||
`ramoops_axp_plaintext_alt` — en DMESG oops/panic escribe magic `AXPDIAG1` +
|
||||
cuerpo en claro al **alt** (ioremap). Verificación LAB:
|
||||
|
||||
```text
|
||||
dd if=/dev/access-ramoops bs=1M count=4 | strings | grep -E 'AXPDIAG1|Kernel panic'
|
||||
```
|
||||
|
||||
Build canal (sin FORTIFY): `scripts/009-bisect-ksync-pstore-alt-plain.sh`
|
||||
(`PSTORE_ALT_PLAIN=1`). Probar SysRq → magic legible **antes** de otro flash
|
||||
FORTIFY.
|
||||
|
||||
### Iteración 2 (ioremap en panic)
|
||||
|
||||
- Alt carveout **sí** persiste: write userspace `AXPUSER1` → reboot → sigue ahí.
|
||||
- Build `20260927T001522Z` con mirror vía `ioremap_wc` **en** `ramoops_pstore_write`
|
||||
(contexto panic/atomic): SysRq → `bootreason=kernel_panic` pero **sin** `AXPDIAG1`
|
||||
(ioremap no es safe ahí; write silencioso no-op).
|
||||
- Fix: pre-map en `ramoops_probe` (`axp_alt_va`) + solo `memcpy_toio`/`wmb` en panic.
|
||||
Rebuild: job `009-bisect-ksync-pstore-alt-plain2`.
|
||||
- plain2: map OK + SysRq `kernel_panic`, sin `AXPDIAG1` (aliasing WC vs `ioremap`).
|
||||
- plain3: `AXPDIAG0-probe` legible tras boot (kernel→alt OK). Tras SysRq solo
|
||||
`AXPDIAG0` — el hook DMESG pstore no corre en este panic path.
|
||||
- plain4: `panic_notifier` + `AXPDIAG1-panic-notifier`, pero el boot siguiente
|
||||
reescribía `AXPDIAG0` encima. Fix: no clobber si head=`AXPDIAG1`.
|
||||
Rebuild: `pstore-alt-plain5`.
|
||||
|
||||
### Canal VERIFICADO (plain7, `20260927T024949Z`)
|
||||
|
||||
| Prueba | Resultado |
|
||||
|--------|-----------|
|
||||
| `echo x > /proc/sysrq-trigger` (sin panic) | `AXPDIAG1-sysrq-fixed` en `/dev/access-ramoops` |
|
||||
| sysrq-x + `adb reboot` | `AXP alt keeps prior AXPDIAG1 capture` |
|
||||
| sysrq-x + sysrq-c → `bootreason=kernel_panic` | magic `AXPDIAG1` sobrevive (cuerpo a veces truncado por reset) |
|
||||
| Metadata `/dev/access-metadata` tras panic | reescrita (claves AES); no usar |
|
||||
|
||||
Lectura post-fallo (root, no hace falta unlock CE):
|
||||
|
||||
```text
|
||||
adb root
|
||||
dd if=/dev/access-ramoops bs=1M count=4 | strings | grep AXPDIAG
|
||||
dmesg | grep AXP
|
||||
```
|
||||
|
||||
## v4 canal (post review v3 2026-09-27)
|
||||
|
||||
Ver `docs/009-fortify-diag-v3-review-20260927.md`. v3 obsoleto: `ioremap`
|
||||
tras `paging_init` (antes de slab/vmalloc) puede tumbar el control sin
|
||||
FORTIFY; attrs early cached vs IO; milestones compartían slots con el fallo.
|
||||
|
||||
`apply_fortify_diag.py` **v4**:
|
||||
|
||||
- Early: `early_ioremap` (FIXMAP_PAGE_IO) antes de `parse_early_param`; se
|
||||
mantiene hasta después de `mm_init`. Permanente: `ioremap` **solo** tras
|
||||
`mm_init`. Handler nunca mapea.
|
||||
- Layout página 0: fallo @0 (+ mirrors); milestones @2048 (zonas separadas).
|
||||
- Adoptar fallo previo solo si registro **completo** (header + `\\n` + mirror).
|
||||
- Ciego residual: pre-`early_map`; ventana breve al cambiar early→perm si el
|
||||
VA se publica mal (v4 publica permanente antes de retirar early).
|
||||
|
||||
Validación control (sin FORTIFY) — media/tardía; no prueba pre-`early_map`:
|
||||
|
||||
0. Wipe zona fallo: `dd if=/dev/zero of=/dev/access-ramoops bs=4K count=1`
|
||||
1. Flash `pstore-alt-plain` v4, boot, `adb root`.
|
||||
2. Milestones: `strings | grep AXPDIAG0` → `...,early_map` / `perm_map` /
|
||||
`mm_init` (offset distinto; pueden coexistir con un AXPDIAG1).
|
||||
3. **Solo** SysRq-c (sin `x`).
|
||||
4. Recover combo4 → `AXPDIAG1,C,<attempt>,0x...,sysrq-c` completo.
|
||||
5. Solo entonces fortify-diag v4.
|
||||
|
||||
### Review resultados v4
|
||||
|
||||
Ver `docs/009-fortify-v4-capture-results-review-20260927.md`,
|
||||
`docs/009-fortify-v4-clean-tests-verification-20260927.md`, y artefactos:
|
||||
|
||||
- `.local-artifacts/009-v4-clean-c-20260927T190738Z/`
|
||||
- `.local-artifacts/009-v4-x-persist-20260927T191143Z/`
|
||||
- `.local-artifacts/009-v4-twophase-x-then-c-20260927T191809Z/` (adb
|
||||
readback then panic: pre-verified X lost by P3)
|
||||
|
||||
### LAB 2026-09-27 (plain-v4 `20260927T084531Z`) — hechos vs hipótesis
|
||||
|
||||
**Demostrado**
|
||||
|
||||
- Writer de first-failure en vivo: SysRq-x →
|
||||
`AXPDIAG1,X,20260927T084531Z,0x...,sysrq-x` @0 (+ mirrors).
|
||||
- Milestone slot @2048 recibe `AXPDIAG0,M,...,panic_reg` (último stage;
|
||||
sobrescribe stages previos en el mismo offset).
|
||||
- Tras SysRq-c (arranque sin `x` previo) + recover combo4: **no** hay
|
||||
`AXPDIAG1` en ninguno de los 8 slots de fallo; @0 es opaco.
|
||||
|
||||
**No demostrado / correcciones**
|
||||
|
||||
- **No** hay, en el código revisado, una rutina de *cifrado del alt al
|
||||
entrar en panic*. Sí hay camino de descifrado del alt. «Desactivar
|
||||
encrypt en el kernel» no apunta aún a una función identificada; no usar
|
||||
eso como siguiente paso.
|
||||
- Que `panic_reg` aparezca @2048 tras combo4 **no** prueba zona segura ni
|
||||
supervivencia al panic: combo4 no escribe `AXPDIAG*`, pero un arranque
|
||||
intermedio de **v4** regenera el mismo `panic_reg` con el mismo attempt
|
||||
id. Hace falta attempt id distinto por boot, o wipe + leer sin otro boot
|
||||
v4, antes de atribuir persistencia.
|
||||
- El latch `axp_first_latch` es **solo RAM**: un wipe del dump no lo
|
||||
resetea. Si en el mismo arranque se hace SysRq-x y luego SysRq-c, `c`
|
||||
no escribe. Las pruebas `c`-only válidas requieren wipe **y reboot**
|
||||
(o imagen nueva) sin `x` previo en ese boot.
|
||||
- Causa de @0 opaco tras `c` (sobrescritura, fallo de escritura, otro
|
||||
productor): **abierta**.
|
||||
@@ -0,0 +1,119 @@
|
||||
# FORTIFY diagnostic review — 2026-09-27
|
||||
|
||||
## Conclusion
|
||||
|
||||
The boot failure remains unresolved. The latest capture does **not** exclude
|
||||
`fortify_panic`, and does not establish a watchdog reset. The diagnostic channel
|
||||
has an early-boot blind spot and its documented panic validation admits a stale
|
||||
marker. Fix these experimental controls before interpreting another empty dump.
|
||||
|
||||
Review covered the Cursor transcript, local patch scripts and capture plan,
|
||||
remote kernel sources/build artifacts, saved diag2 dump and installed LAB
|
||||
modules. No flashing, rebooting, live source changes or new builds were performed
|
||||
in this review.
|
||||
|
||||
## Experiment history and what it establishes
|
||||
|
||||
1. Original defconfig bisects also changed bp4a to bp2a (security patch and
|
||||
platform version regression). Those experiments did not isolate hardening.
|
||||
2. Corrected ksync packaging retained GOODMAKE's boot environment. Combo4 boots
|
||||
with DMESG restriction, slab freelist hardening and allocation/free clearing.
|
||||
3. FORTIFY required a Clang port. Exported overflow BUG stubs were removed;
|
||||
pass_object_size was aligned to the wrappers' object-size mode 0.
|
||||
4. The audio/WLAN overflow-helper link failures were localized to specific
|
||||
functions. Explicit array-capacity guards resolved the targeted compilation
|
||||
failures. Successful linking does not establish runtime correctness of the
|
||||
port, or prove those drivers caused the subsequent boot failure.
|
||||
5. Bounds FORTIFY boots still failed. Diagnostics then added caller printing,
|
||||
stack dumping and a plaintext marker in the alternate ramoops region.
|
||||
6. Plain-channel iterations tested mapping, probe overwriting, a panic notifier
|
||||
and SysRq writes. These are useful channel experiments, but the recorded
|
||||
plain7 result is insufficient to validate fresh panic-time writes.
|
||||
7. Latest diag2 (`20260927T032419Z-bisect-ksync-fortify-diag`) failed to boot;
|
||||
recovery used combo4. No readable failure record has been obtained.
|
||||
|
||||
## Confirmed diagnostic defects
|
||||
|
||||
### 1. Capture starts too late to exclude an early FORTIFY failure
|
||||
|
||||
`apply_fortify_diag.py` maps the alternate region only at the successful end of
|
||||
`ramoops_probe`. Remote `fs/pstore/ram.c:1270` performs the mapping;
|
||||
`ramoops_init` is a `postcore_initcall` at line 1365. The writer immediately
|
||||
returns if `axp_alt_va` is null (patch script lines 105–106).
|
||||
|
||||
Remote `init/main.c` calls `setup_arch` at 565 and `parse_early_param` at 579,
|
||||
before `rest_init` at 738 and the later `do_basic_setup` / `do_initcalls` path.
|
||||
Disassembly of the current FORTIFY vmlinux contains branches to fortify_panic:
|
||||
|
||||
```text
|
||||
parse_early_param: ffffff8012290974 -> ffffff8011ac186c
|
||||
start_kernel: ffffff8012290fb8 -> ffffff8011ac186c
|
||||
setup_arch: ffffff8012296750 -> ffffff8011ac186c
|
||||
```
|
||||
|
||||
These are possible failure paths, **not evidence that any executed**. They
|
||||
demonstrate that an instrumented FORTIFY failure can occur while the persistent
|
||||
writer is unavailable. A SysRq test from a fully booted system cannot validate
|
||||
that interval.
|
||||
|
||||
### 2. Plain7's positive control can accept an old marker
|
||||
|
||||
The capture plan records `sysrq-x + sysrq-c` followed by survival of the magic
|
||||
`AXPDIAG1`, sometimes without the complete body. SysRq-x already writes that
|
||||
magic. The next probe explicitly preserves it. Therefore magic survival alone
|
||||
does not prove that SysRq-c or the panic notifier wrote anything new.
|
||||
|
||||
Require a distinct per-attempt identifier and a complete panic-specific record,
|
||||
different from the pre-panic marker. Validate the exact failed-boot → fastboot
|
||||
→ rescue-image → dump sequence, not just a normal reboot into plain7.
|
||||
|
||||
### 3. The durable record follows operations that may fail
|
||||
|
||||
The injected `fortify_panic` first calls `pr_emerg` and `dump_stack`, then writes
|
||||
the persistent mark (patch script lines 36–39). A failure or recursion in those
|
||||
operations could prevent the mark. The durable body contains only the helper
|
||||
name, not the caller address printed to the unavailable console. Subsequent
|
||||
panic-notifier and pstore writes also target the same slots and can overwrite
|
||||
the first record.
|
||||
|
||||
Record the first failure before formatted output; include a raw caller address,
|
||||
event type and attempt identifier. Preserve the first record. Use a minimal
|
||||
writer independent of the fortified helpers under investigation. This still
|
||||
requires a correctly reserved/mapped region available at the tested boot stage;
|
||||
moving the call alone does not fix defect 1.
|
||||
|
||||
## Additional checks
|
||||
|
||||
- Latest local boot SHA-256 matches the remote published boot:
|
||||
`a5be43617770205bb9a2d2ad5989ca566ad9713134e7210c585f02fd7bdea554`.
|
||||
- Current build configuration enables FORTIFY, Clang LTO, Clang CFI and
|
||||
MODVERSIONS.
|
||||
- Read-only comparison of all 41 installed vendor `.ko` files against current
|
||||
remote `Module.symvers`: **3,182 version entries, zero CRC mismatches, zero
|
||||
missing symbols**. This checks symbol version compatibility only; it does not
|
||||
prove all runtime ABI/CFI behavior is correct or identify the crashing code.
|
||||
- LAB was recovered and running combo4 kernel #16 with `sys.boot_completed=1`.
|
||||
- Saved diag2 `access-ramoops.bin` is 4 MiB and contains none of `AXPDIAG0`,
|
||||
`AXPDIAG1`, `FORTIFY`, `DBGC` or `Oops`. Measured byte entropy is approximately
|
||||
7.99996 bits/byte. This does not uniquely distinguish encryption, overwritten
|
||||
contents or other high-entropy data, nor prove no panic occurred.
|
||||
- `bootreason=reboot` observed after rescue is not a preserved trace of the
|
||||
original failure and cannot exclude a panic in the earlier attempt.
|
||||
|
||||
## Next experiment requirements
|
||||
|
||||
1. Preserve combo4 and archive each diagnostic patch, config, vmlinux and hashes.
|
||||
2. Validate fresh, distinguishable failure records with an otherwise booting
|
||||
control. Test persistence across the same recovery sequence used in practice.
|
||||
3. Cover the early interval explicitly: use a board-supported early output or
|
||||
correctly reserved early persistent writer, with initialization milestones.
|
||||
Do not insert ordinary ioremap calls into arbitrary early/panic context.
|
||||
4. Validate an intentionally triggered diagnostic event at the boot stage being
|
||||
tested. A late SysRq control alone is insufficient.
|
||||
5. Only then repeat FORTIFY with a first-failure record containing a caller and
|
||||
symbolize it using the exact vmlinux. If no reliable early channel is
|
||||
achievable, use controlled localization experiments and label them as such;
|
||||
do not promote them to a working or complete hardening port.
|
||||
|
||||
Do not add overflow stubs, suppress fortify_panic or declare watchdog/CFI the
|
||||
cause solely because the current capture is empty.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Diagnostic v2 review — 2026-09-27
|
||||
|
||||
Reviewed local `apply_fortify_diag.py` and generated remote
|
||||
`kernel/axp_diag_capture.c` with attempt `20260927T083401Z`, while the plain-v2
|
||||
control build was running. No live sources or build jobs were changed.
|
||||
|
||||
The direction is useful: record before printing, include event/caller/build
|
||||
identifier, and validate SysRq-c without first writing SysRq-x. However, this
|
||||
implementation is not yet a validated early-boot recorder.
|
||||
|
||||
## Required corrections
|
||||
|
||||
1. **Do not map from the failure handler.** `axp_diag_mark_event` calls
|
||||
`axp_diag_map`, which calls ordinary `ioremap` if no mapping exists. This
|
||||
reintroduces mapping in panic/early context. In this tree ARM64 ioremap uses
|
||||
`get_vm_area_caller` and `ioremap_page_range`; mm_init initializes the slab
|
||||
allocator and vmalloc. Mapping after successful mm_init is a reasonable
|
||||
later-stage control, but the failure handler must not try to compensate for
|
||||
an earlier failure with that same ordinary mapping path.
|
||||
|
||||
2. **The previously identified early interval is still uncovered.** Remote
|
||||
`init/main.c` calls setup_arch at 565 and parse_early_param at 579; mm_init
|
||||
and the new hook are at 600–604. A successful late SysRq test does not
|
||||
validate a failure in either earlier function or inside mm_init itself.
|
||||
|
||||
3. **First-failure retention is not guaranteed.** `axp_first_done` is a plain
|
||||
integer tested before recording and set only after the writes. Concurrent
|
||||
CPUs or recursion can both pass the test. The event writer does not inspect
|
||||
an existing persistent record, despite the stated promise to preserve one;
|
||||
only the milestone writer does. Use a deliberate atomic/reentrancy protocol
|
||||
and an explicit policy for records from previous boots. A build timestamp
|
||||
distinguishes builds, not repeated attempts with the same image.
|
||||
|
||||
4. **Milestone format contains an embedded NUL.** The literal `AXPDIAG0,M,`
|
||||
is 10 characters, but memcpy copies 11 and advances by 11. This copies the
|
||||
string terminator before the attempt identifier. Consequently `strings |
|
||||
grep AXPDIAG0` loses the attempt/stage from the same line. Use the literal's
|
||||
length excluding its terminator (for example sizeof(literal)-1).
|
||||
|
||||
## Validation scope
|
||||
|
||||
A complete new `C` record surviving the actual combo4 recovery sequence would
|
||||
be useful evidence for late panic capture. It would not establish early-boot
|
||||
coverage. Require the exact expected identifier and complete record; define
|
||||
how previous records are archived/cleared before repeating the same image.
|
||||
Keep the first failure separate from milestones and subsequent notifier events.
|
||||
|
||||
The capture implementation still includes linux/string.h and memcpy calls;
|
||||
verify the final ARM64/LTO generated writer does not depend on the FORTIFY
|
||||
failure path under test. `no_sanitize("cfi")` alone does not disable FORTIFY.
|
||||
|
||||
Do not interpret an empty capture from this v2 as proof against fortify_panic.
|
||||
|
||||
## Status
|
||||
|
||||
Local `apply_fortify_diag.py` updated to **v3** addressing items 1–4
|
||||
(no map-from-handler; early+perm maps in `setup_arch`; atomic latch + durable
|
||||
head check; milestone `sizeof(lit)-1`). Residual pre-`early_map` blind spot
|
||||
remains documented in the capture plan. plain-v2 build is obsolete — rebuild
|
||||
control as plain-v3 before flash.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Diagnostic v3 review — 2026-09-27
|
||||
|
||||
Checked the local generator and remote generated kernel/axp_diag_capture.c,
|
||||
attempt 20260927T084106Z, while plain-v3 was building. No build cancellation,
|
||||
source modification on the server, or device operations were performed.
|
||||
|
||||
## Corrected
|
||||
|
||||
- Failure handler no longer maps memory.
|
||||
- Event claim uses atomic_cmpxchg before composing the record.
|
||||
- Event path checks a previous persistent AXPDIAG1 header.
|
||||
- Milestone prefix length excludes the terminating NUL.
|
||||
- Explicit byte I/O replaces memcpy on the MMIO writer path.
|
||||
- Early mapping now precedes parse_early_param in ARM64 setup_arch.
|
||||
|
||||
## Blocking issue: permanent mapping before allocators exist
|
||||
|
||||
The new setup.c hook at lines 398–402 calls axp_diag_map_permanent immediately
|
||||
after paging_init. This is still inside setup_arch, before start_kernel calls
|
||||
mm_init. It even precedes bootmem_init in setup_arch.
|
||||
|
||||
axp_diag_map_permanent releases the early map and calls ordinary ioremap.
|
||||
In this tree, arch/arm64/mm/ioremap.c calls get_vm_area_caller, which reaches
|
||||
mm/vmalloc.c:1405 __get_vm_area_node and kzalloc_node at line 1421, followed by
|
||||
alloc_vmap_area. The allocator initialization (mem_init, kmem_cache_init,
|
||||
vmalloc_init) occurs later in init/main.c:mm_init.
|
||||
|
||||
Thus paging_init is NOT the readiness gate for ordinary ioremap. This diagnostic
|
||||
can introduce its own boot failure in the no-FORTIFY control. Do not use a
|
||||
failure of this control to draw conclusions about FORTIFY.
|
||||
|
||||
The transition needs a deliberate lifetime plan: ordinary mapping only after
|
||||
its allocators are ready, and safe retirement of the early mapping respecting
|
||||
early_ioremap_reset. Simply relocating one call without checking that lifetime
|
||||
is insufficient. If a temporary uncovered interval is chosen, document it and
|
||||
ensure failure writers cannot dereference a stale early mapping.
|
||||
|
||||
## Mapping attributes and persistence
|
||||
|
||||
early_memremap uses FIXMAP_PAGE_NORMAL, whereas the permanent ioremap and
|
||||
access-ramoops use PROT_DEVICE_nGnRE. This changes memory attributes. The writer
|
||||
only uses wmb and a readback; it has no explicit cache maintenance for a cached
|
||||
early mapping. These operations alone do not establish that early cached writes
|
||||
reach reset-surviving memory. Review compatible early I/O mapping attributes
|
||||
(early_ioremap uses FIXMAP_PAGE_IO in this tree) and verify on hardware.
|
||||
|
||||
## Remaining first-record limitations
|
||||
|
||||
- Milestones check the latch but do not participate in its atomic claim. A
|
||||
milestone interrupted by a failure writer can resume and overwrite the same
|
||||
slots. Separate milestone storage from first-failure storage, or use a
|
||||
protocol that also covers milestones and reentrancy.
|
||||
- A bare eight-byte header is treated as a complete prior failure. An interrupted
|
||||
write that persisted only that header can suppress later captures. Validate a
|
||||
complete record/commit indication and inspect mirrors.
|
||||
- The identifier remains per build, not per boot; archive/clear old captures
|
||||
under an explicit test procedure before repeating the same image.
|
||||
|
||||
The improvements are real, but v3 is not yet ready to be described as a
|
||||
validated early-capture channel. These findings concern instrumentation, not an
|
||||
identified cause of the original FORTIFY boot failure.
|
||||
|
||||
## Status
|
||||
|
||||
Local generator updated to **v4**: no `ioremap` until after `mm_init`; early
|
||||
map uses `early_ioremap` (IO attrs) and is kept until then; failure @0 vs
|
||||
milestones @2048; adopt only complete records. plain-v3 must not be flashed —
|
||||
rebuild control as plain-v4.
|
||||
@@ -0,0 +1,27 @@
|
||||
--- a/techpack/audio/dsp/rtac.c
|
||||
+++ b/techpack/audio/dsp/rtac.c
|
||||
@@ -652,6 +652,12 @@
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
mutex_lock(&rtac_voice_mutex);
|
||||
+ if (rtac_voice_data.num_of_voice_combos > ARRAY_SIZE(rtac_voice_data.voice)) {
|
||||
+ pr_err("%s: invalid voice count %u\n", __func__,
|
||||
+ rtac_voice_data.num_of_voice_combos);
|
||||
+ mutex_unlock(&rtac_voice_mutex);
|
||||
+ return;
|
||||
+ }
|
||||
/* look for device */
|
||||
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
|
||||
if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
|
||||
--- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c
|
||||
+++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c
|
||||
@@ -1092,6 +1092,9 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
+ if (dot11f_ie_rsn.pmkid_count > ARRAY_SIZE(dot11f_ie_rsn.pmkid))
|
||||
+ return false;
|
||||
+
|
||||
for (i = 0; i < dot11f_ie_rsn.pmkid_count; i++) {
|
||||
if (qdf_mem_cmp(dot11f_ie_rsn.pmkid[i],
|
||||
pe_session->fils_info->fils_pmkid,
|
||||
@@ -0,0 +1,127 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Revisión del port FORTIFY en curso — 2026-09-26, 21:25 UTC
|
||||
|
||||
Revisión de solo lectura del servidor; no se han editado scripts en ejecución.
|
||||
El dueño confirma combo4 arrancado. Cursor registra kernel #16, DMESG,
|
||||
SLAB_FREELIST_HARDENED, INIT_ON_ALLOC y INIT_ON_FREE activos, FORTIFY apagado.
|
||||
No se ha repetido aquí la inspección de LAB.
|
||||
|
||||
## Estado real
|
||||
|
||||
Job: `009-bisect-ksync-fortify-clang`, iniciado a las 21:15:03 UTC.
|
||||
Log: `/srv/rom/artifacts/detach-009-bisect-ksync-fortify-clang-20260926T211503Z.log`.
|
||||
A las 21:25 UTC seguía activo, con procesos clang consumiendo CPU. El log
|
||||
principal no se actualizaba desde las 21:18:39; eso no implicaba bloqueo.
|
||||
No había resultado final ni nuevo artefacto FORTIFY validado.
|
||||
|
||||
El script recibe **solo CONFIG_FORTIFY_SOURCE**. Es un ensayo aislado, no
|
||||
combo4+FORTIFY; coincide con el plan local. Preserva breakfast/bp4a y el
|
||||
empaquetado sobre GOODMAKE. El diff actual no modifica lib/string.c ni añade
|
||||
los stubs BUG. Mantener deshabilitado ALLOW_FORTIFY_BUG_STUBS.
|
||||
|
||||
## Hallazgo que revisar antes de aceptar el port
|
||||
|
||||
El script `apply_fortify_clang.py` adapta atributos y prototipos, pero deja
|
||||
consultas de tamaño incoherentes con algunos atributos:
|
||||
|
||||
- POS equivale a `pass_object_size(1)`.
|
||||
- `strlen` y `strnlen` reciben p con POS y consultan
|
||||
`__builtin_object_size(p, 0)`.
|
||||
- `strlcpy`, `strncat` y `strcpy` reciben q con POS y consultan su tamaño
|
||||
con tipo 0. En otros wrappers, POS0 sí coincide con las consultas tipo 0.
|
||||
|
||||
Esto no es un detalle estético. La información de tamaño implícita depende
|
||||
del tipo. Se compiló por stdin una prueba pequeña con el mismo Clang
|
||||
r563880c, también para AArch64 freestanding, sin escribir en el servidor:
|
||||
|
||||
```c
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
__attribute__((noinline))
|
||||
size_t mismatch(const char *const p __attribute__((pass_object_size(1)))) {
|
||||
return __builtin_object_size(p, 0);
|
||||
}
|
||||
__attribute__((noinline))
|
||||
size_t matched(const char *const p __attribute__((pass_object_size(0)))) {
|
||||
return __builtin_object_size(p, 0);
|
||||
}
|
||||
```
|
||||
|
||||
El IR optimizado de mismatch devuelve -1 (tamaño desconocido); matched
|
||||
devuelve el argumento implícito de tamaño. **Límite:** es una prueba aislada
|
||||
noinline del mecanismo, no una demostración de que todas las llamadas a los
|
||||
wrappers always_inline reales pierdan protección. Es necesario probar los
|
||||
wrappers reales con optimización/LTO, tamaños conocidos y desconocidos.
|
||||
|
||||
Referencia primaria:
|
||||
[Clang: pass_object_size](https://clang.llvm.org/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size).
|
||||
|
||||
Adaptar coherentemente los atributos y la semántica de tamaño del 4.14;
|
||||
no sustituir todas las consultas por tipo 1 a ciegas, porque cambia la
|
||||
política whole-object/subobject y puede alterar accesos válidos del árbol.
|
||||
|
||||
## Otros puntos de aceptación pendientes
|
||||
|
||||
- El port elimina `depends on !CC_IS_CLANG` sin implementar la detección y
|
||||
los límites de versión/capacidades que propone su propio plan. Los macros
|
||||
de atributos tienen fallback vacío: un compilador no compatible puede
|
||||
volver a habilitar un FORTIFY sin soporte. No es prueba de fallo de Clang 21,
|
||||
pero la configuración aún no tiene una protección adecuada.
|
||||
- `__diagnose_as` está definido pero no utilizado en los wrappers revisados.
|
||||
Documentar si se omite intencionadamente y validar diagnósticos reales;
|
||||
declarar el atributo no implementa su efecto.
|
||||
- El empaquetador imprime propiedades/config pero varias comprobaciones
|
||||
terminan en `|| true`. Mostrar el valor no garantiza que coincida con el
|
||||
esperado. Antes de entregar: comparar hashes de ramdisk/DTB, metadatos,
|
||||
kernel inyectado y opciones de la config embebida, fallando si difieren.
|
||||
- No editar el script activo. Congelar copia, hash, argumentos, diff y
|
||||
configuración por experimento para evitar repetir el incidente combo4.
|
||||
|
||||
## Qué debe probarse además de compilar y arrancar
|
||||
|
||||
Sin stubs es necesario, pero no suficiente: quitar accidentalmente una
|
||||
comprobación también puede hacer desaparecer símbolos de overflow.
|
||||
Usar casos válidos y desbordamientos intencionados en un harness aislado
|
||||
de los wrappers reales (no provocar corrupción en LAB), comprobando el
|
||||
diagnóstico o camino de fallo esperado con Clang/LTO. Verificar también
|
||||
ausencia de stubs en binarios/módulos, .config efectiva y hardware básico.
|
||||
Después del ensayo aislado, validar combo4+FORTIFY como artefacto distinto.
|
||||
|
||||
Conclusión: el enfoque mejora y el build está activo; aún hay detalles del
|
||||
port y pruebas de eficacia pendientes. No equivale a un port ya aceptado.
|
||||
@@ -0,0 +1,103 @@
|
||||
# FORTIFY POS0: dos errores localizados y corrección candidata
|
||||
|
||||
Revisión del job `009-bisect-ksync-fortify-pos0`, que terminó con exit=1
|
||||
el 2026-09-26 a las 21:54:28 UTC. Se leyó el log del servidor, el fragmento
|
||||
aportado y la conversación reciente de Cursor de este proyecto.
|
||||
|
||||
## Resultado
|
||||
|
||||
Se reprodujeron los dos símbolos sin resolver en compilaciones aisladas de
|
||||
los archivos responsables, usando los argumentos del build fallido y su
|
||||
Clang 21. Añadiendo validaciones explícitas de capacidad, desaparecen ambos
|
||||
en los objetos tras LTO, **sin stubs y sin desactivar FORTIFY**.
|
||||
|
||||
[Parche candidato](009-fortify-driver-bounds-candidate.patch).
|
||||
Es un cambio local propuesto en esta revisión, no un parche upstream.
|
||||
No se ha aplicado al árbol de compilación de Cursor. `git apply --check`
|
||||
contra el árbol remoto actual terminó correctamente.
|
||||
|
||||
## Localización en los objetos reales del build fallido
|
||||
|
||||
Raíz: `/srv/rom/src/lineage/out/target/product/sunfish/obj/KERNEL_OBJ`.
|
||||
|
||||
- `techpack/audio/dsp/q6_dlkm.lto.o`: `rtac_remove_voice+0x1d0`,
|
||||
relocación `R_AARCH64_CALL26 __read_overflow2`.
|
||||
- `drivers/staging/qcacld-3.0/wlan.lto.o`:
|
||||
`lim_process_fils_auth_frame2+0xe48`,
|
||||
relocación `R_AARCH64_CALL26 __read_overflow`.
|
||||
|
||||
Importante: modpost etiqueta el error con `.lto.ko`, pero los objetos
|
||||
intermedios disponibles son `.lto.o`. Los `.ko` antiguos que quedan en out
|
||||
no deben confundirse con módulos del intento fallido.
|
||||
|
||||
### Audio
|
||||
|
||||
`techpack/audio/dsp/rtac.c` tiene capacidad para dos entradas de voz.
|
||||
`rtac_remove_voice` usa un contador global para recorrer el array y llama a
|
||||
`shift_voice_devices`, que copia del elemento `idx+1`. El código de alta
|
||||
ya limita el número de entradas, pero ese invariante no basta para eliminar
|
||||
la rama de diagnóstico en esta compilación.
|
||||
|
||||
El candidato valida el contador bajo `rtac_voice_mutex`, antes del recorrido.
|
||||
Si supera ARRAY_SIZE(voice), registra el error, libera el mutex y retorna.
|
||||
Esto evita aceptar el estado inválido; no altera el recorrido válido ni
|
||||
desactiva las comprobaciones de memoria.
|
||||
|
||||
### Wi-Fi
|
||||
|
||||
`lim_process_fils.c:1095` recorre `dot11f_ie_rsn.pmkid_count` y compara
|
||||
PMKID de 16 bytes. El array declarado en `dot11f.h:6725` es `pmkid[4][16]`.
|
||||
El objeto LTO conserva una rama al helper de overflow cuando el contador
|
||||
alcanza cinco o más sin haberse encontrado una coincidencia.
|
||||
|
||||
El parser `dot11f.c:6703` ya rechaza contadores mayores de cuatro. Por tanto,
|
||||
esta revisión **no demuestra que exista una entrada explotable ni una lectura
|
||||
real fuera de límites**. El compilador no elimina todas las ramas inválidas
|
||||
en el consumidor. El candidato comprueba ARRAY_SIZE(pmkid) justo antes del
|
||||
bucle y devuelve false ante un contador inválido.
|
||||
|
||||
## Validación realizada
|
||||
|
||||
Se trabajó en directorios temporales de rom-dev01, sin cambiar las fuentes
|
||||
ni los objetos de salida usados por Cursor:
|
||||
|
||||
- `/tmp/axp-fortify-probe-bl9zsxpt`: reproducción de ambos archivos y
|
||||
prueba Wi-Fi; contiene también una variante preliminar de audio no elegida.
|
||||
- `/tmp/axp-fortify-probe-kkcpn4o9`: reproducción y candidato final de audio.
|
||||
|
||||
Método: leer la orden original de `.rtac.o.cmd` / `.lim_process_fils.o.cmd`,
|
||||
conservar sus opciones de Clang/LTO/CFI e includes; cambiar únicamente la
|
||||
fuente/output a copias temporales, evitar generar dependencias en out y
|
||||
añadir el directorio original para resolver includes locales. Ejecutar
|
||||
`ld.lld -m aarch64linux -O2 -r` sobre cada objeto bitcode y consultar
|
||||
símbolos sin resolver con llvm-nm.
|
||||
|
||||
Resultados:
|
||||
|
||||
```text
|
||||
audio baseline: U __read_overflow2
|
||||
audio con validación del contador: ningún símbolo overflow sin resolver
|
||||
wifi baseline: U __read_overflow
|
||||
wifi con validación del contador: ningún símbolo overflow sin resolver
|
||||
```
|
||||
|
||||
**Alcance:** son dos unidades de compilación y su enlace LTO aislado. No se
|
||||
ha repetido el enlace completo de q6_dlkm/wlan, modpost global, ROM o boot.
|
||||
No se han probado arranque, llamadas de voz, audio ni Wi-Fi en LAB. Tampoco
|
||||
se sustituye con esto el harness pendiente de eficacia de los wrappers.
|
||||
|
||||
## Reanudación para Cursor
|
||||
|
||||
1. Conservar la evidencia del intento fallido y revisar/aplicar el candidato
|
||||
después del reset y del port FORTIFY en la receta reproducible. El script
|
||||
ksync resetea las fuentes: una edición manual previa se perdería.
|
||||
2. Validar módulos completos/modpost sin `__read_overflow*`, sin nuevos
|
||||
stubs, sin `__NO_FORTIFY` en estos controladores y sin apagar LTO/CFI.
|
||||
3. Validar el harness de FORTIFY, la config efectiva y el empaquetado antes
|
||||
de entregar un nuevo boot. Mantener combo4 como referencia que arranca.
|
||||
4. Tras aceptar FORTIFY aislado, probar combo4+FORTIFY y funciones de hardware.
|
||||
|
||||
La conversación de Cursor proponía mirar los call sites o una exclusión
|
||||
puntual con `__NO_FORTIFY`. Ya hay evidencia para intentar primero estas
|
||||
validaciones de límites. Las advertencias de versionado de símbolos WLAN
|
||||
son un asunto adicional; esta corrección no afirma resolverlas.
|
||||
@@ -0,0 +1,99 @@
|
||||
# v4 capture results review — 2026-09-27
|
||||
|
||||
## Result
|
||||
|
||||
The capture channel still has no validated panic-survival result. Do not infer
|
||||
that AES selectively overwrites offset 0 while sparing offset 2048, and do not
|
||||
choose a high offset as a safe region without establishing its ownership and
|
||||
observed persistence. No FORTIFY-specific failure has been captured yet.
|
||||
|
||||
Reviewed Cursor's recorded experiment summaries, v4 generated source, the kernel
|
||||
ramoops implementation, sunfish DT and init.ramoops.sh. Read the current LAB alt
|
||||
region while LAB was running combo4 #16; no device writes, flashes or reboots.
|
||||
|
||||
Current 4 MiB capture SHA-256:
|
||||
`24bbccbf4ed1271bc0950167f4a7921e2a79c534ad735d506ebb504a0353f310`.
|
||||
It contains `AXPDIAG0,M,20260927T084531Z,panic_reg` at 2048, and no AXPDIAG
|
||||
marker at the eight expected failure offsets 0,128,256,384,512,640,768,896.
|
||||
|
||||
## Unsupported steps in the current explanation
|
||||
|
||||
1. Random-looking bytes are not proof that the current test caused encryption.
|
||||
Without a before/after snapshot from the same attempt, they can be old data,
|
||||
overwritten data or ciphertext. The stored old captures are from different
|
||||
experiments and cannot establish this particular transition.
|
||||
2. The milestone is written again on every v4 boot, with a build-time identifier
|
||||
shared by every boot of that image. Cursor reports that the first SysRq-c
|
||||
returned with kernel_panic, followed by further live v4 tests. A regenerated
|
||||
milestone is therefore an alternative to survival across panic. Final
|
||||
recovery to combo4 does not resolve its age across the preceding boots.
|
||||
3. The v4 latch is in ordinary kernel RAM. SysRq-x sets it. Clearing the alt
|
||||
region with dd does not clear the latch in the running kernel. A subsequent
|
||||
SysRq-c in that same boot will skip recording, even if the region looks
|
||||
empty. Cursor's summary says a clean retry occurred but does not establish
|
||||
the full clear/reboot/no-X sequence; this remains a confounder, not a proven
|
||||
mistake in the executed sequence.
|
||||
4. Current fs/pstore/ram.c exposes ramoops_decrypt_alt: it reads cxt->size,
|
||||
decrypts with crypto_aead_decrypt, and copies the whole buffer back only on
|
||||
success. This is not a panic-time encrypt routine. The inspected sunfish
|
||||
init script invokes ramoops -D and then ramoops -g -l -c. No kernel panic
|
||||
encrypt implementation was identified by these searches. Firmware ownership
|
||||
remains possible, but unproven. Disabling kernel decryption would not by
|
||||
itself demonstrate that an external encryption path was disabled.
|
||||
5. The DT declares a 4 MiB alt ramoops reservation, not a separately reserved
|
||||
diagnostic high-offset region. No offset within it is currently shown safe.
|
||||
|
||||
## Next useful test: preserve attribution before another rebuild
|
||||
|
||||
Use the existing no-FORTIFY control to establish a documented timeline. Keep
|
||||
SysRq-x and SysRq-c experiments in separate boots, and archive full dumps,
|
||||
kernel identity, and boot reason at each available observation point.
|
||||
|
||||
- Archive and clear the diagnostic region BEFORE booting the control; then
|
||||
verify the region contains no complete old failure record. Do not clear only
|
||||
the persistent bytes after X and assume the in-memory latch has reset.
|
||||
- Run a fresh boot with no X. Archive the pre-C contents; execute only C.
|
||||
Recover directly to combo4 when possible, recording any intermediate v4
|
||||
boot or forced hardware reset. A forced reset is a separate experimental
|
||||
condition from the automatic panic reboot.
|
||||
- Compare the full before/after bytes, including mirrors and milestone area.
|
||||
Do not use the same-build milestone alone as evidence of survival.
|
||||
- Independently test X persistence through the SAME recovery sequence. This
|
||||
distinguishes a writer that works in a live kernel from storage that survives
|
||||
the recovery path. It does not replace the fresh-C test.
|
||||
|
||||
If fresh C still leaves no attributable record, a control-only diagnostic can
|
||||
read back/validate the exact committed C record immediately before panic and
|
||||
report or expose that result while observable. This separates failure to write
|
||||
from later loss. It must remain a diagnostic experiment, not a swallowed panic
|
||||
or a production hardening change.
|
||||
|
||||
Only after identifying which transition loses a verified record should the
|
||||
next patch change its storage or intercept an identified writer. A separately
|
||||
reserved region needs a board/firmware-compatible design; an arbitrary high
|
||||
offset is not a substitute for that evidence.
|
||||
|
||||
## Remaining source limitation
|
||||
|
||||
v4 composes up to 128 bytes but caps persistence at 120; long tokens can lose
|
||||
the terminating newline required by adoption. This does not explain the short
|
||||
sysrq-c/sysrq-x records, but must be fixed for general panic messages.
|
||||
|
||||
The original FORTIFY cause remains open. Diagnostics v2/v3 had concrete
|
||||
implementation defects; v4 fixes those major defects and boots, but its test
|
||||
results still do not establish a working early-panic channel.
|
||||
|
||||
## Follow-up LAB (same evening, documented)
|
||||
|
||||
Clean C-only:
|
||||
`.local-artifacts/009-v4-clean-c-20260927T190738Z/` — clear → v4 boot (no X)
|
||||
→ C → **intermediate auto v4 reboot** (`kernel_panic`) → combo4. No
|
||||
`AXPDIAG1` at T3 or T4. Fail zone 0:1024 went from all-zero (T2) to opaque
|
||||
non-`AXPDIAG1` bytes (T3=T4). Latch/X confounder ruled out for this run.
|
||||
|
||||
X persistence (no panic):
|
||||
`.local-artifacts/009-v4-x-persist-20260927T191143Z/` — `AXPDIAG1,X,...`
|
||||
survives combo4 recover; fail[0:128] identical before/after.
|
||||
|
||||
Next: distinguish “C never committed” vs “lost across panic” with a
|
||||
control-only pre-panic readback of the committed C record (see above).
|
||||
@@ -0,0 +1,50 @@
|
||||
# Verification of clean C and X experiments — 2026-09-27
|
||||
|
||||
Independently parsed the binary dumps and recorded kernel/boot properties in:
|
||||
|
||||
- `.local-artifacts/009-v4-clean-c-20260927T190738Z/`
|
||||
- `.local-artifacts/009-v4-x-persist-20260927T191143Z/`
|
||||
|
||||
The clean C test removes the earlier X/latch confounder: T2 has a zero failure
|
||||
zone and a fresh v4 #29 boot; T3 reports kernel_panic on an intermediate v4 boot;
|
||||
T4 is combo4 #16. No complete failure record is present after C. The intermediate
|
||||
boot prevents localization of loss to the panic itself versus later boot stages.
|
||||
|
||||
The X test demonstrates that all eight complete 55-byte X records survive the
|
||||
normal recovery to combo4 unchanged. It does not include the panic transition
|
||||
of the C test, so it is a recovery control rather than the same full sequence.
|
||||
|
||||
Precision correction: T3 and T4 are NOT identical binary dumps. Their first 128
|
||||
bytes match, but 7,213 bytes differ across 4 MiB, including six bytes in the first
|
||||
1 KiB. Likewise X2 and X3 have 79 differing bytes, despite their complete X
|
||||
records surviving intact. These differences do not negate X persistence, but
|
||||
avoid describing entire zones or dumps as identical. Their cause is not yet
|
||||
established.
|
||||
|
||||
Next diagnostic should check a full C record (primary and mirrors, expected
|
||||
event/id/caller/terminator) immediately after its writer and before panic.
|
||||
The success/failure result must be observable independently of the storage
|
||||
whose survival is under test. A print to a console that cannot be retrieved, or
|
||||
another flag only in the same alt region, would repeat the observability problem.
|
||||
A control-only two-phase arm/readback/trigger protocol can expose the record
|
||||
and status through adb before deliberately entering panic; document the changed
|
||||
timing and validate the actual immediate path subsequently. Keep normal FORTIFY
|
||||
failure behavior intact.
|
||||
|
||||
This establishes a narrower investigation: the writer plus normal recovery can
|
||||
work; a clean panic experiment still loses or fails to produce the record.
|
||||
Selective AES overwrite and a safe alternative offset remain unproven.
|
||||
|
||||
## Follow-up: two-phase arm/readback/panic (same evening)
|
||||
|
||||
Artifact:
|
||||
`.local-artifacts/009-v4-twophase-x-then-c-20260927T191809Z/`
|
||||
|
||||
Using existing v4 (no rebuild): SysRq-x → **adb dump confirms** eight
|
||||
complete `AXPDIAG1,X` records → SysRq-c (latch no-ops C write; panic runs)
|
||||
→ intermediate v4 (`kernel_panic`) → combo4.
|
||||
|
||||
Result: pre-verified X is **absent at P3 and P4**. Independent channel was
|
||||
adb, not alt-only flags. Timing caveat: adb RTT between arm and panic; type
|
||||
X not C. Narrow reading: fail-zone content verified before panic does not
|
||||
survive this panic/reboot path; soft recover without panic still preserves X.
|
||||
@@ -0,0 +1,135 @@
|
||||
# Gate G / FR-017 — kernel hardening attribution (ship candidate)
|
||||
|
||||
**What “Gate G doc” means:** the acceptance contract asks for a written list of
|
||||
**what kernel hardening we applied, what we skipped and why**, plus userspace
|
||||
AVB/signing gaps (or “impossible on this stack”). This file is that list for the
|
||||
**kernel** half. Userspace AVB is tracked separately below as still open.
|
||||
|
||||
**LAB device:** `11231JEC207477` only.
|
||||
**Accepted kernel ship pack (LAB 2026-10-01):** Stage1 Graphene/AH + combo4 +
|
||||
Clang FORTIFY + Magisk preroot + **CVE clean-offset 429** + **hi-batch1+2 (15)**
|
||||
with `CVE-2022-49980` denylisted. Clean-only `#47` / hi-batch1 `#48` remain bisect GOODs.
|
||||
|
||||
Prior Stage1-only pack `20260929T123401Z-axp-stage1-combo4` remains the
|
||||
**recover / bisect GOOD** baseline (kernel `#32`).
|
||||
|
||||
## Current accepted artifact
|
||||
|
||||
| Field | Value |
|
||||
|--------|--------|
|
||||
| Artifact | `/srv/rom/artifacts/009-axp-los23-port/20261001T201836Z-axp-stage1-combo4-cve-hi-batch2/` |
|
||||
| Local flash copy | `.local-artifacts/009-flash-cve-hi-batch2/` |
|
||||
| Prior hi-batch1 GOOD | `20261001T192418Z-…-cve-hi-batch1/` (`#48`) |
|
||||
| Prior clean GOOD | `20261001T180955Z-…-cve-clean/` (`#47`) |
|
||||
| Kernel base | LOS `msm-4.14` `@ 28f9290ae067` (`4.14.357-openela`) |
|
||||
| Running LAB (boot flash) | slot `_a`, kernel `#49` `Thu Oct 1 19:49:54 UTC 2026` |
|
||||
| CVE list | clean **429** + hi-batch1 (**7**) + hi-batch2 (**8**) |
|
||||
| Apply quality | clean OK=429; hi OK=15 fuzz≤1 (elevated abs-offset) |
|
||||
| Note | host detach `exit=141` after `bacon_exit=0` = tee SIGPIPE, not a real fail |
|
||||
| Magisk | EXTENDROM-class preroot v30.7 (virgin until Additional Setup; `magiskd` OK) |
|
||||
| KernelSU | absent (Magisk track) |
|
||||
|
||||
**Flash procedure that works:** recovery → (optional wipe) → sideload zip →
|
||||
**Reboot system**. Bisect/CVE boots may use `fastboot -s 11231JEC207477 flash boot`
|
||||
only when CRC/modules match the installed vendor. Do **not** flash Magisk
|
||||
`boot.img` onto the other slot alone (new kernel + old vendor ⇒ `wlan` CRC mismatch).
|
||||
|
||||
**Build entrypoints:**
|
||||
|
||||
- Apply: `apply_stage1_combo4.sh` then `apply_cve_strict.sh` with
|
||||
`CVE_STRICT_LIST=…/cve-clean-offset.list` (denylist includes 49980)
|
||||
- Bacon: `scripts/009-bacon-axp-stage1-combo4-cve-clean.sh` (or
|
||||
`009-bacon-cve-clean-post49980` host wrapper)
|
||||
- Baseline-only: `scripts/009-bacon-axp-stage1-combo4.sh`
|
||||
|
||||
## Applied (attributable)
|
||||
|
||||
### A. Combo4 defconfig + Clang FORTIFY port
|
||||
|
||||
| Item | Source / notes |
|
||||
|------|----------------|
|
||||
| `CONFIG_FORTIFY_SOURCE=y` | Ship; Clang port required on this toolchain |
|
||||
| `CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y` | Combo4 |
|
||||
| `CONFIG_INIT_ON_FREE_DEFAULT_ON=y` | Combo4 |
|
||||
| `CONFIG_SECURITY_DMESG_RESTRICT=y` | Combo4 |
|
||||
| `CONFIG_SLAB_FREELIST_HARDENED=y` | Combo4 (not `SLAB_HARDENED` alone) |
|
||||
| Clang FORTIFY / `__pass_object_size` | `fortify-clang/apply_fortify_clang.py` (Kees-class port adapted to 4.14 `string.h`) |
|
||||
| Nested strlen fix | `strlcpy`/`strcpy` use `__underlying_strlen(q)` — LAB smoking gun 2026-09-28 |
|
||||
| Driver bounds | `fortify-clang/0001-driver-bounds-rtac-fils.patch` (link/false-path) |
|
||||
| `# CONFIG_KSU is not set` | Magisk track |
|
||||
|
||||
### B. Stage1 Graphene / AndroidHardening (30 patches)
|
||||
|
||||
Source tree: AXP `kernel_patches` (host `/srv/rom/references/axp/kernel_patches`).
|
||||
List: `vendor/sunfish-a16/patches/009-kernel-hardening/stage1.list` via
|
||||
`apply_stage1.sh`.
|
||||
|
||||
Includes (series names): Deny_USB, allocsize (partial), bugon, fortify
|
||||
strict-string patch (AXP `0004` — **not** a substitute for the Clang port),
|
||||
misc, random, ro, sanitize, slab, unused, etc. Full paths in `stage1.list`.
|
||||
|
||||
**LAB marker:** `/proc/sys/kernel/deny_new_usb` present (Graphene Deny USB).
|
||||
|
||||
**Build fix retained:** Stage1 `slab/0014` misfuzz into `is_root_cache` →
|
||||
reverted in `apply_stage1_combo4.sh` when detected (`BUILD-FIXES.md`).
|
||||
|
||||
## Explicitly NOT in this ship pack
|
||||
|
||||
| Item | Why |
|
||||
|------|-----|
|
||||
| Full `cve-strict.list` (~503) | Logo hang; includes high-offset (≥200) and `CVE-2022-49980`. Do not reflash `20260929T181525Z-…-cve` / old `*-kh-cve`. |
|
||||
| `CVE-2022-49980` (USB gadget UAF) | **Denylist.** Alone reproduces Google-logo hang on LAB (2026-10-01). One-liner takes `udc_lock` in `usb_udc_uevent` while this 4.14 tree still fires uevents under the same lock (`device_add` / bind / unbind). Needs lock-scope companion port, not bulk apply. See `docs/009-cve-bisect-plan.md`. |
|
||||
| High-offset CVE set (`cve-high-offset-ge200.txt`, ~73) | Quarantine + sunfish filter (26 KEEP). **hi-batch1+2 (15) LAB BOOT_OK `#49`**. Remaining KEEP ~10 (skip `3777`/`26643` nf_tables-class). |
|
||||
| LinuxIncrementals | Skipped (policy / scope) |
|
||||
| Failed Stage1 probes | allocsize/0007, ro/0007+0034, slab/0010+0018 — port later |
|
||||
| Location lockdown | FR-018 — **skip forever on this track**; keep GPS precise/fast (LOS defaults) |
|
||||
| FORTIFY `BUG()` overflow stubs | Invalid ship fix; never reuse |
|
||||
| KernelSU / SusFS | Out of Magisk ship track (optional later recycle) |
|
||||
| Userspace Deblob (Widevine/IMS/CNE) | Deferred (mobile data / Widevine) |
|
||||
| Bootloader lock | Wont (AXP/LOS unlocked norm) |
|
||||
|
||||
## Historical note (why this pack exists)
|
||||
|
||||
1. Stage1 / CVE / kh-full bacons of 2026-09-18 **compiled** but **did not boot** on LAB (logo hang).
|
||||
2. Bisect found Clang FORTIFY + nested `strlen` inside `strlcpy` as a hard brick; combo4 without broken FORTIFY booted.
|
||||
3. Fixed FORTIFY → combo4+FORTIFY Magisk bacon OK → Stage1 **re-tried on that baseline** → LAB OK 2026-09-29.
|
||||
|
||||
## Userspace Gate G (still open)
|
||||
|
||||
Kernel attribution above satisfies the **FR-017 / SC-010 kernel** bullet.
|
||||
Userspace / signing work is **not** done by this kernel bacon.
|
||||
|
||||
### In scope (do)
|
||||
|
||||
| Item | Intent |
|
||||
|------|--------|
|
||||
| **Release / definitive signing keys** | Ship OTAs and images signed with project release keys (not AOSP test-keys). Phonesky and update identity stay on that key across releases. Secrets stay on `rom-dev01` under `/srv/rom/secrets/` — never in Git. |
|
||||
| **AVB as applicable on unlocked sunfish** | Match GOLDEN/AXP-class AVB *build* posture where LOS 23.2 allows; document any gap that is impossible without locked bootloader or vendor glue we do not have. |
|
||||
| **Userspace hardening** | Staged Graphene/AXP-class patches (and CVE mega on the boot-OK kernel pack) — attributable, bisectable. |
|
||||
| **CVE mega (kernel)** | **Partial ship:** clean-offset 429 on Stage1+combo4+FORTIFY (LAB OK). Remaining: high-offset quarantine + proper 49980 port. Never flash `20260918*-kh-cve/full` or full-503 BAD packs. |
|
||||
|
||||
### Out of scope (explicit skip)
|
||||
|
||||
| Item | Why |
|
||||
|------|-----|
|
||||
| **Bootloader relock / locked-device ship** | Neither **AXP.OS** nor **LineageOS** ship a locked-bootloader product as the normal path. **IOdes** does; we are not cloning that model. LAB and end-user sunfish remain **unlocked** for Magisk preroot / sideload workflow. Do **not** treat “cannot lock bootloader” as a Gate G failure. |
|
||||
|
||||
Gap rule unchanged: anything still missing from the **in-scope** rows must be present **or** written down as impossible on this stack — no silent omit.
|
||||
|
||||
**Checklist + measured GOLDEN vs LAB:** `docs/009-hardening-signing-checklist.md`
|
||||
(T040). LAB 2026-09-29 is still `userdebug`/`test-keys`/`orange`; GOLDEN is
|
||||
`user`/`release-keys`/`orange` unlocked — same unlock class, missing project
|
||||
keys.
|
||||
|
||||
## Prior known-good (fallback)
|
||||
|
||||
| Artifact | Role |
|
||||
|----------|------|
|
||||
| `20260929T033128Z-axp-combo4-fortify` | Magisk + combo4+FORTIFY **without** Stage1 |
|
||||
| `20260918T143547Z-axp-full` | Pre-KH Magisk baseline (bisect GOODMAKE source) |
|
||||
|
||||
## Owner LAB smoke (2026-09-29)
|
||||
|
||||
Owner reported Magisk, microG, and related checks OK on Stage1 pack after
|
||||
sideload to slot `_b`. Optional: second sideload to refresh leftover slot `_a`
|
||||
(not required for daily use).
|
||||
@@ -0,0 +1,248 @@
|
||||
# 009 — Userspace hardening / signing / AVB checklist (Gate G)
|
||||
|
||||
**Task:** T040.
|
||||
**Companion:** kernel half = `docs/009-gate-g-kernel-attribution.md`.
|
||||
**Policy (2026-09-29):** project **release keys yes**; **bootloader relock no**
|
||||
(AXP/LOS unlocked norm; IOdes-class lock = non-goal). 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)
|
||||
|
||||
| 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 | **done US-S5-1** | LAB `162840Z` `CONFIG_SECURITY_YAMA=y` |
|
||||
| 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`): `CONFIG_SECURITY_YAMA=y` +
|
||||
`CONFIG_SLAB_FREELIST_RANDOM=y` — see
|
||||
`docs/009-lab-acceptance-20261002-uss5.md`
|
||||
- [ ] Optional later: `CVE-2022-49980` lock-scope port; Stage1 slab FAIL
|
||||
retries; `hardened_malloc`
|
||||
|
||||
Map updates: `docs/009-kernel-hardening-map.md` + Gate G attribution.
|
||||
|
||||
### US-S6 — Optional later
|
||||
|
||||
- [ ] Switch default lunch to `lineage_sunfish-user` for ship
|
||||
- [ ] 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.
|
||||
@@ -0,0 +1,64 @@
|
||||
# AXP Internet connectivity check providers (from GOLDEN Settings)
|
||||
|
||||
Source: `Settings.apk` on GOLDEN `11071JEC203839`
|
||||
(`ConnectivityCheckPreferenceController` + `connectivity_check_*` arrays),
|
||||
pulled 2026-09-18.
|
||||
Artifact: `.local-artifacts/002-golden/20260918-connectivity/`
|
||||
|
||||
Preference: **Internet connectivity check**
|
||||
(`connectivity_check_settings`) — sets global
|
||||
`captive_portal_{http,https,fallback,other_fallback}_url` and
|
||||
`captive_portal_mode`.
|
||||
|
||||
## GOLDEN UI list (as shipped)
|
||||
|
||||
| value | UI label | HTTP check URL |
|
||||
|------:|----------|----------------|
|
||||
| 0 | Disabled | *(mode=0; stock Google URLs cleared/disabled)* |
|
||||
| 1 | Amazon Fire OS (US) | `http://fireoscaptiveportal.com/generate_204` |
|
||||
| 2 | Cloudflare (US) | `http://cp.cloudflare.com` |
|
||||
| 3 | **AXP.OS (DE)** | `http://captiveportal.axpos.org/generate_204` |
|
||||
| 4 | Google (US) [default] | `http://connectivitycheck.gstatic.com/generate_204` |
|
||||
| 5 | Huawei (CN) | `http://connectivitycheck.platform.hicloud.com/generate_204` |
|
||||
| 6 | Kuketz (DE) | `http://captiveportal.kuketz.de` |
|
||||
| 7 | Microsoft Edge (US) | `http://edge-http.microsoft.com/captiveportal/generate_204` |
|
||||
| 8 | openSUSE (DE) | `http://conncheck.opensuse.org` |
|
||||
| 9 | Ubuntu (UK) | `http://connectivity-check.ubuntu.com` |
|
||||
|
||||
Code also implements (not in GOLDEN `connectivity_check_entries`):
|
||||
|
||||
| value | internal name | HTTP check URL |
|
||||
|------:|---------------|----------------|
|
||||
| 10 | Xiaomi / MIUI | `http://connect.rom.miui.com/generate_204` |
|
||||
| 11 | GrapheneOS | `http://connectivitycheck.grapheneos.network/generate_204` |
|
||||
|
||||
Note: value `3` constants are named `DIVESTOS_*` in smali but point at
|
||||
`captiveportal.axpos.org` and are labeled **AXP.OS (DE)** in the UI.
|
||||
|
||||
## Clone target for LOS 23.2 (sans axp.os)
|
||||
|
||||
**Drop** value 3 / AXP.OS / `*.axpos.org` entirely (spec: no axp.os endpoints).
|
||||
|
||||
Ship UI (renumber values contiguously after drop):
|
||||
|
||||
| UI label | HTTP | HTTPS |
|
||||
|----------|------|-------|
|
||||
| Disabled | — | — |
|
||||
| Amazon Fire OS (US) | `http://fireoscaptiveportal.com/generate_204` | `https://fireoscaptiveportal.com/generate_204` |
|
||||
| Cloudflare (US) | `http://cp.cloudflare.com` | `https://cp.cloudflare.com` |
|
||||
| Google (US) [default] | `http://connectivitycheck.gstatic.com/generate_204` | `https://www.google.com/generate_204` |
|
||||
| Huawei (CN) | `http://connectivitycheck.platform.hicloud.com/generate_204` | `https://connectivitycheck.platform.hicloud.com/generate_204` |
|
||||
| Kuketz (DE) | `http://captiveportal.kuketz.de` | `https://captiveportal.kuketz.de` |
|
||||
| Microsoft Edge (US) | `http://edge-http.microsoft.com/captiveportal/generate_204` | same (AXP uses HTTP URL for https slot) |
|
||||
| openSUSE (DE) | `http://conncheck.opensuse.org` | `https://conncheck.opensuse.org` |
|
||||
| Ubuntu (UK) | `http://connectivity-check.ubuntu.com` | `https://connectivity-check.ubuntu.com` |
|
||||
|
||||
Optional extras already in GOLDEN controller (owner choice later): Xiaomi, GrapheneOS.
|
||||
|
||||
Google default also sets:
|
||||
- fallback: `http://www.google.com/gen_204`
|
||||
- other fallback: `http://play.googleapis.com/generate_204`
|
||||
|
||||
GrapheneOS (if enabled later) also sets:
|
||||
- fallback: `http://grapheneos.online/gen_204`
|
||||
- other: `http://grapheneos.online/generate_204`
|
||||
@@ -0,0 +1,229 @@
|
||||
# Auditoría de los fallos de arranque del kernel — 2026-09-26
|
||||
|
||||
Revisión de documentación local, scripts, fuentes y artefactos de `rom-dev01`.
|
||||
No se ha compilado, flasheado, reiniciado ni modificado el servidor o los teléfonos.
|
||||
Este documento registra evidencias y un punto de reanudación; no cambia requisitos.
|
||||
|
||||
## Conclusión
|
||||
|
||||
**Hallazgo prioritario posterior: los bisect cambian TARGET_RELEASE de bp4a
|
||||
a bp2a.** La comparación binaria y el log demuestran que no se está aislando
|
||||
el hardening. Ver la sección siguiente antes de construir o probar más boots.
|
||||
|
||||
Hay errores verificables en la preparación de los experimentos y en su trazabilidad.
|
||||
Todavía no hay una traza que identifique la causa exacta del fallo de arranque.
|
||||
El siguiente paso debe recuperar un experimento controlado, no volver a aplicar
|
||||
todo el hardening/CVE/deblob desde cero.
|
||||
|
||||
## Hallazgo principal: cambio accidental de release Android en los bisect
|
||||
|
||||
Tras confirmar el dueño que GOODMAKE también arranca, se han desempaquetado
|
||||
GOODMAKE y el boot mild y extraído sus configuraciones IKCONFIG y ramdisks.
|
||||
[Evidencia y diff de configuración](009-kernel-boot-image-comparison-20260926.txt).
|
||||
|
||||
- GOODMAKE: cabecera con parche `2026-09`; ramdisk declara
|
||||
`ro.build.version.security_patch=2026-09-01`, SDK completo `36.1`.
|
||||
- MILD: cabecera con parche `2025-08`; ramdisk declara
|
||||
`ro.build.version.security_patch=2025-08-05`, SDK completo `36.0`.
|
||||
- DTB idéntico. Ramdisk diferente, incluyendo bibliotecas y propiedades.
|
||||
- Configuración del kernel: además de DMESG/SLAB cambian VT/fbcon, watchdog
|
||||
y PANIC_TIMEOUT (de 0 a 5), entre otros cambios derivados. La base buena
|
||||
conservaba configuración de depuración y el bloque Kconfig de KernelSU,
|
||||
aunque CONFIG_KSU estaba desactivado.
|
||||
|
||||
Origen confirmado en el servidor:
|
||||
|
||||
- `scripts/009-bacon-axp.sh:87` usa `breakfast sunfish userdebug`.
|
||||
- `vendor/lineage/build/envsetup.sh` hace que breakfast lea
|
||||
`vendor/lineage/vars/aosp_target_release`, cuyo valor actual es `bp4a`.
|
||||
- Los bisect fuerzan `lunch lineage_sunfish-bp2a-userdebug`.
|
||||
- El log `detach-009-bisect-dc-20260921T180802Z.log:53` registra literalmente
|
||||
`TARGET_RELEASE ("bp4a" -> "bp2a")`.
|
||||
- `build/release/flag_values/bp2a/RELEASE_PLATFORM_SECURITY_PATCH.textproto`
|
||||
contiene `2025-08-05`.
|
||||
- Los dos scripts nuevos del 26 de septiembre, `009-bisect-dmesg-only.sh`
|
||||
y `009-bisect-slab-only.sh`, también fuerzan **bp2a en la línea 32**.
|
||||
No se han detenido ni modificado sus procesos desde esta auditoría.
|
||||
|
||||
**Defecto demostrado:** los experimentos denominados «solo una/dos opciones»
|
||||
cambian también la release Android y metadatos de seguridad del boot.
|
||||
Que GOODMAKE arranque no valida la equivalencia del entorno que los recompila.
|
||||
|
||||
**Hipótesis causal prioritaria, aún no confirmada en LAB:** el retroceso del
|
||||
nivel de parche o su inconsistencia con el sistema instalado puede interferir
|
||||
con Keymaster y las claves necesarias para montar datos. AOSP documenta
|
||||
[version binding](https://source.android.com/docs/security/features/keystore/version-binding):
|
||||
las claves están vinculadas a versiones/niveles de parche y no se pueden
|
||||
degradar libremente. Los flags AVB que desactivan verificación no constituyen
|
||||
una prueba de compatibilidad de esas claves. Falta traza o prueba controlada;
|
||||
no afirmar que esto explique también todos los OTA Stage1 anteriores.
|
||||
|
||||
**Corrección del experimento:** recuperar la release y metadatos efectivos
|
||||
del build bueno; verificar cabecera, propiedades y AVB del resultado antes de
|
||||
flashear. Cambiar simplemente a bp4a no basta como verificación: el archivo
|
||||
bp4a actual declara `2025-12-05`, mientras GOODMAKE declara `2026-09-01`, por
|
||||
lo que hay que localizar/reproducir sus overrides y no inventar una fecha.
|
||||
Usar salida aislada y empezar con un control recompilado sin hardening nuevo.
|
||||
No hacer factory reset como método de validación. Después aislar kernel y
|
||||
módulos sin variar simultáneamente ramdisk, release o metadatos.
|
||||
|
||||
## Historial aportado por el dueño después de la revisión
|
||||
|
||||
El 26 de septiembre el dueño aporta una conversación previa:
|
||||
|
||||
- «Tanto con uno como el otro» el teléfono reinicia en recovery y muestra
|
||||
«Try again / Factory data reset». El fragmento no identifica inequívocamente
|
||||
los dos archivos por nombre/hash; no asignar este resultado a mild.
|
||||
- Tras restaurar el boot GOOD de `20260918T143547Z`, confirma «estoy en el
|
||||
sistema». No se relata un borrado de datos. Es evidencia de recuperación
|
||||
con el boot conocido, no una prueba de corrupción permanente de `/data`.
|
||||
- El agente anterior informa ADB `unauthorized` en recovery; después, ya en
|
||||
sistema, informa ausencia de `su`, depuración root desactivada y ningún log
|
||||
útil obtenido. No hay salidas originales que permitan verificar qué rutas
|
||||
pudo leer: «no pude obtener evidencia» no equivale a «no se generó evidencia».
|
||||
- La conversación termina proponiendo mild como prueba pendiente. No aporta
|
||||
una respuesta posterior que confirme su ejecución ni su resultado.
|
||||
|
||||
Este historial matiza el registro «nunca recovery/Android»: al menos en los
|
||||
intentos relatados sí se llega a recovery tras el fallo. No demuestra que el
|
||||
kernel del arranque normal alcanzara una fase concreta, porque recovery es
|
||||
un arranque posterior. Preparar acceso diagnóstico en el sistema GOOD antes
|
||||
de otro ensayo, sin completar Magisk únicamente para obtener logs ni mezclar
|
||||
su activación con el cambio de kernel. No interpretar el menú de recovery
|
||||
como una indicación de que sea necesario hacer factory reset.
|
||||
|
||||
## 1. Imagen antigua dentro del ensayo nuevo (confirmado por SHA-256)
|
||||
|
||||
Raíz de artefactos remota: `/srv/rom/artifacts/009-axp-los23-port/`.
|
||||
|
||||
Estos dos archivos tienen el mismo SHA-256, recalculado el 26 de septiembre:
|
||||
|
||||
- `20260921T185024Z-bisect-defconfig-only/boot.img`
|
||||
- `20260918T231654Z-axp-kh-full/boot.img`
|
||||
|
||||
SHA-256: `3715f9f20c8823e5a23323792600b5d76d9f25e73eed3492c28f457a751d3c51`.
|
||||
|
||||
El script remoto `scripts/009-bisect-defconfig-only.sh` ejecuta `mka bootimage`
|
||||
y luego busca el primer `target_files_intermediates/.../IMAGES/boot.img`.
|
||||
Ese segundo archivo pertenece al empaquetado anterior: el ensayo termina
|
||||
conteniendo dos imágenes con kernels distintos.
|
||||
|
||||
El `boot-make.img` del ensayo tiene SHA-256 registrado
|
||||
`f52405c6b39a14d3357efd59441c9a28128bbce982186b1d86c71b01da8846b1`.
|
||||
El README sí indica usar ese archivo. No he encontrado en lo revisado un
|
||||
registro de flasheo con hash que permita confirmar cuál se probó. Por tanto,
|
||||
la identidad equivocada está demostrada; que se flashease la imagen equivocada,
|
||||
no. El script posterior `009-bisect-defconfig-mild.sh` ya evita esta copia.
|
||||
|
||||
## 2. «Solo defconfig» también cambia código de FORTIFY (confirmado)
|
||||
|
||||
El mismo script añade a `lib/string.c` definiciones exportadas de
|
||||
`__read_overflow`, `__read_overflow2`, `__read_overflow3` y `__write_overflow`,
|
||||
todas con cuerpo `BUG()`. El log
|
||||
`/srv/rom/artifacts/detach-009-bisect-dc-20260921T180802Z.log` confirma
|
||||
`added fortify stubs`.
|
||||
|
||||
En las fuentes LOS inspeccionadas, `include/linux/string.h:241` y siguientes
|
||||
declaran los helpers de lectura con `__compiletime_error`. Proporcionarles
|
||||
un cuerpo permite resolver símbolos que impedían enlazar, pero no demuestra
|
||||
que las llamadas sean correctas ni que no se ejecuten. Si se alcanza uno de
|
||||
esos cuerpos se ejecuta `BUG()`. Falta investigar los sitios de llamada y su
|
||||
relación con Clang/LTO; no atribuir el bootloop a ellos sin traza.
|
||||
|
||||
La conclusión previa «defconfig extras alone are enough to kill boot» es
|
||||
demasiado fuerte: el ensayo incluye cambios C, varias opciones simultáneas y
|
||||
la ambigüedad de imágenes anterior. Además cambia `SLAB_HARDENED` de Stage1
|
||||
por `SLAB_FREELIST_HARDENED`, por lo que tampoco reproduce exactamente su config.
|
||||
|
||||
## 3. Se avanzó de etapa sin validar arranque (confirmado documentalmente)
|
||||
|
||||
`docs/009-kernel-hardening-map.md` ordena diferir los CVE hasta que Stage1
|
||||
arranque, pero registra tres builds el 18 de septiembre: Stage1, Stage1 con
|
||||
unos 500 CVE, y hardening ampliado. Los tres fallaron en LAB según el registro
|
||||
del 21. Compilar correctamente no cumplía esa condición.
|
||||
|
||||
Stage1 ya agrupaba 30 parches y varias opciones; también se documentan restos
|
||||
de modificaciones SusFS en el árbol inicial. El script de bisect posterior
|
||||
sí limpia las fuentes hasta `28f9290ae067`; no confundir ambos estados.
|
||||
|
||||
## 4. Aplicación de parches y reparaciones no reproducibles
|
||||
|
||||
El `apply_stage1.sh` local usa `patch --batch` sin exigir fuzz cero. Ya existe
|
||||
un caso documentado de aplicación en la función equivocada: `slab/0014` entró
|
||||
en `is_root_cache` en vez de `slab_equal_or_root`.
|
||||
|
||||
El listado sigue incluyendo ese parche. Las correcciones de slab y FORTIFY
|
||||
se describen en `BUILD-FIXES.md`, pero no están implementadas por el aplicador
|
||||
local. Ejecutar la receta publicada no reproduce por sí solo el árbol corregido.
|
||||
|
||||
Otros defectos visibles del aplicador:
|
||||
|
||||
- Si falta un archivo, incrementa `fail` y continúa; al acabar puede devolver
|
||||
éxito porque el último comando es `echo`.
|
||||
- Ante fallo elimina `.rej` y `.orig`, perdiendo evidencia; no revierte los
|
||||
hunks que se hayan aplicado antes del fallo.
|
||||
- `--dry-run` prueba cada parche sobre el mismo árbol sin aplicar sus
|
||||
predecesores: no valida fielmente una serie con dependencias.
|
||||
|
||||
En el servidor, `scripts/009-cve-compile-fix.sh` intenta seleccionar parches
|
||||
para excluir por tokens extraídos del mensaje del compilador y registra el
|
||||
código de salida de su reversión sin exigir que sea cero. Esto no verifica
|
||||
dependencias ni garantiza que el árbol coincida con la denylist. Son defectos
|
||||
del método; esta revisión no establece qué rondas concretas los ejercitaron.
|
||||
|
||||
## 5. Kernel y módulos: compatibilidad pendiente de demostrar
|
||||
|
||||
Los dos scripts de bisect generan y guardan únicamente imágenes de arranque;
|
||||
sus instrucciones reutilizan la ROM `20260918T143547Z-axp-full` instalada.
|
||||
No guardan ni indican desplegar un conjunto correspondiente de módulos vendor.
|
||||
|
||||
El código actual `include/linux/slub_def.h:120` añade el campo `random` a
|
||||
`struct kmem_cache` bajo `CONFIG_SLAB_FREELIST_HARDENED`. La `.config` generada
|
||||
actual contiene esa opción y `CONFIG_MODVERSIONS=y`.
|
||||
|
||||
Esto justifica comprobar ABI/CRC de los módulos realmente cargados y los que
|
||||
van en el ramdisk/vendor antes de interpretar un ensayo de solo boot. No prueba
|
||||
por sí solo incompatibilidad ni explica necesariamente los primeros tres OTA.
|
||||
La misma precaución ya consta en `docs/007-susfs-source-audit.md`.
|
||||
|
||||
## 6. Faltan observabilidad y continuidad entre sesiones
|
||||
|
||||
El logo de Google no identifica por sí solo la fase exacta del bloqueo.
|
||||
El pstore vacío tampoco demuestra que no hubiera traza: la auditoría de `007`
|
||||
documenta un error de descifrado de ramoops en LAB. Es evidencia histórica;
|
||||
no se ha vuelto a medir el estado actual del teléfono en esta revisión.
|
||||
|
||||
El mapa local acaba proponiendo el ensayo mild, pero este ya fue compilado:
|
||||
|
||||
- Artefacto: `20260921T192533Z-bisect-defconfig-mild/boot-make.img`.
|
||||
- SHA-256 registrado en su log:
|
||||
`6ed0351edb762bdf4bfe2dd96d7e4e2fa43ccf0ad497d7fce35ab88cd722f4f2`.
|
||||
- Estado del proceso: `exit=0`, finalizado el 21 a las 19:25:33 UTC.
|
||||
- Resultado de arranque: **no encontrado en los registros revisados**.
|
||||
- Árbol remoto actual: HEAD `28f9290ae067d3e7857126eb6312720dbe9c7c80`;
|
||||
único archivo modificado según Git: `sunfish_defconfig`, con KSU desactivado,
|
||||
`SECURITY_DMESG_RESTRICT=y` y `SLAB_FREELIST_HARDENED=y`.
|
||||
- `.config` actual: FORTIFY e INIT_ON_ALLOC/FREE desactivados. No sustituye
|
||||
a una configuración archivada de cada build anterior.
|
||||
|
||||
## Punto de reanudación propuesto
|
||||
|
||||
1. Conservar como referencia el build `20260918T143547Z-axp-full`, cuyo
|
||||
arranque está confirmado por el dueño en el mapa. Identificar por hash el
|
||||
boot realmente probado en cada bisect y aclarar el resultado de mild.
|
||||
2. Reproducir un control sin hardening nuevo con fuentes, herramienta de
|
||||
compilación, salida aislada y módulos identificados. Validar arranque en LAB.
|
||||
3. Separar las variables: una opción por ensayo. Tratar FORTIFY más sus
|
||||
modificaciones C como una investigación propia; no ocultar errores de enlace
|
||||
bajo la etiqueta «solo config».
|
||||
4. Para cambios que afecten ABI, comprobar o desplegar un conjunto compatible
|
||||
de kernel y módulos. Registrar slot, particiones, hashes y resultado.
|
||||
5. Recuperar diagnóstico del fallo antes de atribuirlo a un subsistema.
|
||||
No borrar datos, alternar slots o añadir parches como sustituto de evidencia.
|
||||
6. Congelar cada estado probado: revisión y diff de fuentes, parches y sus
|
||||
hashes, `.config` efectiva, compilador, imágenes/módulos, log y resultado.
|
||||
No avanzar a CVE ni deblob hasta aceptar la etapa anterior.
|
||||
|
||||
Deblob no es una causa demostrada en estos ensayos: el registro de `009`
|
||||
lo declara pendiente, y la retirada de IPA se omitió expresamente. No se ha
|
||||
realizado aquí una auditoría exhaustiva del contenido de todos los payloads.
|
||||
@@ -0,0 +1,125 @@
|
||||
Comparación directa de imágenes — 2026-09-26
|
||||
GOODMAKE: .local-artifacts/009-flash-20260918T143547Z/boot-make.img
|
||||
MILD: rom-dev01:/srv/rom/artifacts/009-axp-los23-port/20260921T192533Z-bisect-defconfig-mild/boot-make.img
|
||||
|
||||
good: SHA256=fcc52ec5c7c077def20ce9d9b9ac3782475e0834817f453e845eb2c1e66d1255
|
||||
header patch level: 2026-09
|
||||
ro.build.version.sdk_full=36.1
|
||||
ro.build.version.security_patch=2026-09-01
|
||||
ro.build.version.sdk_full=36.1
|
||||
ro.build.version.security_patch=2026-09-01
|
||||
kernel: SHA256=5db3af0d7eb76dcd26d7fdbe7dad554d7493073bfa3495f1b49c1aa323ad6b4f
|
||||
ramdisk.cpio: SHA256=a2e412792fa236a1db3416b6bf7ed374e606f88c714339319759b04f84d90067
|
||||
dtb: SHA256=2fca15709ff6d9f48fea938952439e8d00c2b998c73e7a216172ae3965b07566
|
||||
|
||||
mild: SHA256=6ed0351edb762bdf4bfe2dd96d7e4e2fa43ccf0ad497d7fce35ab88cd722f4f2
|
||||
header patch level: 2025-08
|
||||
ro.build.version.sdk_full=36.0
|
||||
ro.build.version.security_patch=2025-08-05
|
||||
ro.build.version.sdk_full=36.0
|
||||
ro.build.version.security_patch=2025-08-05
|
||||
kernel: SHA256=c7829fa4751643067da5ca6e726d402771c781cfc10771201ab989d73a10cdf8
|
||||
ramdisk.cpio: SHA256=17d51096168cffb1bb0d93682045203d50e3fc00783f4339e4b79adf0785b3eb
|
||||
dtb: SHA256=2fca15709ff6d9f48fea938952439e8d00c2b998c73e7a216172ae3965b07566
|
||||
|
||||
Configuración extraída de IKCONFIG de cada kernel:
|
||||
--- GOODMAKE.config
|
||||
+++ MILD.config
|
||||
@@ -243,7 +243,7 @@
|
||||
# CONFIG_SLOB is not set
|
||||
CONFIG_SLAB_MERGE_DEFAULT=y
|
||||
# CONFIG_SLAB_FREELIST_RANDOM is not set
|
||||
-# CONFIG_SLAB_FREELIST_HARDENED is not set
|
||||
+CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
CONFIG_SLUB_CPU_PARTIAL=y
|
||||
CONFIG_SYSTEM_DATA_VERIFICATION=y
|
||||
CONFIG_PROFILING=y
|
||||
@@ -2282,12 +2282,7 @@
|
||||
# Character devices
|
||||
#
|
||||
CONFIG_TTY=y
|
||||
-CONFIG_VT=y
|
||||
-CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
-CONFIG_VT_CONSOLE=y
|
||||
-CONFIG_VT_CONSOLE_SLEEP=y
|
||||
-CONFIG_HW_CONSOLE=y
|
||||
-CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
+# CONFIG_VT is not set
|
||||
CONFIG_UNIX98_PTYS=y
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_SERIAL_NONSTANDARD is not set
|
||||
@@ -3564,16 +3559,6 @@
|
||||
# CONFIG_BACKLIGHT_ARCXCNN is not set
|
||||
# CONFIG_VGASTATE is not set
|
||||
CONFIG_HDMI=y
|
||||
-
|
||||
-#
|
||||
-# Console display driver support
|
||||
-#
|
||||
-CONFIG_DUMMY_CONSOLE=y
|
||||
-CONFIG_DUMMY_CONSOLE_COLUMNS=80
|
||||
-CONFIG_DUMMY_CONSOLE_ROWS=25
|
||||
-CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
|
||||
-CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||
CONFIG_LOGO=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
@@ -4493,7 +4478,6 @@
|
||||
#
|
||||
# Speakup console speech
|
||||
#
|
||||
-# CONFIG_SPEAKUP is not set
|
||||
# CONFIG_STAGING_MEDIA is not set
|
||||
|
||||
#
|
||||
@@ -4780,7 +4764,7 @@
|
||||
CONFIG_QCOM_MEMORY_DUMP_V2=y
|
||||
# CONFIG_MSM_DEBUG_LAR_UNLOCK is not set
|
||||
CONFIG_QCOM_WATCHDOG_V2=y
|
||||
-# CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC is not set
|
||||
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
|
||||
CONFIG_QCOM_WDOG_IPI_ENABLE=y
|
||||
CONFIG_QCOM_SMEM_STATE=y
|
||||
CONFIG_QCOM_SMP2P=y
|
||||
@@ -5331,11 +5315,6 @@
|
||||
CONFIG_ESOC_MDM_DRV=y
|
||||
CONFIG_ESOC_MDM_DBG_ENG=y
|
||||
# CONFIG_MDM_DBG_REQ_ENG is not set
|
||||
-
|
||||
-#
|
||||
-# KernelSU
|
||||
-#
|
||||
-# CONFIG_KSU is not set
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
@@ -5651,7 +5630,7 @@
|
||||
# CONFIG_PANIC_ON_OOPS is not set
|
||||
CONFIG_PANIC_ON_OOPS_VALUE=0
|
||||
# CONFIG_PANIC_ON_WARN_DEFAULT_ENABLE is not set
|
||||
-CONFIG_PANIC_TIMEOUT=0
|
||||
+CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_SCHED_DEBUG=y
|
||||
CONFIG_SCHED_INFO=y
|
||||
# CONFIG_PANIC_ON_SCHED_BUG is not set
|
||||
@@ -5830,7 +5809,7 @@
|
||||
# CONFIG_PFT is not set
|
||||
CONFIG_PFK=y
|
||||
# CONFIG_PFK_WRAPPED_KEY_SUPPORTED is not set
|
||||
-# CONFIG_SECURITY_DMESG_RESTRICT is not set
|
||||
+CONFIG_SECURITY_DMESG_RESTRICT=y
|
||||
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
|
||||
CONFIG_SECURITY=y
|
||||
# CONFIG_SECURITY_WRITABLE_HOOKS is not set
|
||||
@@ -6139,10 +6118,6 @@
|
||||
CONFIG_MPILIB=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_OID_REGISTRY=y
|
||||
-CONFIG_FONT_SUPPORT=y
|
||||
-# CONFIG_FONTS is not set
|
||||
-CONFIG_FONT_8x8=y
|
||||
-CONFIG_FONT_8x16=y
|
||||
# CONFIG_SG_SPLIT is not set
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
@@ -0,0 +1,267 @@
|
||||
# 009 kernel hardening map (FR-017)
|
||||
|
||||
> **Priority finding, 2026-09-26:** Bisect scripts (including the new dmesg-only
|
||||
> and slab-only scripts) force **bp2a**, whereas the GOOD build used **bp4a**.
|
||||
> Direct image comparison finds GOODMAKE security patch 2026-09 / SDK 36.1
|
||||
> versus mild 2025-08 / SDK 36.0. GOODMAKE boots according to the owner.
|
||||
> These are not isolated defconfig trials; see the audit below before testing.
|
||||
|
||||
> **Audit 2026-09-26:** Before resuming builds, read
|
||||
> [the boot investigation](009-kernel-boot-audit-20260926.md).
|
||||
> The defconfig-only experiment also added FORTIFY C stubs and its `boot.img`
|
||||
> is byte-identical to the older full-hardening image; only `boot-make.img`
|
||||
> represents the new build. Its reported boot failure does not yet isolate
|
||||
> configuration alone. The later mild build already exists; its LAB boot
|
||||
> result was not found in the reviewed records.
|
||||
> Subsequent owner-provided history reports failed attempts rebooting into
|
||||
> recovery (Try again / Factory data reset), followed by successful system
|
||||
> boot after restoring GOOD. Thus "never recovery" below is not a universal
|
||||
> description. That history still presents mild as pending; see the audit.
|
||||
|
||||
**Base**: LineageOS 23.2 `sunfish` / `kernel/google/msm-4.14` (non-GKI).
|
||||
**Not base**: GrapheneOS A13 sunfish tree, random prebuilts, KernelSU.
|
||||
|
||||
## Inventory (2026-09-18, `rom-dev01`)
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| LOS tree | `/srv/rom/src/lineage/kernel/google/msm-4.14` |
|
||||
| LOS rev | `28f9290ae067` — *Revert "BACKPORT: module: Do not offer sha224…"* |
|
||||
| Version | `4.14.357-openela` |
|
||||
| AXP stack | `/srv/rom/references/axp/kernel_patches` @ `df3cab2155b3` (codeberg mirror) |
|
||||
| Dry-run worktree | `/srv/rom/artifacts/009-axp-los23-port/kernel-harden-dryrun/` |
|
||||
| Iodé manifest | `/srv/rom/references/iode/android-manifest` (`v5-staging`) |
|
||||
|
||||
### LOS `sunfish_defconfig` already on
|
||||
|
||||
`CFI_CLANG`, `SHADOW_CALL_STACK`, `CC_STACKPROTECTOR_STRONG`, `RANDOMIZE_BASE`,
|
||||
`ARM64_SW_TTBR0_PAN`, `SECURITY_PERF_EVENTS_RESTRICT`, `HARDENED_USERCOPY`(+PAGESPAN),
|
||||
`BUG_ON_DATA_CORRUPTION`, `SCHED_STACK_END_CHECK`, `# CONFIG_DEVMEM is not set`,
|
||||
`BPF_JIT_ALWAYS_ON`.
|
||||
`# CONFIG_UNMAP_KERNEL_AT_EL0 is not set` (kept as LOS).
|
||||
|
||||
### LOS defconfig gaps (vs typical Graphene/AH)
|
||||
|
||||
Not set in `sunfish_defconfig` (may need Kconfig + patches first):
|
||||
`FORTIFY_SOURCE`, `INIT_ON_ALLOC_DEFAULT_ON`, `INIT_ON_FREE_DEFAULT_ON`,
|
||||
`SLAB_FREELIST_RANDOM`, `SLAB_FREELIST_HARDENED`, `SHUFFLE_PAGE_ALLOCATOR`,
|
||||
`PAGE_POISONING`, `SECURITY_DMESG_RESTRICT`, `DEBUG_LIST`, `REFCOUNT_FULL`.
|
||||
|
||||
### AXP `kernel_patches` shape
|
||||
|
||||
| Series | 4.14 patches | Role |
|
||||
|--------|-------------:|------|
|
||||
| `0001-LinuxIncrementals` | 335 | Version bumps — **skip** (tree already 4.14.357-openela) |
|
||||
| `0004`–`0006`, `0008-*`, `0009` | ~40 Graphene/AH | Stage-1 candidates (below) |
|
||||
| `CVE-*` dirs | ~2301 with 4.14 | Mega CVE stage — **later**, after Stage 1 boots |
|
||||
| Location-related | — | **Skip** (FR-018 policy) |
|
||||
|
||||
### IodéOS
|
||||
|
||||
`v5-staging` manifest cloned; **no** `sunfish` / `msm-4.14` kernel project in
|
||||
snippets. Public gitlab device/kernel repos need auth. Treat Iodé as
|
||||
**userspace privacy** for this device; no extra 4.14 kernel delta found.
|
||||
|
||||
## Source priority (owner 2026-09-18)
|
||||
|
||||
| Priority | Source | Role |
|
||||
|----------|--------|------|
|
||||
| 1 | **AXP** sunfish kernel / build patches | Clone first (max) |
|
||||
| 2 | **LOS 23.2** msm-4.14 as shipped | Inventory; skip dupes |
|
||||
| 3 | **IodéOS** (LOS fork) | Diff for extra 4.14-safe hardening/deblob |
|
||||
| 4 | **GrapheneOS** | Optional: modern techniques / docs; A13 sunfish only if clearly useful |
|
||||
| — | **DivestOS** standalone | **Do not hunt** (EOL). AXP-inherited commits OK via AXP clone |
|
||||
|
||||
## Location policy
|
||||
|
||||
**Do not** extra-cap location vs LOS defaults (FR-018). Skip AXP location
|
||||
lockdown patches; document as skipped. Goal: **precise, fast GPS** like
|
||||
stock LOS 23.2 — not AXP privacy lockdown. Deblob/CVE stages must not
|
||||
reintroduce location hardening by accident.
|
||||
|
||||
## Sequential apply probe (Graphene/AH only)
|
||||
|
||||
Clean worktree @ `28f9290ae067`, patches from AXP `kernel_patches` in Divest-like
|
||||
order (`4.14` then `ANY`). Result: **OK=30, SKIP_ALREADY=4, FAIL=12**.
|
||||
|
||||
Full machine log:
|
||||
`/srv/rom/artifacts/009-axp-los23-port/kernel-harden-dryrun/apply-sequential-summary.txt`
|
||||
|
||||
## Patch ledger
|
||||
|
||||
| id | title | source | AXP? | 4.14-safe? | decision | notes |
|
||||
|----|-------|--------|------|------------|----------|-------|
|
||||
| KH-INC | LinuxIncrementals 4.14 (335) | AXP `0001` @ df3cab215 | Y | n/a | **skip** | Already 4.14.357-openela |
|
||||
| KH-004 | Perf events restrict | AXP `0004` ANY/0001 | Y | Y | **skip** | Already in LOS (`SKIP_ALREADY` + defconfig) |
|
||||
| KH-005 | Deny USB (toggle) | AXP `0005-Graphene-Deny_USB` 4.14/0003 | Y | Y | **stage1 apply** | Clean apply |
|
||||
| KH-006 | wcnss buffer fixes | AXP `0006` ANY/0001–0003 | Y | ? | **skip/port later** | Wrong path on this tree (`can't find file`) |
|
||||
| KH-008-as | alloc_size attrs | AXP `0008-…-allocsize` | Y | Y | **stage1 apply** | OK: 0002,0011,0016,0021; FAIL: 0007 (vmalloc.h hunk) |
|
||||
| KH-008-bug | ksize BUG_ON | AXP `0008-…-bugon` 0010 | Y | Y | **stage1 apply** | OK |
|
||||
| KH-008-fort | FORTIFY intra-object | AXP `0008-…-fortify` 0004 | Y | Y | **stage1 apply** | OK; then enable `CONFIG_FORTIFY_SOURCE` |
|
||||
| KH-008-misc | misc Graphene | AXP `0008-…-misc` | Y | Y | **stage1 apply** | OK 0001,0005,0010,0018; SKIP 0021 + ANY/0015 |
|
||||
| KH-008-rnd | brk/arg randomize | AXP `0008-…-random` | Y | Y | **stage1 apply** | All 4 OK when sequential |
|
||||
| KH-008-ro | __ro_after_init / sysctl RO | AXP `0008-…-ro` | Y | partial | **stage1 apply** | OK most; FAIL 0007, 0034 (sysctl drift) |
|
||||
| KH-008-san | page/slab sanitize | AXP `0008-…-sanitize` | Y | Y | **stage1 apply** | All 4 OK sequential |
|
||||
| KH-008-slab | SLAB_HARDENED | AXP `0008-…-slab` | Y | partial | **stage1 apply** | OK 0006,0014; FAIL 0010,0018 |
|
||||
| KH-008-un | unused-fn noise | AXP `0008-…-unused` | Y | Y | **stage1 apply** | OK (build hygiene) |
|
||||
| KH-009 | rfc4941bis IPv6 | AXP `0009` | Y | partial | **skip** | 4.14/0003 already present; ANY/* fail |
|
||||
| KH-CVE | CVE clean-offset 429 + denylist | AXP `CVE-*` | Y | LAB OK `#47` | **ship partial** | `cve-clean-offset.list` (ex-430−49980); high-offset ≥200 quarantined; `CVE-2022-49980` denylist (udc_lock); see `009-cve-bisect-plan.md` / `009-axp-graphene-remaining.md` |
|
||||
| KH-LOC | AXP location lockdown | AXP | Y | — | **skip** | FR-018 |
|
||||
| KH-IODE | Iodé kernel delta | Iodé | — | — | **skip** | No sunfish 4.14 fork found |
|
||||
| KH-CFG | Hardening defconfig | LOS+AXP | — | Y | **stage1 after patches** | Flip gaps that Kconfig allows post-patch |
|
||||
| KH-US-S5-1 | Yama + SLAB_FREELIST_RANDOM | Graphene/AXP class | Y | Y | **apply** | `apply_uss5_1_defconfig.sh`; LSM already listed yama |
|
||||
|
||||
### Stage 1 apply list (exact files)
|
||||
|
||||
From host `$KP=/srv/rom/references/axp/kernel_patches` — **only** these (order
|
||||
matters):
|
||||
|
||||
```
|
||||
0005-Graphene-Deny_USB/4.14/0003.patch
|
||||
0008-Graphene-Kernel_Hardening-allocsize/4.14/0002.patch
|
||||
0008-Graphene-Kernel_Hardening-allocsize/4.14/0011.patch
|
||||
0008-Graphene-Kernel_Hardening-allocsize/4.14/0016.patch
|
||||
0008-Graphene-Kernel_Hardening-allocsize/4.14/0021.patch
|
||||
0008-Graphene-Kernel_Hardening-bugon/4.14/0010.patch
|
||||
0008-Graphene-Kernel_Hardening-fortify/4.14/0004.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0001.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0005.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0010.patch
|
||||
0008-Graphene-Kernel_Hardening-misc/4.14/0018.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0002.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0007.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0012.patch
|
||||
0008-Graphene-Kernel_Hardening-random/4.14/0017.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0002.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0012.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0017.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0028.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0030.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0032.patch
|
||||
0008-Graphene-Kernel_Hardening-ro/4.14/0038.patch
|
||||
0008-Graphene-Kernel_Hardening-sanitize/4.14/0005.patch
|
||||
0008-Graphene-Kernel_Hardening-sanitize/4.14/0009.patch
|
||||
0008-Graphene-Kernel_Hardening-sanitize/4.14/0015.patch
|
||||
0008-Graphene-Kernel_Hardening-sanitize/4.14/0017.patch
|
||||
0008-Graphene-Kernel_Hardening-slab/4.14/0006.patch
|
||||
0008-Graphene-Kernel_Hardening-slab/4.14/0014.patch
|
||||
0008-Graphene-Kernel_Hardening-unused/4.14/0001.patch
|
||||
0008-Graphene-Kernel_Hardening-unused/4.14/0002.patch
|
||||
```
|
||||
|
||||
Then defconfig (only options that exist after patches): at least
|
||||
`CONFIG_FORTIFY_SOURCE=y`; evaluate `INIT_ON_*` / slab freelist / dmesg restrict
|
||||
against Kconfig `depends on` before flipping.
|
||||
|
||||
## Applied / skipped summary
|
||||
|
||||
- **Applied (2026-09-18, live tree):** Stage 1 — 30 AXP Graphene/AH patches via
|
||||
`vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1.sh` onto
|
||||
`/srv/rom/src/lineage/kernel/google/msm-4.14` (Stage1 alone ~28 paths;
|
||||
tree also had prior Magisk-track dirt: KSU/SusFS `# CONFIG_* is not set`
|
||||
stubs + residual SusFS-touched fs/overlayfs etc. — not Stage1).
|
||||
- **Defconfig (same day):** `CONFIG_FORTIFY_SOURCE=y`,
|
||||
`CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y`, `CONFIG_INIT_ON_FREE_DEFAULT_ON=y`,
|
||||
`CONFIG_SECURITY_DMESG_RESTRICT=y`, `CONFIG_SLAB_HARDENED=y`.
|
||||
- Skipped: location lockdown (policy); Divest-as-hunt (policy); LinuxIncrementals;
|
||||
KH-004 (already present); KH-006 wcnss (path miss); KH-009 ANY; Iodé kernel
|
||||
(none found); CVE mega (in progress via `cve_checker`)
|
||||
- Failed probe (port later): allocsize/0007, ro/0007+0034, slab/0010+0018
|
||||
- **Build fix 2026-09-18:** Stage1 `slab/0014` misfuzzed into `is_root_cache`
|
||||
(`return p == s` with no `p`) — reverted that stub. Intent was
|
||||
`slab_equal_or_root`; LOS already has `return s == p` there.
|
||||
- **Build fix 2026-09-18b:** `CONFIG_FORTIFY_SOURCE=y` + Clang LTO left
|
||||
`__read_overflow*` undefined in modules (qcacld/techpack) — added `BUG()`
|
||||
stubs + `EXPORT_SYMBOL` in `lib/string.c`.
|
||||
- **Bacon OK (Stage1 only):**
|
||||
`/srv/rom/artifacts/009-axp-los23-port/20260918T180359Z-axp-kh-stage1/`
|
||||
- **CVE bacon OK:**
|
||||
`/srv/rom/artifacts/009-axp-los23-port/20260918T215034Z-axp-kh-cve/`
|
||||
Stage1 + ~500 CVE patches that compile. ~34 incomplete series on denylist
|
||||
(`cve-stage/denylist.txt`) — skipped, not silently dropped without a log.
|
||||
Magisk preroot present; KernelSU absent.
|
||||
- **More complete bacon OK:**
|
||||
`/srv/rom/artifacts/009-axp-los23-port/20260918T231654Z-axp-kh-full/`
|
||||
AXP `hardenDefconfig` on the CVE tree (only options this Kconfig has).
|
||||
Left on: `IO_URING`, `USERFAULTFD`, WireGuard, IPA. Magisk preroot OK.
|
||||
- **Not done:** userspace Deblob.sh (Widevine/IMS/CNE). Kernel deblob in AXP
|
||||
is mostly IPA removal — skipped so mobile data keeps working.
|
||||
- **Flash target (LAB 2026-09-21):** back on
|
||||
`20260918T143547Z-axp-full` (pre-kernel-hardening). Owner confirmed boot OK.
|
||||
- **Boot-fail (LAB 2026-09-21):** all three KH artifacts hang at Google logo
|
||||
(bootloader splash, never recovery/Android):
|
||||
- `231654Z-axp-kh-full`, `215034Z-axp-kh-cve`, `180359Z-axp-kh-stage1`
|
||||
- Stage1 **`boot-make.img` (no Magisk)** also hangs → kernel Stage1 (+
|
||||
Stage1 defconfig extras), not Magisk packaging.
|
||||
- OTA `payload` boot == Magisk artifact boot; OTA `dtbo` identical across
|
||||
good vs Stage1. Loose `dtbo.img`/`vbmeta.img` in artifact dirs ≠ payload
|
||||
(do not flash those sueltos). Embedded boot `dtb` identical all four.
|
||||
- `/sys/fs/pstore` empty after failed boots (no ramoops).
|
||||
- **Bisect 2026-09-21:** `20260921T185024Z-bisect-defconfig-only`
|
||||
(clean LOS + FORTIFY/INIT_ON_*/DMESG/SLAB_FREELIST_HARDENED, no Graphene
|
||||
patches) → LAB **bootloop** / try-again recovery.
|
||||
- **LAB 2026-09-28:** Clang FORTIFY nested-`strlen` fix (`strlcpy`/`strcpy` →
|
||||
`__underlying_strlen`). Family `full` + **combo4+FORTIFY** boot. Magisk bacon:
|
||||
`apply_combo4_fortify.sh` / `009-bacon-axp-combo4-fortify.sh`.
|
||||
- **LAB 2026-09-29 (ship kernel pack):** Stage1 (30) + combo4 + Clang FORTIFY
|
||||
Magisk bacon `20260929T123401Z-axp-stage1-combo4` — boots, Wi‑Fi CRC OK,
|
||||
Deny USB sysctl present. Attribution: `docs/009-gate-g-kernel-attribution.md`.
|
||||
Apply: `apply_stage1_combo4.sh`. Bacon: `009-bacon-axp-stage1-combo4.sh`.
|
||||
- **CVE re-try 2026-09-29:** full `cve-strict` (503) = LAB Google logo hang.
|
||||
Bisect: `docs/009-cve-bisect-plan.md` (`cve-bisect-h1/h2.list`).
|
||||
- **Bisect 2026-09-21 mild:** `DMESG_RESTRICT` + `SLAB_FREELIST_HARDENED`
|
||||
only → same failure.
|
||||
- **Control 2026-09-26:** `20260918T143547Z` **boot-make.img** (no Magisk,
|
||||
no extra CONFIG) flashed onto Magisk system → **boots OK**.
|
||||
- **Audit 2026-09-26 (owner second opinion):** bisect scripts wrongly used
|
||||
`lunch …-bp2a-userdebug` while good bacon uses `breakfast` → `bp4a`.
|
||||
Mild/defconfig-only boots carry `security_patch=2025-08-05` / SDK 36.0 vs
|
||||
GOODMAKE `2026-09-01` / 36.1; ramdisk and other kernel options also differ.
|
||||
**Invalidates** “DMESG/SLAB alone kill boot”. bp2a one-config builds aborted.
|
||||
See `docs/009-kernel-boot-audit-20260926.md`.
|
||||
- **Control ksync 2026-09-26:** new breakfast/bp4a kernel (no Stage1 CONFIG)
|
||||
injected into GOODMAKE ramdisk → LAB **boots OK** (`20260926T161646Z-bisect-ksync-control`).
|
||||
Method validated. Next: same inject path, one CONFIG at a time (DMESG then SLAB).
|
||||
**Future tests:** always `breakfast`/bp4a + inject kernel into GOODMAKE ramdisk;
|
||||
never bp2a-only bootimage as a “config” experiment. Lessons also in agent
|
||||
personal store `009-kernel-bisect-lessons.md`.
|
||||
Deblob still deferred (GPS: no AXP location lockdown).
|
||||
|
||||
## CVE / hardening / deblob policy (owner 2026-09-18 evening)
|
||||
|
||||
- **Source of truth**: AXP method (`kernel_patches` + `cve_checker`), applied onto
|
||||
LOS23 `msm-4.14` — not inventing our own CVE hunt.
|
||||
- **Skip if already fixed** in LOS tree (patcher “already applied” / reverse
|
||||
hunks). LOS23 is newer than AXP22; many CVEs may already be present via
|
||||
`4.14.357-openela`. Hardening/deblob are where AXP usually still wins.
|
||||
- **Loose 4.19**: when enabled, the patcher may also try patches filed under
|
||||
`4.19/` (and with extreme matching, even `^5.x`/`^6.x`) on a `4.14` tree.
|
||||
First pass with loose ON applied ~185 non-4.14 patches and **broke the
|
||||
build** (incomplete binder/bpf/f2fs series). **OFF for CVE apply** (exact
|
||||
`4.14` + `ANY` only). Re-evaluate later if needed.
|
||||
- **On failure**: do not silent-drop — attempt fix / adapt / re-apply; only
|
||||
then document skip with reason (AXP `Fix_CVE_Patchers` style).
|
||||
- **Deblob**: AXP deblob pass after CVE/hardening inventory (separate from CVE
|
||||
IDs); Lineage rarely matches AXP here.
|
||||
- **Flash**: owner on return; agent does not need to flash for this phase.
|
||||
|
||||
## 2026 catalog refresh (started 2026-09-19)
|
||||
|
||||
CIP `kernel-sec` cloned at `/srv/rom/references/cip-kernel-sec` @ `025be706`
|
||||
(2026-09-19). Scrape vs AXP catalog `df3cab215` (2025-10-30): **7086** CVEs
|
||||
not in that list (6317× CVE-2026, 769× CVE-2025). **None** have a `4.14`
|
||||
backport link; one has `4.19`. The rest are mainline / 5.10+.
|
||||
|
||||
kernel.org `linux-stable` `v4.14.*` stops at **4.14.336**. Nothing newer to
|
||||
incremental-apply; the LOS tree is already `4.14.357-openela`.
|
||||
|
||||
Android bulletins (new URL `/docs/security/bulletin/YYYY/YYYY-MM-01`, which
|
||||
the jar scraper does not accept) have **no** `git.kernel.org` links. Kernel
|
||||
rows point at `android.googlesource.com/kernel/common`: 2025-12 (44),
|
||||
2026-03 (36), 2026-06 (2), 2026-09 (10). Links saved in
|
||||
`/srv/rom/artifacts/009-axp-los23-port/cve-2026/asb-links.txt`.
|
||||
|
||||
Download + checker (read-only on the live tree; does not reset the flashed
|
||||
kernel) is detached as tmux `009-cve-2026`. One mainline patch per new CVE
|
||||
lands in `/srv/rom/references/axp/kernel_patches_2026/`. Apply is **not**
|
||||
started: 2026 patches are 6.x and the last loose pass broke 4.14.
|
||||
@@ -0,0 +1,22 @@
|
||||
# LAB acceptance note — 20261002T103558Z (AVB infra ship)
|
||||
|
||||
Device: `11231JEC207477`
|
||||
Artifact: `20261002T103558Z-axp-stage1-combo4-cve-hi-releasekeys`
|
||||
Ship zip twin: `AXP-Resurection-Pro-23.2-20261002-sunfish.zip` (= lineage zip bytes)
|
||||
|
||||
|
||||
Owner smoke 2026-10-02: no errors reported after sideload + boot/vbmeta reinforce.
|
||||
|
||||
| Gate | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| A Boot/HW | pass (owner) | Boots home; Wi‑Fi/BT/call smoke OK per owner |
|
||||
| B Google stack | pass (prior+owner) | microG/Phonesky path unchanged this bacon |
|
||||
| C Toggles | pass (prior) | Spoof / call-rec not regressed this bacon |
|
||||
| D Magisk | pass | `magiskd` present; preroot; unlocked orange |
|
||||
| E Banking | deferred | Not MVP |
|
||||
| F Usability | pass (prior) | Bundled apps / WebView LOS |
|
||||
| G Hardening | partial | Release-keys + AVB **signing** infra (flags 3); US-S4 stage0 measure done; US-S4-1 code pending next content bacon |
|
||||
|
||||
`ro.lineage.version` on this flash is still `23.2-20261002-UNOFFICIAL-sunfish`
|
||||
(pre-branding.mk). Next content bacon picks up
|
||||
`…-UNOFFICIAL-AXP-Resurection-Pro-…`.
|
||||
@@ -0,0 +1,27 @@
|
||||
# LAB acceptance — 20261002T151944Z (US-S4-1 + Pro branding)
|
||||
|
||||
Device: `11231JEC207477`
|
||||
Artifact: `20261002T151944Z-axp-stage1-combo4-cve-hi-releasekeys`
|
||||
Ship: `AXP-Resurection-Pro-23.2-20261002-sunfish.zip`
|
||||
|
||||
Sideload + boot/vbmeta/dtbo reinforce 2026-10-02 evening. Owner/ChatGPT artifact
|
||||
gates + LAB post-boot checks below.
|
||||
|
||||
| Gate | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| A Boot/HW | pass | `sys.boot_completed=1`, slot `_a` |
|
||||
| B Google stack | pass (prior) | microG/Phonesky unchanged this bacon |
|
||||
| C Toggles | pass (prior) | Not regressed |
|
||||
| D Magisk | pass | `magiskd` pid present; TF Magisk boot reinforced |
|
||||
| E Banking | deferred | |
|
||||
| F Usability | pass (prior) | |
|
||||
| G Hardening | pass (this pack) | AVB **signing** infra flags=3; US-S4-1 OpenSSH/rsync/procmem absent; `init.openssh.rc` present (AXP) |
|
||||
|
||||
Props:
|
||||
- `ro.lineage.version=23.2-20261002-UNOFFICIAL-AXP-Resurection-Pro-sunfish`
|
||||
- `ro.axp.resurection.track=pro`
|
||||
- `ro.boot.flash.locked=0`
|
||||
- no `/product/bin/sshd`, no `/product/bin/rsync`
|
||||
- `/product/etc/init/init.openssh.rc` present
|
||||
|
||||
Prior AVB-only ship note: `docs/009-lab-acceptance-20261002-avb.md` (`103558Z`).
|
||||
@@ -0,0 +1,27 @@
|
||||
# LAB acceptance — 20261002T162840Z (US-S5-1 Yama + SLAB_FREELIST_RANDOM)
|
||||
|
||||
Device: `11231JEC207477`
|
||||
Artifact: `20261002T162840Z-axp-stage1-combo4-cve-hi-releasekeys`
|
||||
Ship: `AXP-Resurection-Pro-23.2-20261002-sunfish.zip`
|
||||
|
||||
Sideload Pro zip + reinforce Magisk `boot`/`dtbo`/`vbmeta`/`vbmeta_system` on
|
||||
active slot `_b` (2026-10-02 evening).
|
||||
|
||||
| Gate | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| A Boot/HW | pass | `sys.boot_completed=1`, slot `_b` |
|
||||
| B Google stack | pass (prior) | microG/Phonesky unchanged this bacon |
|
||||
| C Toggles | pass (prior) | Not regressed |
|
||||
| D Magisk | pass | `magiskd` present; TF Magisk boot reinforced |
|
||||
| E Banking | deferred | PIF/Vector BL spoof — owner config, not this pack |
|
||||
| F Usability | pass (prior) | |
|
||||
| G Hardening | pass (this pack) | US-S5-1: `CONFIG_SECURITY_YAMA=y`, `CONFIG_SLAB_FREELIST_RANDOM=y`, LSM lists `yama`; US-S4-1 OpenSSH still absent; `init.openssh.rc` present |
|
||||
|
||||
Props:
|
||||
- `ro.lineage.version=23.2-20261002-UNOFFICIAL-AXP-Resurection-Pro-sunfish`
|
||||
- `ro.axp.resurection.track=pro`
|
||||
- `ro.boot.flash.locked=0`, `verifiedbootstate=orange`
|
||||
- `/proc/config.gz`: YAMA + SLAB_FREELIST_RANDOM + `LSM=…,yama,…`
|
||||
|
||||
Recover baseline: `20261002T085915Z-axp-stage1-combo4-cve-hi-releasekeys` (README).
|
||||
Prior US-S4 LAB: `docs/009-lab-acceptance-20261002-uss4.md` (`151944Z`).
|
||||
@@ -0,0 +1,22 @@
|
||||
# 009 localization / location: AXP vs LOS (deferred — FR-018)
|
||||
|
||||
**Status**: Look later — **not** an MVP acceptance gate.
|
||||
|
||||
Owner note (2026-09-17): AXP has historically felt aggressive on localization /
|
||||
location; want a deliberate compare vs stock LineageOS before cloning that
|
||||
policy blindly.
|
||||
|
||||
## What to compare later
|
||||
|
||||
| Area | AXP / GOLDEN | Stock LOS 23 | Decision TBD |
|
||||
|------|--------------|--------------|--------------|
|
||||
| Network location / NLP backends | microG BeaconDB path (see `004`/`005` docs) | LOS + microG defaults | |
|
||||
| Location permission defaults | | | |
|
||||
| Privacy toggles / sensors | | | |
|
||||
| Extra lockdown patches | | | |
|
||||
| UX: “how much it capea” | Owner complaint baseline | | |
|
||||
|
||||
## Until then
|
||||
|
||||
Do **not** invent extra location lockdown beyond what the rest of the AXP clone
|
||||
already implies. Matrix row = `deferred`.
|
||||
@@ -0,0 +1,111 @@
|
||||
# 009 Magisk preinstall runbook (AXP / GOLDEN class)
|
||||
|
||||
**Device roles**: GOLDEN `11071JEC203839` = `adb` **read-only** oracle.
|
||||
LAB `11231JEC207477` = flash/test only. **Never** flash or Magisk-change GOLDEN.
|
||||
|
||||
**Evidence**: `/srv/rom/artifacts/009-axp-los23-port/`
|
||||
**Contract**: `specs/009-axp-los23-port/contracts/magisk-preinstall.md`
|
||||
|
||||
## Ship policy (owner 2026-09-17)
|
||||
|
||||
- **Clone AXP first (mandatory):** Magisk packaging = EXTENDROM
|
||||
`EXTENDROM_PREROOT_BOOT` method. Copy that flow; do **not** invent alternate
|
||||
Magisk install paths. Only diverge if LOS23 / Magisk version breaks the
|
||||
AXP/EXTENDROM path, and document why.
|
||||
- **Magisk clean**: ship Magisk preroot only — **do not** bake GOLDEN modules
|
||||
(`playintegrityfix`, `teesim`, `hosts`, `flag-secure-disabler`,
|
||||
`zygisk_vector`, …). Owner installs modules later if wanted.
|
||||
- **Manager UI**: stock **Magisk** upstream (not Magia branding).
|
||||
- **Dormant until activation (AXP Pro):** after flash, Magisk is pre-rooted in
|
||||
boot but root must stay inactive until the user opens Magisk and completes
|
||||
Additional Setup. Skipping setup ⇒ no `su` / no Magisk binaries in the OS
|
||||
(undetectable). Do **not** bake Magisk as `PRODUCT_PACKAGE`; do **not**
|
||||
sideload the full Magisk APK before measuring virgin LAB state.
|
||||
- **Build host**: LAB/GOLDEN USB **not required** to compile. Phones only for
|
||||
measurement (GOLDEN `adb`) or flash validation (LAB).
|
||||
|
||||
## GOLDEN measurement (2026-09-17, live `adb`)
|
||||
|
||||
| Item | Value |
|
||||
|------|--------|
|
||||
| Build | `22.2-2026.003-sunfish-pro` / `BP1A.250505.005` |
|
||||
| Magisk binary | **29.0:MAGISK:R** (`29000`) at `/system_ext/bin/magisk` |
|
||||
| Also present | `/system_ext/bin/magiskpolicy` |
|
||||
| Runtime | `/data/adb/magisk/` full toolkit + `stub.apk`; `magisk.db` |
|
||||
| Settings (sqlite via `magisk --sqlite`) | `zygisk=1`, `denylist=1`, `mnt_ns=2`, `bootloop=0` |
|
||||
| Manager UI | Magisk app **hidden/renamed** (random pkg `oq.aq.cjn`, `versionName=1.0`) — AXP brands this UI as **Magia** in docs/screenshots; package name is not stable after “Hide the Magisk app” |
|
||||
| Modules seen | `flag-secure-disabler`, `hosts`, `playintegrityfix`, `teesim`, `zygisk_vector` |
|
||||
| Secure toggles | `allow_signature_fake=1`, `extendrom_call_recording=1` |
|
||||
|
||||
**Important:** GOLDEN is already **fully activated**. The virgin
|
||||
“preinstalled but not fully activated” UX is the **first-boot / additional
|
||||
setup** Magisk flow after an AXP-style preroot image (see AXP setup guide +
|
||||
EXTENDROM FAQ: “Requires Additional Setup”). Measure that class from AXP docs +
|
||||
EXTENDROM `PREINITDEVICE=userdata` behaviour — do not wipe GOLDEN to re-see it.
|
||||
|
||||
## How AXP / EXTENDROM builds Magisk into the ROM
|
||||
|
||||
Attribute: **sfX-android `android_vendor_extendrom`** + Magisk APK.
|
||||
|
||||
1. `EXTENDROM_PREROOT_BOOT=true` — Magisk is **not** a normal PRODUCT_PACKAGE;
|
||||
it patches **boot / init_boot** at image build time.
|
||||
2. Magisk APK (v22+) is unzipped under `out/.magisk/`; `boot_patch.sh` runs via
|
||||
`vendor/extendrom/config/magisk/patch.sh`.
|
||||
3. Releasetools inject: patch under
|
||||
`config/magisk/{lineage|axp}/A{version}/0001-build_make_tools_releasetools_common.py`
|
||||
hooks `common.py` `_BuildBootableImage` / prebuilt boot.
|
||||
4. Patcher env of note: `KEEPVERITY=true`, `KEEPFORCEENCRYPT=true`,
|
||||
`PREINITDEVICE=userdata`, `BOOTMODE=false`.
|
||||
5. Post-flash **virgin**: stub may appear; `/system_ext/bin/magisk` and `su`
|
||||
appear only **after** user activation (AXP FAQ “Revert Magisk activation”).
|
||||
Measure virgin before opening Magisk. GOLDEN already activated is not virgin.
|
||||
|
||||
Host reference tree: `/srv/rom/references/extendrom/` on `rom-dev01`.
|
||||
|
||||
## Enable Magisk on next bacon (009)
|
||||
|
||||
```bash
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
export OUT_DIR=/srv/rom/src/lineage/out # or /srv/rom/out-009 for parallel
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
# Copy staged runtime into OUT (or re-run prepare):
|
||||
# rsync -a /srv/rom/prebuilts/magisk/runtime/ "$OUT_DIR/.magisk/"
|
||||
# or: MAGISK_STAGE_DIR=$OUT_DIR/.magisk vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
```
|
||||
|
||||
Hook is already in `build/make/tools/releasetools/common.py` but **no-ops** unless
|
||||
`SUNFISH_A16_MAGISK_PREROOT=1` (008 in-flight stays safe).
|
||||
|
||||
1. Clean-flash LAB with Magisk-preroot `009` images (wipe `/data` if LAB had
|
||||
Magisk activated before).
|
||||
2. **Virgin check (before opening Magisk):**
|
||||
`adb shell 'which su; which magisk; ps -A | grep magiskd'` — expect no `su`,
|
||||
no Magisk binaries (AXP dormant). Record under `…/magisk/pre-activation.md`.
|
||||
3. Open Magisk stub → download/install full Magisk if prompted → complete
|
||||
**Additional setup** → reboot (AXP setup guide).
|
||||
4. Confirm `magisk -v` matches pin (target: newest workable stable; host aims
|
||||
at **v30.7** unless regression).
|
||||
5. Enable Zygisk + DenyList as needed.
|
||||
6. For DenyList smoke (MVP): hide a **non-bank test package** before first open.
|
||||
7. Banking DenyList workflow = **deferred** (US3 / Gate E).
|
||||
|
||||
## Optional KernelSU recycle (FR-016)
|
||||
|
||||
Paths under `/srv/rom/artifacts/007-*/` — debug/reference only. **Not ship.**
|
||||
Never gate Magisk acceptance on KSU.
|
||||
|
||||
**Hard rule for Magisk LAB:** `sunfish_defconfig` must keep `# CONFIG_KSU is not
|
||||
set` (and SusFS off). Magisk + in-kernel ReSukiSU/KSU on the same boot causes
|
||||
app `failed to attach` / `start timeout` and hung `su`.
|
||||
|
||||
**Full AXP-clone bacon (detached):**
|
||||
`/srv/rom/artifacts/009-axp-los23-port/scripts/009-bacon-axp.sh`
|
||||
session `009-bacon-axp` — Magisk preroot + noksu + Phonesky exact-alarm +
|
||||
WMS FLAG_SECURE (no `ro.debuggable` gate). After zip sideload, flash
|
||||
artifact `boot.img` (TF IMAGES) to both slots.
|
||||
|
||||
## Staged known-good images (FR-013)
|
||||
|
||||
Keep prior LAB flashables + SHA-256 under
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/` before each risky Magisk or
|
||||
hardening stage.
|
||||
@@ -0,0 +1,34 @@
|
||||
# AXP Private DNS providers (from GOLDEN Settings)
|
||||
|
||||
Source: `Settings.apk` on GOLDEN `11071JEC203839`
|
||||
(`22.2-2026.003-sunfish-pro`), pulled 2026-09-18.
|
||||
Artifact: `.local-artifacts/002-golden/20260918-private-dns/Settings.apk`
|
||||
|
||||
Stock AOSP/LOS radios: Off / Automatic / Provider hostname.
|
||||
AXP adds the following preset radios (hostname → DoT provider):
|
||||
|
||||
| key (resource) | UI label (en) | hostname |
|
||||
|----------------|---------------|----------|
|
||||
| `adguard` | AdGuard (CT) | `dns.adguard.com` |
|
||||
| `appliedprivacy` | AppliedPrivacy (AT) | `dot1.applied-privacy.net` |
|
||||
| `cira` | CIRA (CA) | `protected.canadianshield.cira.ca` |
|
||||
| `cleanbrowsing` | CleanBrowsing (US) | `security-filter-dns.cleanbrowsing.org` |
|
||||
| `cloudflare` | Cloudflare (US) | `security.cloudflare-dns.com` |
|
||||
| `controld` | Control D (CA) | `p2.freedns.controld.com` |
|
||||
| `cznic` | CZ.NIC (CZ) | `odvr.nic.cz` |
|
||||
| `dnssb` | DNS.SB (DE) | `dot.sb` |
|
||||
| `dnszero` | DNS0 (FR) | `zero.dns0.eu` |
|
||||
| `google` | Google (US) | `dns.google` |
|
||||
| `mullvad` | Mullvad (SE) | `base.dns.mullvad.net` |
|
||||
| `quadnine` | Quad9 (CH) | `dns.quad9.net` |
|
||||
| `restena` | Restena (LU) | `kaitain.restena.lu` |
|
||||
| `switch` | SWITCH (CH) | `dns.switch.ch` |
|
||||
| `uncensoreddns` | UncensoredDNS (DK) | `anycast.censurfridns.dk` |
|
||||
|
||||
Plus stock: Off, Opportunistic (Automatic), custom Provider hostname.
|
||||
|
||||
AXP setup docs recommend Quad9 (`dns.quad9.net`) and DNS0 (`zero.dns0.eu`).
|
||||
|
||||
Clone target for LOS 23.2: extend `PrivateDnsModeDialogPreference` +
|
||||
`private_dns_mode_dialog.xml` + strings to match this set (no `axp.os`
|
||||
branding).
|
||||
@@ -0,0 +1,30 @@
|
||||
# 009 — Sideload system package updates (FR-019)
|
||||
|
||||
Owner cadence: refresh bundled **system / privileged** packages about every
|
||||
**2–3 months** without a full ROM reflash. **No** AXP OTA / external repos.
|
||||
|
||||
Status: **stub** — fill before final ship (task T046a). Packaging of the
|
||||
shipping image MUST already preserve update eligibility.
|
||||
|
||||
## In scope
|
||||
|
||||
| Component | Intended update path | Signing constraint |
|
||||
|-----------|----------------------|--------------------|
|
||||
| microG GmsCore / companions | `adb install -r` / recovery sideload of upstream APK | **PRESIGNED** / same signer as shipped |
|
||||
| Magisk | Magisk app self-update and/or documented boot re-patch | Manager + boot image must stay matched |
|
||||
| Project Phonesky | Sideload project-signed APK | **Same project key** across releases |
|
||||
| Other bundled system apps | Sideload matching-signer APK (or recovery zip if priv-app needs it) | Same identity as image |
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Network OTA / AXP update servers
|
||||
- Full `bacon` + clean flash for routine APK bumps (still OK for kernel /
|
||||
framework / Magisk boot changes when required)
|
||||
|
||||
## Checklist before claiming FR-019 done
|
||||
|
||||
- [ ] Each row above has a concrete command/runbook step
|
||||
- [ ] `pm install` / PackageManager does not reject for signature mismatch
|
||||
- [ ] Privileged permissions still grant after update (or re-flash privapp XML noted)
|
||||
- [ ] Magisk version after update matches kernel/boot expectation
|
||||
- [ ] Record new versions in `docs/009-version-pins.md`
|
||||
@@ -0,0 +1,52 @@
|
||||
# US-S4 — Userspace hardening (first stage)
|
||||
|
||||
Status 2026-10-02. No bacon solely for this doc.
|
||||
|
||||
## Stage 0 — LAB baseline (measure, closed)
|
||||
|
||||
On LAB `11231JEC207477` after AVB ship `20261002T103558Z` (+ boot/vbmeta reinforce):
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| SELinux | Enforcing |
|
||||
| Encryption | `ro.crypto.state=encrypted`, `ro.crypto.type=file` |
|
||||
| Verified boot | orange / `flash.locked=0` (unlocked Magisk track) |
|
||||
| `security.perf_harden` | 1 (already) |
|
||||
| Yama / `ptrace_scope` | **done** (US-S5-1 `162840Z`) — `CONFIG_SECURITY_YAMA=y` |
|
||||
|
||||
## Stage 1 — US-S4-1 drop product OpenSSH / rsync / procmem
|
||||
|
||||
**Oracle**: `AXP.OS-22.2-20260324-PRO-sunfish.zip` product (+ system) images —
|
||||
no `sshd`/`ssh`/`rsync`/`procmem` binaries; orphan `init.openssh.rc` only.
|
||||
|
||||
**Shipped in tree**: `vendor/sunfish-a16/hardening.mk` +
|
||||
`patches/009-axp-los23-port/hardening/README.md`.
|
||||
|
||||
Removes Lineage product OpenSSH binaries + `rsync`, `procmem` (DEBUG).
|
||||
**Keeps** `init.openssh.rc` (AXP PRO still has it). Admin path: adb + Magisk.
|
||||
|
||||
LAB verify after flash: no `/product/bin/sshd`, no `/product/bin/rsync`,
|
||||
`/product/etc/init/init.openssh.rc` present, Magisk still up.
|
||||
|
||||
## Stage 2 — US-S4-2 drop Jelly + Gallery2
|
||||
|
||||
**Oracle**: AXP PRO product has neither; Fossify on system_ext. See
|
||||
`docs/009-axp-pro-product-apps-20260324.md`.
|
||||
|
||||
Wired: `apply_009_drop_jelly_gallery2.py`, `NoLineageJelly` phony override,
|
||||
hardening.mk filter, bacon gate. Pending next bacon + LAB.
|
||||
|
||||
## Later candidates (one per bacon when risk unclear)
|
||||
|
||||
1. Mount / noexec where stock sunfish already allows (verify HW first)
|
||||
2. Package-visibility / query hardening (high app-compat risk → later)
|
||||
3. Further debug-tool trim (`adb_root` only if LAB proves unused)
|
||||
|
||||
Promote from `docs/hardening-backlog.md` only with upstream attribution.
|
||||
|
||||
## Out of scope here
|
||||
|
||||
- `WITH_AVB=true` / flags 0
|
||||
- Bootloader relock
|
||||
- `lineage_sunfish-user` default lunch (US-S6)
|
||||
- Kernel Yama / more CVE (US-S5)
|
||||
@@ -0,0 +1,24 @@
|
||||
# 009 version pins
|
||||
|
||||
Policy: newest stable (or newest tagged pre-release upstream ships) that works
|
||||
on sunfish / LOS 23.2 — except Phonesky = project artifact, WebView = LOS
|
||||
default. Refresh with `git fetch --tags` / release APIs before long builds.
|
||||
Never ship from stale laptop caches.
|
||||
|
||||
| component | version_name | version_code | upstream_ref | policy | verified_on | notes |
|
||||
|-----------|--------------|--------------|--------------|--------|-------------|-------|
|
||||
| VanillaBaseline | lineage-23.2 sunfish | | `/srv/rom/artifacts/003-vanilla/20260914-lineage-23.2-sunfish` | los_default | 2026-09-14 | Known-good vanilla artifact on host |
|
||||
| microG GmsCore | v0.3.16.252432 | | microG official (matches GitHub latest 2026-09-17) | newest_stable | 2026-09-16 staged | `/srv/rom/prebuilts/microg/` |
|
||||
| GSF Proxy | v0.1.0 | | microG official | newest_stable | 2026-09-16 staged | |
|
||||
| Phonesky | 52.9.22-24 | | project patched host artifact | project_phonesky | 2026-09-14 | `/srv/rom/prebuilts/phonesky/`; never Git |
|
||||
| Magisk | v30.7 | | https://github.com/topjohnwu/Magisk/releases/tag/v30.7 | newest_stable | 2026-09-17 | Staged APK; GOLDEN oracle **29.0** layout only |
|
||||
| Kernel sunfish | 4.14.357-openela | | `kernel/google/msm-4.14` @ `28f9290ae067` | los_default + FR-017 stage1 | 2026-09-18 | AXP `kernel_patches` @ `df3cab2155b3`; see `docs/009-kernel-hardening-map.md` |
|
||||
| Aurora Store | present on GOLDEN | | `com.aurora.store` | newest_stable | 2026-09-17 seen | Stage APK later |
|
||||
| F-Droid | present on GOLDEN | | `org.fdroid.fdroid` | newest_stable | 2026-09-17 seen | |
|
||||
| Fossify Gallery | present on GOLDEN | | `org.fossify.gallery` | newest_stable | 2026-09-17 seen | |
|
||||
| Seedvault | present on GOLDEN | | `com.stevesoltys.seedvault` | los_default / newest | 2026-09-17 seen | Often LOS-provides |
|
||||
| Island | deferred | | `com.oasisfeng.island.fdroid` | | | US3 deferred |
|
||||
|
||||
## Host artifact hashes (copy from host VERSIONS when refreshed)
|
||||
|
||||
See `/srv/rom/prebuilts/*/VERSIONS.txt` on `rom-dev01`.
|
||||
@@ -39,7 +39,7 @@ feature. Signing/AVB, userspace hardening, and kernel hardening remain `011`–
|
||||
| Magisk / preroot | Magisk (**Magia** UI on GOLDEN, 29.0) | **Substitute:** KernelSU-Next (+ SusFS) / evaluate ReSukiSU | substitute | Captured in `002`; do **not** fix GOLDEN; project root = `007` on LAB |
|
||||
| DenyList / umount for banks | Magia DenyList (pkg list in `docs/002-golden-inventory.md`) | KernelSU app profiles + verified umount | todo | `007` re-runs `006`; GOLDEN DenyList captured `002` |
|
||||
| Insular work profile | AXP docs say Insular; **GOLDEN measures Island** (`com.oasisfeng.island.fdroid` 6.4.2) | Banking workflow parity (Island or equivalent) | todo | `006`; capture in `002` |
|
||||
| Yuh in Insular/Island | Historically worked; **FAIL since ~weeks** (HA / “certificate invalid”; KeyMint/TEE errors in `002` logs) | Hard-gate Compatibility MVP (rootless in `006`); **Revolut not a hard-gate** | partial | `002` evidence; LAB may need SusFS+TrickyStore-class stack (`reference-sources.md` §8); never GOLDEN |
|
||||
| Yuh in Insular/Island | Was FAIL ~weeks (HA); **PASS again 2026-10-02 on GOLDEN** with Vector **bootloader spoofer** (`002`) | Hard-gate Compatibility MVP (rootless in `006`); **Revolut not a hard-gate** | partial | `002`; Gate E on LAB = DenyList + PIF/teesim + Vector BL spoof (sunfish-coherent); never flash GOLDEN |
|
||||
| Swissquote in Insular/Island | **PASS** on GOLDEN (owner report, DenyList) | Hard-gate Compatibility MVP (rootless in `006`) | partial | `002`; re-test in `006`/`007`/`011` |
|
||||
| Unrestricted call recording | Yes | Yes — native ROM on Android 16 | todo | AXP/EXTENDROM/iodé as references only; re-validate on LOS 23.2; `008` |
|
||||
| DNS blocker / privacy DNS | Yes | Wanted; exact UX TBD | decide | `010` |
|
||||
|
||||
+21
-16
@@ -55,31 +55,32 @@ Status: `candidate` | `investigate` | `accepted→spec` | `rejected` | `los-prov
|
||||
|
||||
The kernel base remains the LineageOS 23.2-compatible sunfish kernel.
|
||||
|
||||
**Priority (009 / owner 2026-09-18):** AXP clone first → LOS inventory →
|
||||
IodéOS diff → optional Graphene (modern techniques / selective A13).
|
||||
**Do not** separately mine DivestOS EOL. See `docs/009-kernel-hardening-map.md`.
|
||||
|
||||
```text
|
||||
┌─ historical GOS sunfish
|
||||
┌─ AXP sunfish (max priority clone)
|
||||
│
|
||||
LOS23/A16 sunfish 4.14 ←─┼─ AXP own + DivestOS
|
||||
LOS23/A16 sunfish 4.14 ←─┼─ LOS23 already-present
|
||||
OUR BASE │
|
||||
├─ modern GOS techniques
|
||||
├─ IodéOS (LOS fork, hardened/deblobbed)
|
||||
│
|
||||
└─ original upstream fixes
|
||||
└─ Graphene optional (modern / selective A13)
|
||||
```
|
||||
|
||||
**Not:** GrapheneOS Android 13 (or any old GrapheneOS) kernel tree as our base.
|
||||
**Not:** DivestOS as a hunt target (EOL).
|
||||
|
||||
Candidate hardening comes from four classes:
|
||||
Candidate hardening comes from:
|
||||
|
||||
1. **Historical GrapheneOS sunfish** — device-specific patches/configuration known
|
||||
to have run on sunfish (real commits, not only `.config`).
|
||||
2. **AXP.OS / DivestOS sunfish** — audit the actual patch stack; distinguish
|
||||
AXP-owned changes from inherited changes.
|
||||
3. **Modern GrapheneOS** — use current kernel hardening as a source of
|
||||
techniques/security properties; adapt/backport only where feasible on
|
||||
non-GKI Linux 4.14; do not assume current Pixel kernel patches cherry-pick
|
||||
cleanly.
|
||||
4. **Original upstream** — where a GrapheneOS/AXP/Divest patch derives from AOSP,
|
||||
Android common, Linux stable, or another upstream source, prefer the
|
||||
appropriate original upstream fix when practical.
|
||||
1. **AXP.OS sunfish** — primary; audit actual patch stack on `rom-dev01`.
|
||||
2. **LineageOS 23.2 msm-4.14** — what is already applied.
|
||||
3. **IodéOS** — diff vs LOS for extra hardening/deblob worth porting.
|
||||
4. **GrapheneOS** — optional: modern Pixel techniques adaptable to 4.14;
|
||||
historical sunfish A13 only if clearly still valuable.
|
||||
5. **Original upstream** — when a patch derives from Linux/AOSP common,
|
||||
prefer upstream form when practical.
|
||||
|
||||
For each candidate record:
|
||||
|
||||
@@ -96,6 +97,10 @@ For each candidate record:
|
||||
- test result;
|
||||
- final decision.
|
||||
|
||||
**Location:** do not extra-cap vs LOS (owner GPS UX); skip AXP location
|
||||
lockdown in this track unless revisited later.
|
||||
|
||||
|
||||
## Much later / evaluate
|
||||
|
||||
| Idea | Notes | Status |
|
||||
|
||||
Executable
+152
@@ -0,0 +1,152 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — AXP Magisk preroot + combo4+Clang-FORTIFY kernel (LAB-verified pack).
|
||||
# Does NOT apply Graphene Stage1 mega-pack (not boot-OK yet on LOS23/Clang).
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-combo4-fortify.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-combo4-fortify $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
APPLY=vendor/sunfish-a16/patches/009-kernel-hardening/apply_combo4_fortify.sh
|
||||
test -x "$APPLY" || chmod +x "$APPLY"
|
||||
bash "$APPLY" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: $DEF still enables KernelSU" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
if ! grep -q "^CONFIG_${k}=y" "$DEF"; then
|
||||
echo "FAIL: missing CONFIG_${k}=y" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
echo "OK: combo4+FORTIFY markers + nested-strlen fix present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
echo "OK: cleared prior Image for kernel rebuild"
|
||||
|
||||
# FLAG_SECURE + Settings UX (idempotent)
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
if ! "$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM; then
|
||||
echo "FAIL: Phonesky missing USE_EXACT_ALARM" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: Phonesky has USE_EXACT_ALARM"
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-combo4-fortify
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
echo "boot_source=target_files_IMAGES"
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
echo "WARN: no TF IMAGES/boot.img — using Make boot"
|
||||
fi
|
||||
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
# Magisk present, KernelSU absent
|
||||
MB=out/.magisk/magiskboot
|
||||
if [ -x "$MB" ]; then
|
||||
rm -rf "$DEST/boot-check" && mkdir -p "$DEST/boot-check"
|
||||
if "$MB" unpack "$DEST/boot.img" "$DEST/boot-check" >/dev/null 2>&1; then
|
||||
if [ -f "$DEST/boot-check/ramdisk.cpio" ]; then
|
||||
if "$MB" cpio "$DEST/boot-check/ramdisk.cpio" "exists overlay.d/sbin/magisk64.xz" \
|
||||
|| "$MB" cpio "$DEST/boot-check/ramdisk.cpio" "exists overlay.d/sbin/magisk.xz"; then
|
||||
echo "OK: Magisk overlay in boot.img"
|
||||
else
|
||||
echo "WARN: Magisk overlay not detected in boot.img ramdisk"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "WARN: magiskboot unpack failed (host SIGILL flake possible); skip TF check"
|
||||
fi
|
||||
fi
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU strings in boot.img" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: no KernelSU strings in boot.img"
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "kernel_base=$BASE"
|
||||
echo "hardening=combo4+clang-fortify (nested __underlying_strlen)"
|
||||
echo "magisk=preroot EXTENDROM-class v30.7"
|
||||
echo "stage1_graphene=NOT_INCLUDED (not boot-OK on LOS23 yet)"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1+combo4+FORTIFY + CVE bisect half (h1|h2).
|
||||
# Usage on rom-dev01: CVE_BISECT=h1 bash scripts/009-bacon-axp-stage1-combo4-cve-bisect.sh
|
||||
set -e
|
||||
BISECT="${CVE_BISECT:?set CVE_BISECT=h1 or h2}"
|
||||
case "$BISECT" in h1|h2) ;; *) echo "CVE_BISECT must be h1 or h2" >&2; exit 2 ;; esac
|
||||
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-${BISECT}.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve-${BISECT} $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST="$KH/cve-bisect-${BISECT}.list"
|
||||
test -f "$LIST"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
export CVE_STRICT_LIST="$LIST"
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-${BISECT} markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-${BISECT}
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
fi
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "bisect=$BISECT"
|
||||
echo "list=$LIST"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-${BISECT}"
|
||||
echo "signing=test-keys"
|
||||
echo "flash=fastboot flash boot boot.img (preferred for bisect); sideload zip if Wi-Fi breaks"
|
||||
echo "recover=fastboot flash boot from 20260929T123401Z-axp-stage1-combo4"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1+combo4+FORTIFY + CVE clean-offset allowlist (no huge patch offsets).
|
||||
# Does not include cve-high-offset-ge200.txt. test-keys. Do not flash until boot-tested.
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-clean.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve-clean $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST="$KH/cve-clean-offset.list"
|
||||
test -f "$LIST"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
export CVE_STRICT_LIST="$LIST"
|
||||
# Strict quality gates (defaults in apply_cve_strict.sh)
|
||||
unset CVE_STRICT_CONTINUE || true
|
||||
export CVE_MAX_FUZZ=1
|
||||
export CVE_MAX_ABS_OFFSET=200
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-clean-offset markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-clean
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
fi
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "list=$LIST (cve-strict minus high-offset>=200 minus denylist)"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean-offset"
|
||||
echo "signing=test-keys"
|
||||
echo "flash=fastboot flash boot ONLY after owner OK; recover=Stage1 boot.img"
|
||||
echo "note=do not flash full 503 CVE zip"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1+combo4+FORTIFY + CVE clean-offset + high-offset batch1 (≤10).
|
||||
# Batch1: intentional CVE_MAX_ABS_OFFSET=9999 after spot-check (fuzz=0). test-keys.
|
||||
# Do not flash until boot-tested. Recover = last clean BOOT_OK boot.img.
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-hi-batch1.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve-hi-batch1 $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST_CLEAN="$KH/cve-clean-offset.list"
|
||||
LIST_HI="$KH/cve-high-offset-batch1.list"
|
||||
test -f "$LIST_CLEAN"
|
||||
test -f "$LIST_HI"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
|
||||
export CVE_STRICT_LIST="$LIST_CLEAN"
|
||||
unset CVE_STRICT_CONTINUE || true
|
||||
export CVE_MAX_FUZZ=1
|
||||
export CVE_MAX_ABS_OFFSET=200
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
echo "=== high-offset batch1 (elevated abs-offset gate; fuzz still ≤1) ==="
|
||||
export CVE_STRICT_LIST="$LIST_HI"
|
||||
export CVE_MAX_ABS_OFFSET=9999
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
# batch1 markers (spot-checked)
|
||||
grep -q "mmget_still_valid" "$LIVE/mm/madvise.c"
|
||||
grep -q "sched_release_group" "$LIVE/kernel/sched/core.c"
|
||||
grep -q "fwnode_handle_put(tcpci->tcpc.fwnode)" "$LIVE/drivers/usb/typec/tcpm/tcpci.c"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-clean + hi-batch1 markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-hi-batch1
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
fi
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "list_clean=$LIST_CLEAN (429)"
|
||||
echo "list_hi=$LIST_HI (7; dropped CVE-2023-3777 missing nft_chain_is_bound)"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1"
|
||||
echo "cve_max_abs_offset_hi=9999"
|
||||
echo "signing=test-keys"
|
||||
echo "flash=fastboot flash boot ONLY after owner OK; recover=cve-clean BOOT_OK"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1+combo4+FORTIFY + CVE clean + hi-batch1 + hi-batch2.
|
||||
# Elevated CVE_MAX_ABS_OFFSET=9999 for high-offset lists. test-keys.
|
||||
# Recover = hi-batch1 BOOT_OK boot.img (or cve-clean).
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-hi-batch2.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve-hi-batch2 $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST_CLEAN="$KH/cve-clean-offset.list"
|
||||
LIST_HI1="$KH/cve-high-offset-batch1.list"
|
||||
LIST_HI2="$KH/cve-high-offset-batch2.list"
|
||||
test -f "$LIST_CLEAN"
|
||||
test -f "$LIST_HI1"
|
||||
test -f "$LIST_HI2"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
|
||||
export CVE_STRICT_LIST="$LIST_CLEAN"
|
||||
unset CVE_STRICT_CONTINUE || true
|
||||
export CVE_MAX_FUZZ=1
|
||||
export CVE_MAX_ABS_OFFSET=200
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
echo "=== high-offset batch1 (prior LAB OK) ==="
|
||||
export CVE_STRICT_LIST="$LIST_HI1"
|
||||
export CVE_MAX_ABS_OFFSET=9999
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
echo "=== high-offset batch2 ==="
|
||||
export CVE_STRICT_LIST="$LIST_HI2"
|
||||
export CVE_MAX_ABS_OFFSET=9999
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
grep -q "mmget_still_valid" "$LIVE/mm/madvise.c"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2 markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-hi-batch2
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
fi
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "list_clean=$LIST_CLEAN (429)"
|
||||
echo "list_hi1=$LIST_HI1"
|
||||
echo "list_hi2=$LIST_HI2"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2"
|
||||
echo "cve_max_abs_offset_hi=9999"
|
||||
echo "signing=test-keys"
|
||||
echo "flash=fastboot flash boot; recover=hi-batch1 BOOT_OK"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1+combo4+FORTIFY + CVE clean + hi-batch1+2+3.
|
||||
# Elevated CVE_MAX_ABS_OFFSET=9999 for high-offset lists. test-keys.
|
||||
# Recover = hi-batch2 BOOT_OK boot.img.
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-hi-batch3.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve-hi-batch3 $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST_CLEAN="$KH/cve-clean-offset.list"
|
||||
LIST_HI1="$KH/cve-high-offset-batch1.list"
|
||||
LIST_HI2="$KH/cve-high-offset-batch2.list"
|
||||
LIST_HI3="$KH/cve-high-offset-batch3.list"
|
||||
test -f "$LIST_CLEAN"
|
||||
test -f "$LIST_HI1"
|
||||
test -f "$LIST_HI2"
|
||||
test -f "$LIST_HI3"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
|
||||
export CVE_STRICT_LIST="$LIST_CLEAN"
|
||||
unset CVE_STRICT_CONTINUE || true
|
||||
export CVE_MAX_FUZZ=1
|
||||
export CVE_MAX_ABS_OFFSET=200
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
export CVE_MAX_ABS_OFFSET=9999
|
||||
for L in "$LIST_HI1" "$LIST_HI2" "$LIST_HI3"; do
|
||||
echo "=== high-offset $(basename "$L") ==="
|
||||
export CVE_STRICT_LIST="$L"
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
done
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
grep -q "mmget_still_valid" "$LIVE/mm/madvise.c"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3 markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-hi-batch3
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
fi
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "list_clean=$LIST_CLEAN (429)"
|
||||
echo "list_hi1=$LIST_HI1"
|
||||
echo "list_hi2=$LIST_HI2"
|
||||
echo "list_hi3=$LIST_HI3"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3"
|
||||
echo "cve_max_abs_offset_hi=9999"
|
||||
echo "signing=test-keys"
|
||||
echo "flash=fastboot flash boot; recover=hi-batch2 BOOT_OK"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
# Force clean exit even if tee gets SIGPIPE on detach wrap
|
||||
exit 0
|
||||
+380
@@ -0,0 +1,380 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — ship pack with project release keys (US-S2).
|
||||
# Stage1+combo4+FORTIFY + CVE clean + hi-batch1+2+3 + PRODUCT_DEFAULT_DEV_CERTIFICATE.
|
||||
# Requires $HOME/.android-certs/releasekey.{pk8,x509.pem}. userdebug.
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve-hi-releasekeys.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-cve-hi-releasekeys $(date -Is) ==="
|
||||
|
||||
CERT_DIR="${ANDROID_CERTS_DIR:-$HOME/.android-certs}"
|
||||
if [[ ! -f "$CERT_DIR/releasekey.pk8" || ! -f "$CERT_DIR/releasekey.x509.pem" ]]; then
|
||||
echo "FAIL: missing $CERT_DIR/releasekey.{pk8,x509.pem}" >&2
|
||||
exit 1
|
||||
fi
|
||||
export PRODUCT_DEFAULT_DEV_CERTIFICATE="$CERT_DIR/releasekey"
|
||||
echo "OK: PRODUCT_DEFAULT_DEV_CERTIFICATE=$PRODUCT_DEFAULT_DEV_CERTIFICATE"
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
LIST_CLEAN="$KH/cve-clean-offset.list"
|
||||
LIST_HI1="$KH/cve-high-offset-batch1.list"
|
||||
LIST_HI2="$KH/cve-high-offset-batch2.list"
|
||||
LIST_HI3="$KH/cve-high-offset-batch3.list"
|
||||
test -f "$LIST_CLEAN"
|
||||
test -f "$LIST_HI1"
|
||||
test -f "$LIST_HI2"
|
||||
test -f "$LIST_HI3"
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1.sh "$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
|
||||
bash "$KH/apply_stage1_combo4.sh" "$LIVE"
|
||||
|
||||
# US-S5-1 — Yama + SLAB_FREELIST_RANDOM (Graphene/AXP defconfig gaps)
|
||||
chmod +x "$KH/apply_uss5_1_defconfig.sh" 2>/dev/null || true
|
||||
bash "$KH/apply_uss5_1_defconfig.sh" "$LIVE"
|
||||
|
||||
export CVE_STRICT_LIST="$LIST_CLEAN"
|
||||
unset CVE_STRICT_CONTINUE || true
|
||||
export CVE_MAX_FUZZ=1
|
||||
export CVE_MAX_ABS_OFFSET=200
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
|
||||
export CVE_MAX_ABS_OFFSET=9999
|
||||
for L in "$LIST_HI1" "$LIST_HI2" "$LIST_HI3"; do
|
||||
echo "=== high-offset $(basename "$L") ==="
|
||||
export CVE_STRICT_LIST="$L"
|
||||
bash "$KH/apply_cve_strict.sh" "$LIVE"
|
||||
done
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: KernelSU in defconfig" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED \
|
||||
SECURITY_YAMA SLAB_FREELIST_RANDOM; do
|
||||
grep -q "^CONFIG_${k}=y" "$DEF" || { echo "FAIL missing $k" >&2; exit 1; }
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
grep -q "mmget_still_valid" "$LIVE/mm/madvise.c"
|
||||
echo "OK: Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3 markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_unofficial_build_id.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_openssh_packages.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_jelly_gallery2.py
|
||||
|
||||
# Host prebuilts → vendor/sunfish-a16/prebuilt (rsync --delete must not wipe these).
|
||||
mkdir -p vendor/sunfish-a16/prebuilt
|
||||
link_prebuilt() {
|
||||
local name="$1" src="$2"
|
||||
local dst="vendor/sunfish-a16/prebuilt/$name"
|
||||
ln -sfn "$src" "$dst"
|
||||
test -e "$dst" || { echo "FAIL: missing prebuilt $dst -> $src" >&2; exit 1; }
|
||||
}
|
||||
link_prebuilt Phonesky.apk /srv/rom/prebuilts/phonesky/Phonesky.apk
|
||||
link_prebuilt GmsCore.apk /srv/rom/prebuilts/microg/GmsCore.apk
|
||||
link_prebuilt GsfProxy.apk /srv/rom/prebuilts/microg/GsfProxy.apk
|
||||
link_prebuilt AuroraStore.apk /srv/rom/prebuilts/axp-apps/AuroraStore.apk
|
||||
link_prebuilt Droidify.apk /srv/rom/prebuilts/axp-apps/Droidify.apk
|
||||
link_prebuilt FossifyGallery.apk /srv/rom/prebuilts/axp-apps/FossifyGallery.apk
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
"$AAPT" dump permissions vendor/sunfish-a16/prebuilt/Phonesky.apk 2>/dev/null | grep -q USE_EXACT_ALARM
|
||||
|
||||
# Early hook so LINEAGE_VERSION includes AXP-Resurection-Pro (before version.mk).
|
||||
mkdir -p vendor/extra
|
||||
ln -sfn ../sunfish-a16/extra-product.mk vendor/extra/product.mk
|
||||
test -f vendor/extra/product.mk
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
# re-export after envsetup (some trees clear it)
|
||||
export PRODUCT_DEFAULT_DEV_CERTIFICATE="$CERT_DIR/releasekey"
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
BT_SEPOL=$(get_build_var MAINLINE_BLUETOOTH_SEPOLICY_DEV_CERTIFICATES)
|
||||
echo "MAINLINE_BLUETOOTH_SEPOLICY_DEV_CERTIFICATES=$BT_SEPOL"
|
||||
case "$BT_SEPOL" in
|
||||
*vendor/sunfish-a16/certs*) ;;
|
||||
*) echo "FAIL: BT sepolicy certs still AOSP default ($BT_SEPOL)" >&2; exit 1 ;;
|
||||
esac
|
||||
AVB_KEY=$(get_build_var BOARD_AVB_KEY_PATH)
|
||||
AVB_ALG=$(get_build_var BOARD_AVB_ALGORITHM)
|
||||
echo "BOARD_AVB_KEY_PATH=$AVB_KEY"
|
||||
echo "BOARD_AVB_ALGORITHM=$AVB_ALG"
|
||||
case "$AVB_KEY" in
|
||||
*vendor/sunfish-a16/certs/avb.pem) ;;
|
||||
*) echo "FAIL: AVB key not project certs/avb.pem ($AVB_KEY)" >&2; exit 1 ;;
|
||||
esac
|
||||
[[ "$AVB_ALG" == "SHA256_RSA4096" ]] || { echo "FAIL: AVB alg=$AVB_ALG" >&2; exit 1; }
|
||||
|
||||
echo "=== mka bacon $(date -Is) signing=$PRODUCT_DEFAULT_DEV_CERTIFICATE ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
# Post-ship gates: drop pipefail. Early-exit awk/head + large pipes otherwise
|
||||
# yield exit=141 (SIGPIPE) and skip Magisk/AVB/US-S4 checks.
|
||||
set +o pipefail
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve-hi-releasekeys
|
||||
mkdir -p "$DEST"
|
||||
|
||||
# Ship pair = target_files IMAGES (Magisk boot + matching vbmeta). OUT/*.img can be
|
||||
# stock make images that do NOT match the OTA payload — do not prefer those.
|
||||
TF_IMG=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -type d -path '*/IMAGES' 2>/dev/null | head -1)
|
||||
[[ -n "${TF_IMG:-}" && -d "$TF_IMG" ]] || { echo "FAIL: missing target_files IMAGES" >&2; exit 1; }
|
||||
TF_IMG=$(readlink -f "$TF_IMG")
|
||||
for f in boot.img vbmeta.img vbmeta_system.img dtbo.img; do
|
||||
[[ -f "$TF_IMG/$f" ]] || { echo "FAIL: missing $TF_IMG/$f" >&2; exit 1; }
|
||||
cp -v "$TF_IMG/$f" "$DEST/"
|
||||
done
|
||||
# Large partition images: hardlink into DEST so verify_image stays repeatable
|
||||
# after OUT is cleaned (same FS). Fallback: absolute symlink, then full copy.
|
||||
for f in vendor.img product.img system.img system_ext.img; do
|
||||
[[ -f "$TF_IMG/$f" ]] || continue
|
||||
rm -f "$DEST/$f"
|
||||
if cp -al "$TF_IMG/$f" "$DEST/$f" 2>/dev/null; then
|
||||
echo "hardlink $f -> $DEST/$f"
|
||||
elif ln -sfn "$TF_IMG/$f" "$DEST/$f"; then
|
||||
echo "symlink-abs $f -> $TF_IMG/$f"
|
||||
else
|
||||
cp -v "$TF_IMG/$f" "$DEST/$f"
|
||||
fi
|
||||
done
|
||||
# Keep make OUT boot for forensics only (often stock / non-Magisk).
|
||||
cp -v "$PROD/boot.img" "$DEST/boot-make-out.img" 2>/dev/null || true
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL*.zip "$DEST/" 2>/dev/null || \
|
||||
cp -v "$PROD"/lineage-*.zip "$DEST/" 2>/dev/null || true
|
||||
|
||||
# Publish AXP Resurection Pro ship name (hardlink/copy). Lineage bacon.mk still
|
||||
# emits lineage-*.zip; do not rebuild solely to rename.
|
||||
ZIP_LINEAGE=$(ls "$DEST"/lineage-*.zip 2>/dev/null | head -1 || true)
|
||||
if [[ -n "${ZIP_LINEAGE:-}" ]]; then
|
||||
# lineage-23.2-YYYYMMDD-UNOFFICIAL[-AXP-Resurection[-Pro]]-sunfish.zip
|
||||
# → AXP-Resurection-Pro-23.2-YYYYMMDD-sunfish.zip
|
||||
ZIP_BASE=$(basename "$ZIP_LINEAGE")
|
||||
ZIP_AXP=$(echo "$ZIP_BASE" | sed -E \
|
||||
's/^lineage-([0-9]+\.[0-9]+)-([0-9]{8})(-[0-9]{6})?-UNOFFICIAL(-AXP-Resurection(-Pro)?)?-sunfish\.zip$/AXP-Resurection-Pro-\1-\2\3-sunfish.zip/')
|
||||
if [[ "$ZIP_AXP" == "$ZIP_BASE" ]]; then
|
||||
ZIP_AXP="AXP-Resurection-Pro-${ZIP_BASE#lineage-}"
|
||||
fi
|
||||
ln -f "$ZIP_LINEAGE" "$DEST/$ZIP_AXP" 2>/dev/null || cp -v "$ZIP_LINEAGE" "$DEST/$ZIP_AXP"
|
||||
echo "ship_zip=$ZIP_AXP (from $ZIP_BASE)"
|
||||
fi
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
fi
|
||||
|
||||
# Avoid pipefail SIGPIPE: never `strings | grep` on large boot.img.
|
||||
_BOOT_STR=$(mktemp)
|
||||
strings "$DEST/boot.img" >"$_BOOT_STR"
|
||||
if grep -iE 'KernelSU|CONFIG_KSU_SUSFS' "$_BOOT_STR" >/dev/null; then
|
||||
rm -f "$_BOOT_STR"
|
||||
echo "FAIL: KernelSU in boot" >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$_BOOT_STR"
|
||||
|
||||
# Magisk preroot must be present on the ship boot (magiskboot cpio test: 0=stock, 1=Magisk).
|
||||
MAGISKBOOT="$ANDROID_BUILD_TOP/out/.magisk/magiskboot"
|
||||
[[ -x "$MAGISKBOOT" ]] || { echo "FAIL: missing $MAGISKBOOT" >&2; exit 1; }
|
||||
MB_TMP=$(mktemp -d)
|
||||
cp "$DEST/boot.img" "$MB_TMP/boot.img"
|
||||
set +e
|
||||
( cd "$MB_TMP" && "$MAGISKBOOT" unpack boot.img >/dev/null )
|
||||
( cd "$MB_TMP" && "$MAGISKBOOT" cpio ramdisk.cpio test )
|
||||
MB_EC=$?
|
||||
set -e
|
||||
rm -rf "$MB_TMP"
|
||||
# magiskboot cpio test: 0=stock, non-zero (usually 1) = Magisk present
|
||||
[[ "$MB_EC" -ne 0 ]] || { echo "FAIL: ship boot is stock (magiskboot cpio test=$MB_EC); expected Magisk" >&2; exit 1; }
|
||||
echo "magiskboot_cpio_test=$MB_EC (non-zero => Magisk present)"
|
||||
|
||||
ZIP=$(ls "$DEST"/lineage-*-UNOFFICIAL*.zip 2>/dev/null | head -1 || true)
|
||||
if [[ -n "$ZIP" ]]; then
|
||||
unzip -p "$ZIP" META-INF/com/android/otacert 2>/dev/null | openssl x509 -noout -subject 2>/dev/null \
|
||||
| tee "$DEST/otacert-subject.txt" || true
|
||||
if grep -qi 'Test Keys\|Android\|AOSP' "$DEST/otacert-subject.txt" 2>/dev/null; then
|
||||
echo "WARN: otacert subject looks like test/AOSP — check keys wire" | tee -a "$DEST/README.txt"
|
||||
fi
|
||||
fi
|
||||
|
||||
# US-S3 artifact gates — fail closed (signing infrastructure; NOT runtime AVB harden).
|
||||
# flags=3 => HASHTREE_DISABLED|VERIFICATION_DISABLED (libavb); Magisk-friendly unlocked LAB.
|
||||
AVBTOOL="$ANDROID_BUILD_TOP/out/host/linux-x86/bin/avbtool"
|
||||
AVB_PEM="$ANDROID_BUILD_TOP/vendor/sunfish-a16/certs/avb.pem"
|
||||
AVB_PKMD="$ANDROID_BUILD_TOP/vendor/sunfish-a16/certs/avb_pkmd.bin"
|
||||
[[ -x "$AVBTOOL" ]] || { echo "FAIL: missing $AVBTOOL" >&2; exit 1; }
|
||||
[[ -f "$DEST/vbmeta.img" ]] || { echo "FAIL: missing $DEST/vbmeta.img" >&2; exit 1; }
|
||||
[[ -f "$DEST/boot.img" ]] || { echo "FAIL: missing $DEST/boot.img" >&2; exit 1; }
|
||||
[[ -f "$AVB_PEM" ]] || { echo "FAIL: missing $AVB_PEM" >&2; exit 1; }
|
||||
if [[ ! -f "$AVB_PKMD" ]]; then
|
||||
"$AVBTOOL" extract_public_key --key "$AVB_PEM" --output "$AVB_PKMD"
|
||||
fi
|
||||
|
||||
"$AVBTOOL" info_image --image "$DEST/vbmeta.img" | tee "$DEST/vbmeta-info.txt"
|
||||
EXP=$(sha1sum "$AVB_PKMD" | awk '{print $1}')
|
||||
GOT=$(awk '/^Public key \(sha1\):/{print $NF; exit}' "$DEST/vbmeta-info.txt")
|
||||
FLAGS=$(awk '/^Flags:/{print $2; exit}' "$DEST/vbmeta-info.txt")
|
||||
echo "avb_pubkey_sha1 artifact=$GOT project=$EXP flags=$FLAGS"
|
||||
[[ -n "$GOT" ]] || { echo "FAIL: could not parse vbmeta public key sha1" >&2; exit 1; }
|
||||
[[ "$GOT" == "$EXP" ]] || { echo "FAIL: vbmeta pubkey != project avb_pkmd.bin" >&2; exit 1; }
|
||||
[[ "$FLAGS" == "3" ]] || { echo "FAIL: expected vbmeta Flags 3 (Magisk track), got '$FLAGS'" >&2; exit 1; }
|
||||
|
||||
# Cryptographic check against TF sibling images in $DEST (hardlinked/copied).
|
||||
# Magisk boot footer is Algorithm NONE — chain trust is top-level vbmeta + project key.
|
||||
# Does NOT mean the device will enforce AVB at boot (flags 3 disables that).
|
||||
set +e
|
||||
(
|
||||
cd "$DEST"
|
||||
"$AVBTOOL" verify_image --image vbmeta.img --key "$AVB_PEM" \
|
||||
--expected_chain_partition "vbmeta_system:1:$AVB_PKMD"
|
||||
) >"$DEST/vbmeta-verify.txt" 2>&1
|
||||
ec_v=$?
|
||||
set -e
|
||||
cat "$DEST/vbmeta-verify.txt"
|
||||
[[ "$ec_v" -eq 0 ]] || { echo "FAIL: avbtool verify_image vbmeta.img (TF Magisk boot chain)" >&2; exit 1; }
|
||||
|
||||
set +e
|
||||
(
|
||||
cd "$DEST"
|
||||
"$AVBTOOL" verify_image --image vbmeta_system.img --key "$AVB_PEM"
|
||||
) >"$DEST/vbmeta_system-verify.txt" 2>&1
|
||||
ec_s=$?
|
||||
set -e
|
||||
cat "$DEST/vbmeta_system-verify.txt"
|
||||
[[ "$ec_s" -eq 0 ]] || { echo "FAIL: avbtool verify_image vbmeta_system.img" >&2; exit 1; }
|
||||
|
||||
# Boot footer integrity (unsigned Magisk footer is OK); do not require --key match.
|
||||
set +e
|
||||
(
|
||||
cd "$DEST"
|
||||
"$AVBTOOL" verify_image --image boot.img
|
||||
) >"$DEST/boot-verify.txt" 2>&1
|
||||
ec_b=$?
|
||||
set -e
|
||||
cat "$DEST/boot-verify.txt"
|
||||
[[ "$ec_b" -eq 0 ]] || { echo "FAIL: avbtool verify_image boot.img footer/hash" >&2; exit 1; }
|
||||
|
||||
# US-S4-1 — AXP PRO product surface (binaries gone; init.openssh.rc kept).
|
||||
SIMG="$ANDROID_BUILD_TOP/out/host/linux-x86/bin/simg2img"
|
||||
[[ -x "$SIMG" ]] || { echo "FAIL: missing $SIMG" >&2; exit 1; }
|
||||
[[ -e "$DEST/product.img" ]] || { echo "FAIL: missing $DEST/product.img" >&2; exit 1; }
|
||||
PROD_RAW=$(mktemp /tmp/axp-product-XXXX.img)
|
||||
"$SIMG" "$DEST/product.img" "$PROD_RAW"
|
||||
for p in /bin/sshd /bin/ssh /bin/scp /bin/sftp /bin/rsync /bin/start-ssh; do
|
||||
if debugfs -R "stat $p" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
|
||||
rm -f "$PROD_RAW"
|
||||
echo "FAIL: US-S4 expected absent $p on product.img" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if ! debugfs -R "stat /etc/init/init.openssh.rc" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
|
||||
rm -f "$PROD_RAW"
|
||||
echo "FAIL: US-S4 expected init.openssh.rc present (AXP surface)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "US-S4-1 product surface OK (no ssh/rsync bins; init.openssh.rc present)"
|
||||
|
||||
# US-S4-2 — AXP PRO: no Jelly / Gallery2 *apps* on product (Fossify stays).
|
||||
# Note: LOCAL_OVERRIDES removes Gallery2.apk but stale JNI symlink dirs under
|
||||
# product/app/Gallery2/lib can remain from older out/ — gate on the APK.
|
||||
for p in /app/Jelly/Jelly.apk /app/Gallery2/Gallery2.apk; do
|
||||
if debugfs -R "stat $p" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
|
||||
rm -f "$PROD_RAW"
|
||||
echo "FAIL: US-S4-2 expected absent $p on product.img" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# Directory-only Gallery2 leftover (jni symlinks) is not a shipped app — warn.
|
||||
if debugfs -R "stat /app/Gallery2" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
|
||||
echo "WARN: US-S4-2 /app/Gallery2 dir still present (likely stale jni symlinks; no APK)"
|
||||
fi
|
||||
if ! debugfs -R "stat /app/FossifyGallery" "$PROD_RAW" 2>&1 | grep -q 'Inode:'; then
|
||||
rm -f "$PROD_RAW"
|
||||
echo "FAIL: US-S4-2 expected FossifyGallery present" >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$PROD_RAW"
|
||||
echo "US-S4-2 product surface OK (no Jelly/Gallery2 APK; FossifyGallery present)"
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "list_clean=$LIST_CLEAN (429)"
|
||||
echo "list_hi=batch1+2+3"
|
||||
echo "hardening=Stage1+combo4+FORTIFY + CVE-clean + hi-batch1+2+3 + US-S4-1-no-openssh + US-S4-2-no-jelly-gallery2 + US-S5-1-yama-slabrand"
|
||||
echo "branding=AXP-Resurection-Pro"
|
||||
echo "signing=$PRODUCT_DEFAULT_DEV_CERTIFICATE"
|
||||
echo "avb_infra=$AVB_KEY alg=$AVB_ALG flags=3 (HASHTREE_DISABLED|VERIFICATION_DISABLED)"
|
||||
echo "avb_runtime_enforce=no (unlocked Magisk track; not AVB-hardened boot)"
|
||||
echo "avb_pubkey_sha1=$GOT"
|
||||
echo "magiskboot_cpio_test=$MB_EC"
|
||||
echo "ship_images=target_files/IMAGES (not OUT make images)"
|
||||
echo "ship_zip_brand=AXP-Resurection-Pro-*-sunfish.zip (sibling of lineage-*.zip; not slim)"
|
||||
echo "flash=sideload AXP-Resurection-Pro zip (or lineage twin); boot-only insufficient"
|
||||
echo "recover=20261002T085915Z-axp-stage1-combo4-cve-hi-releasekeys"
|
||||
echo "bootloader_lock=wont"
|
||||
echo "oem_unlock=leave_enabled_escape_hatch_not_guaranteed_recovery"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make-out.img vbmeta.img vbmeta_system.img dtbo.img \
|
||||
lineage-*.zip AXP-Resurection-Pro-*.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "FLASH_READY $DEST"
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
exit 0
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Stage1 + combo4+FORTIFY + CVE-strict (AXP cve_checker allowlist).
|
||||
# Intentionally test-keys (isolate CVE vs signing). Flash only after LAB boot/Wi‑Fi.
|
||||
# Do NOT flash old 20260918 *-axp-kh-cve/full (pre-FORTIFY hang).
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
# Isolate: no release keys on this CVE iteration
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4-cve.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4-cve $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
KH=vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
chmod +x "$KH"/apply_stage1_combo4.sh "$KH"/apply_cve_strict.sh \
|
||||
"$KH"/apply_stage1_combo4_cve.sh "$KH"/apply_stage1.sh \
|
||||
"$KH"/apply_combo4_fortify.sh 2>/dev/null || true
|
||||
bash "$KH/apply_stage1_combo4_cve.sh" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: $DEF still enables KernelSU" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
if ! grep -q "^CONFIG_${k}=y" "$DEF"; then
|
||||
echo "FAIL: missing CONFIG_${k}=y" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
echo "OK: Stage1 + combo4+FORTIFY + CVE markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
echo "OK: cleared prior Image for kernel rebuild"
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
if ! "$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM; then
|
||||
echo "FAIL: Phonesky missing USE_EXACT_ALARM" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: Phonesky has USE_EXACT_ALARM"
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
# Force test-keys for this CVE pack (signing is a later stage)
|
||||
unset PRODUCT_DEFAULT_DEV_CERTIFICATE || true
|
||||
echo "OK: signing=test-keys (CVE isolation)"
|
||||
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-cve
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
echo "boot_source=target_files_IMAGES"
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
echo "WARN: no TF IMAGES/boot.img — using Make boot"
|
||||
fi
|
||||
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
if [ -n "$KCRC" ] && [ -n "$MCRC" ] && [ "$KCRC" = "$MCRC" ]; then
|
||||
echo "OK: wlan.ko CRC matches kernel (Wi-Fi pack coherent)"
|
||||
else
|
||||
echo "WARN: wlan.ko CRC mismatch or unreadable — check before flash"
|
||||
fi
|
||||
fi
|
||||
|
||||
MB=out/.magisk/magiskboot
|
||||
if [ -x "$MB" ]; then
|
||||
rm -rf "$DEST/boot-check" && mkdir -p "$DEST/boot-check"
|
||||
if ! "$MB" unpack "$DEST/boot.img" "$DEST/boot-check" >/dev/null 2>&1; then
|
||||
echo "WARN: magiskboot unpack failed (host SIGILL flake possible)"
|
||||
fi
|
||||
fi
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU strings in boot.img" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: no KernelSU strings in boot.img"
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "kernel_base=$BASE"
|
||||
echo "hardening=Stage1 + combo4+clang-fortify + CVE-strict (~503 AXP allowlist, denylist skipped)"
|
||||
echo "magisk=preroot EXTENDROM-class v30.7"
|
||||
echo "signing=test-keys (CVE isolation; release-keys later)"
|
||||
echo "flash=recovery wipe + sideload zip + reboot system"
|
||||
echo "note=do not flash 20260918 kh-cve/kh-full (pre-FORTIFY hang)"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
Executable
+176
@@ -0,0 +1,176 @@
|
||||
#!/bin/bash
|
||||
# 009 bacon — Magisk preroot + Stage1 Graphene/AH + combo4 Clang FORTIFY.
|
||||
# Full zip so vendor modules match kernel (Wi-Fi). LAB flash only after gates.
|
||||
set -e
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build
|
||||
export CCACHE_DIR=/srv/rom/ccache
|
||||
export USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1
|
||||
export MAGISK_APK=/srv/rom/prebuilts/magisk/Magisk-v30.7.apk
|
||||
|
||||
LOGDIR=/srv/rom/logs/009-build
|
||||
mkdir -p "$LOGDIR"
|
||||
LOG=$LOGDIR/bacon-axp-stage1-combo4.log
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "=== START 009-bacon-axp-stage1-combo4 $(date -Is) ==="
|
||||
|
||||
LIVE=kernel/google/msm-4.14
|
||||
BASE=28f9290ae067
|
||||
test -d "$LIVE"
|
||||
|
||||
echo "=== reset kernel @ $BASE ==="
|
||||
git -C "$LIVE" reset --hard "$BASE"
|
||||
git -C "$LIVE" clean -fdq
|
||||
|
||||
APPLY=vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1_combo4.sh
|
||||
test -x "$APPLY" || chmod +x "$APPLY"
|
||||
bash "$APPLY" "$LIVE"
|
||||
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
if grep -qE "^CONFIG_KSU.*=y" "$DEF"; then
|
||||
echo "FAIL: $DEF still enables KernelSU" >&2
|
||||
exit 1
|
||||
fi
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED; do
|
||||
if ! grep -q "^CONFIG_${k}=y" "$DEF"; then
|
||||
echo "FAIL: missing CONFIG_${k}=y" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
grep -q "ret = __underlying_strlen(q);" "$LIVE/include/linux/string.h"
|
||||
# Stage1 marker (Deny USB / sysctl)
|
||||
if ! grep -q "deny_new_usb" "$LIVE/kernel/sysctl.c" \
|
||||
&& ! grep -qE "deny_new_usb|CONFIG_DENY_NEW_USB|usb_device_authorization" \
|
||||
"$LIVE/drivers/usb/core/hub.c"; then
|
||||
echo "FAIL: Stage1 Deny_USB markers missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: Stage1 + combo4+FORTIFY markers present"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4 \
|
||||
out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image \
|
||||
out/target/product/sunfish/kernel
|
||||
echo "OK: cleared prior Image for kernel rebuild"
|
||||
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_disable_user_apps.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_private_dns_providers.py
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_connectivity_check.py
|
||||
|
||||
PH=/srv/rom/src/lineage/vendor/sunfish-a16/prebuilt/Phonesky.apk
|
||||
test -e "$PH"
|
||||
AAPT=/srv/rom/src/lineage/prebuilts/sdk/tools/linux/bin/aapt
|
||||
if ! "$AAPT" dump permissions "$PH" 2>/dev/null | grep -q USE_EXACT_ALARM; then
|
||||
echo "FAIL: Phonesky missing USE_EXACT_ALARM" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: Phonesky has USE_EXACT_ALARM"
|
||||
|
||||
MAGISK_STAGE_DIR=/srv/rom/src/lineage/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
test -f out/.magisk/READY
|
||||
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/releasetools_common
|
||||
rm -rf out/soong/.intermediates/build/make/tools/releasetools/add_img_to_target_files
|
||||
rm -rf out/target/product/sunfish/obj/PACKAGING/target_files_intermediates
|
||||
rm -f out/target/product/sunfish/lineage-*.zip \
|
||||
out/target/product/sunfish/boot.img \
|
||||
out/target/product/sunfish/system/priv-app/Phonesky/Phonesky.apk
|
||||
touch frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
|
||||
|
||||
set +u
|
||||
# shellcheck disable=SC1091
|
||||
source build/envsetup.sh
|
||||
set -e
|
||||
|
||||
# US-S2: project release keys when present (Gate G). Fallback = AOSP test-keys.
|
||||
CERT_DIR="${ANDROID_CERTS_DIR:-$HOME/.android-certs}"
|
||||
if [[ -f "$CERT_DIR/releasekey.pk8" && -f "$CERT_DIR/releasekey.x509.pem" ]]; then
|
||||
export PRODUCT_DEFAULT_DEV_CERTIFICATE="$CERT_DIR/releasekey"
|
||||
echo "OK: PRODUCT_DEFAULT_DEV_CERTIFICATE=$PRODUCT_DEFAULT_DEV_CERTIFICATE"
|
||||
else
|
||||
echo "WARN: no $CERT_DIR/releasekey — building with AOSP test-keys"
|
||||
fi
|
||||
|
||||
breakfast sunfish userdebug
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
echo "=== mka bacon $(date -Is) ==="
|
||||
set -o pipefail
|
||||
mka bacon -j8
|
||||
ec=${PIPESTATUS[0]}
|
||||
echo "bacon_exit=$ec $(date -Is)"
|
||||
[ "$ec" -eq 0 ] || exit "$ec"
|
||||
|
||||
PROD=out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
if [[ -n "${PRODUCT_DEFAULT_DEV_CERTIFICATE:-}" ]]; then
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4-releasekeys
|
||||
else
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-axp-stage1-combo4
|
||||
fi
|
||||
mkdir -p "$DEST"
|
||||
|
||||
TF_BOOT=$(find "$PROD/obj/PACKAGING/target_files_intermediates" -path "*/IMAGES/boot.img" 2>/dev/null | head -1)
|
||||
MAKE_BOOT=$PROD/boot.img
|
||||
if [ -n "${TF_BOOT:-}" ] && [ -f "$TF_BOOT" ]; then
|
||||
cp -v "$TF_BOOT" "$DEST/boot.img"
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot-make.img" 2>/dev/null || true
|
||||
echo "boot_source=target_files_IMAGES"
|
||||
else
|
||||
cp -v "$MAKE_BOOT" "$DEST/boot.img"
|
||||
echo "WARN: no TF IMAGES/boot.img — using Make boot"
|
||||
fi
|
||||
|
||||
cp -v "$PROD"/lineage-*-UNOFFICIAL-sunfish.zip "$DEST/" 2>/dev/null || true
|
||||
for f in vbmeta.img dtbo.img; do
|
||||
[ -f "$PROD/$f" ] && cp -v "$PROD/$f" "$DEST/"
|
||||
done
|
||||
|
||||
# Module CRC sanity vs kernel (Wi-Fi)
|
||||
WLAN=$PROD/vendor/lib/modules/wlan.ko
|
||||
if [ -f "$WLAN" ] && [ -f "$PROD/obj/KERNEL_OBJ/Module.symvers" ]; then
|
||||
KCRC=$(awk '$2=="kmalloc_caches"{print $1; exit}' "$PROD/obj/KERNEL_OBJ/Module.symvers")
|
||||
MCRC=$(/sbin/modprobe --dump-modversions "$WLAN" 2>/dev/null | awk '$2=="kmalloc_caches"{print $1; exit}')
|
||||
echo "wlan kmalloc_caches kernel=$KCRC module=$MCRC"
|
||||
if [ -n "$KCRC" ] && [ -n "$MCRC" ] && [ "$KCRC" = "$MCRC" ]; then
|
||||
echo "OK: wlan.ko CRC matches kernel (Wi-Fi pack coherent)"
|
||||
else
|
||||
echo "WARN: wlan.ko CRC mismatch or unreadable — check before flash"
|
||||
fi
|
||||
fi
|
||||
|
||||
MB=out/.magisk/magiskboot
|
||||
if [ -x "$MB" ]; then
|
||||
rm -rf "$DEST/boot-check" && mkdir -p "$DEST/boot-check"
|
||||
if ! "$MB" unpack "$DEST/boot.img" "$DEST/boot-check" >/dev/null 2>&1; then
|
||||
echo "WARN: magiskboot unpack failed (host SIGILL flake possible)"
|
||||
fi
|
||||
fi
|
||||
if strings "$DEST/boot.img" | grep -qiE 'KernelSU|CONFIG_KSU_SUSFS'; then
|
||||
echo "FAIL: KernelSU strings in boot.img" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: no KernelSU strings in boot.img"
|
||||
|
||||
{
|
||||
echo "artifact=$DEST"
|
||||
echo "kernel_base=$BASE"
|
||||
echo "hardening=Stage1 Graphene/AH + combo4+clang-fortify (nested __underlying_strlen)"
|
||||
echo "magisk=preroot EXTENDROM-class v30.7"
|
||||
echo "signing=${PRODUCT_DEFAULT_DEV_CERTIFICATE:-test-keys}"
|
||||
echo "flash=recovery wipe + sideload zip + reboot system (do NOT flash boot onto other slot alone)"
|
||||
date -u +"built=%Y-%m-%dT%H:%M:%SZ"
|
||||
} | tee "$DEST/README.txt"
|
||||
|
||||
(cd "$DEST" && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null || true) \
|
||||
| tee "$DEST/SHA256SUMS"
|
||||
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
Executable
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
# Usage: 009-bisect-ksync-one.sh <name> [CONFIG_FOO] ...
|
||||
# Rebuilds kernel with optional CONFIG_=y extras, injects into GOODMAKE.
|
||||
set -eo pipefail
|
||||
NAME=${1:?name}; shift
|
||||
cd /srv/rom/src/lineage
|
||||
export HOME=/home/android-build CCACHE_DIR=/srv/rom/ccache USE_CCACHE=1
|
||||
export PATH=/home/android-build/bin:/usr/local/bin:/usr/bin:/bin:$PATH
|
||||
export ANDROID_BUILD_TOP=/srv/rom/src/lineage
|
||||
unset OUT_DIR || true
|
||||
LIVE=kernel/google/msm-4.14
|
||||
DEF=$LIVE/arch/arm64/configs/sunfish_defconfig
|
||||
GOOD=/srv/rom/artifacts/009-axp-los23-port/20260918T143547Z-axp-full/boot-make.img
|
||||
MB=$(find /srv/rom/prebuilts/magisk -name magiskboot | head -1)
|
||||
|
||||
echo "=== ksync-$NAME START $(date -Is) configs=[$*] ==="
|
||||
git -C "$LIVE" reset --hard 28f9290ae067
|
||||
git -C "$LIVE" clean -fd
|
||||
sed -i '/CONFIG_KSU/d' "$DEF"
|
||||
echo '# CONFIG_KSU is not set' >> "$DEF"
|
||||
for k in FORTIFY_SOURCE INIT_ON_ALLOC_DEFAULT_ON INIT_ON_FREE_DEFAULT_ON SECURITY_DMESG_RESTRICT SLAB_FREELIST_HARDENED SLAB_HARDENED; do
|
||||
sed -i "/CONFIG_${k}/d" "$DEF"
|
||||
done
|
||||
for cfg in "$@"; do
|
||||
echo "${cfg}=y" >> "$DEF"
|
||||
echo "enable $cfg"
|
||||
done
|
||||
|
||||
# Clang FORTIFY port (no BUG stubs). See docs/009-fortify-clang-port.md
|
||||
case " $* " in
|
||||
*" CONFIG_FORTIFY_SOURCE "*)
|
||||
python3 /srv/rom/artifacts/009-axp-los23-port/scripts/apply_fortify_clang.py "$LIVE"
|
||||
# Driver bounds for Clang/LTO fortify false-path link (docs/009-fortify-pos0-link-failure-20260927.md)
|
||||
patch -p1 --forward --batch -d "$LIVE" < /srv/rom/artifacts/009-axp-los23-port/scripts/0001-driver-bounds-rtac-fils.patch
|
||||
if [ "${FORTIFY_DIAG:-0}" = 1 ]; then
|
||||
python3 /srv/rom/artifacts/009-axp-los23-port/scripts/apply_fortify_diag.py "$LIVE"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Plaintext panic mirror into alt ramoops (no FORTIFY). See docs/009-fortify-diag-capture-plan.md
|
||||
# Also applied via FORTIFY_DIAG above when building fortify-diag.
|
||||
if [ "${PSTORE_ALT_PLAIN:-0}" = 1 ]; then
|
||||
python3 /srv/rom/artifacts/009-axp-los23-port/scripts/apply_fortify_diag.py "$LIVE"
|
||||
fi
|
||||
|
||||
# FORTIFY stubs DISABLED by default (see docs/009-fortify-clang-port.md).
|
||||
# Set ALLOW_FORTIFY_BUG_STUBS=1 only for archaeology — not a valid port.
|
||||
if [ "${ALLOW_FORTIFY_BUG_STUBS:-0}" = 1 ]; then
|
||||
case " $* " in *" CONFIG_FORTIFY_SOURCE "*)
|
||||
echo 'WARN: injecting BUG() fortify stubs (ALLOW_FORTIFY_BUG_STUBS=1)'
|
||||
python3 - <<'PY2'
|
||||
from pathlib import Path
|
||||
import re
|
||||
p = Path("kernel/google/msm-4.14/lib/string.c")
|
||||
t = p.read_text()
|
||||
if "EXPORT_SYMBOL(__read_overflow)" not in t:
|
||||
m = re.search(r"void fortify_panic\(const char \*name\).*?EXPORT_SYMBOL\(fortify_panic\);", t, re.S)
|
||||
assert m, 'fortify_panic marker missing'
|
||||
stub = m.group(0) + """
|
||||
|
||||
void __read_overflow(void) { BUG(); }
|
||||
EXPORT_SYMBOL(__read_overflow);
|
||||
void __read_overflow2(void) { BUG(); }
|
||||
EXPORT_SYMBOL(__read_overflow2);
|
||||
void __read_overflow3(void) { BUG(); }
|
||||
EXPORT_SYMBOL(__read_overflow3);
|
||||
void __write_overflow(void) { BUG(); }
|
||||
EXPORT_SYMBOL(__write_overflow);
|
||||
"""
|
||||
p.write_text(t[:m.start()] + stub + t[m.end():])
|
||||
PY2
|
||||
;; esac
|
||||
fi
|
||||
|
||||
set +u; source build/envsetup.sh; set -e
|
||||
breakfast sunfish userdebug
|
||||
echo "TARGET_RELEASE=${TARGET_RELEASE:-unset}"
|
||||
test "${TARGET_RELEASE:-}" = "bp4a"
|
||||
|
||||
rm -f out/target/product/sunfish/obj/KERNEL_OBJ/arch/arm64/boot/Image.lz4
|
||||
rm -f out/target/product/sunfish/boot.img
|
||||
mka bootimage -j8
|
||||
|
||||
PROD=/srv/rom/src/lineage/out/target/product/sunfish
|
||||
BID=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
DEST=/srv/rom/artifacts/009-axp-los23-port/${BID}-bisect-ksync-${NAME}
|
||||
mkdir -p "$DEST"
|
||||
cp -v "$PROD/boot.img" "$DEST/boot-make-native.img"
|
||||
|
||||
WORK=$DEST/work
|
||||
rm -rf "$WORK"; mkdir -p "$WORK/good" "$WORK/new" "$WORK/check"
|
||||
(cd "$WORK/good" && "$MB" unpack "$GOOD")
|
||||
(cd "$WORK/new" && "$MB" unpack "$PROD/boot.img")
|
||||
cp -f "$WORK/new/kernel" "$WORK/good/kernel"
|
||||
(cd "$WORK/good" && "$MB" repack "$GOOD" "$DEST/boot-make.img")
|
||||
(cd "$WORK/check" && "$MB" unpack "$DEST/boot-make.img" >/dev/null && "$MB" cpio ramdisk.cpio extract)
|
||||
echo "=== VERIFY $NAME ==="
|
||||
grep -E 'security_patch|sdk_full' "$WORK/check/prop.default" | sort -u
|
||||
# Prefer header from first successful unpack (WORK/check); do not ||true a SIGILL unpack.
|
||||
if [[ -f "$WORK/check/kernel" ]]; then
|
||||
"$MB" unpack "$DEST/boot-make.img" >"$DEST/unpack-hdr.txt" 2>&1 || \
|
||||
echo "WARN: magiskboot header unpack failed (host SIGILL?); kernel already verified via WORK/check" | tee -a "$DEST/unpack-hdr.txt"
|
||||
else
|
||||
"$MB" unpack "$DEST/boot-make.img" >"$DEST/unpack-hdr.txt" 2>&1
|
||||
fi
|
||||
grep -E 'OS_PATCH|KERNEL_SZ|KERNEL_FMT' "$DEST/unpack-hdr.txt" || true
|
||||
# ikconfig spot-check
|
||||
/srv/rom/src/lineage/kernel/google/msm-4.14/scripts/extract-ikconfig "$WORK/check/kernel" 2>/dev/null \
|
||||
| grep -E 'CONFIG_(SECURITY_DMESG_RESTRICT|SLAB_FREELIST_HARDENED|FORTIFY_SOURCE|INIT_ON_ALLOC)=' || true
|
||||
sha256sum "$DEST/boot-make.img" "$DEST/boot-make-native.img" | tee "$DEST/SHA256SUMS"
|
||||
printf '%s\n' "ksync bisect: $NAME" "configs: $*" "Flash boot-make.img only (GOODMAKE ramdisk)." > "$DEST/README.txt"
|
||||
echo "=== DONE $DEST $(date -Is) ==="
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# Channel-proof build (no FORTIFY): diag v4 early_ioremap + ioremap after mm_init.
|
||||
# Validate (docs/009-fortify-diag-capture-plan.md v4 — mid/late only):
|
||||
# 0) Wipe first 4K of access-ramoops or fresh attempt id
|
||||
# 1) Flash boot-make.img, boot, adb root
|
||||
# 2) Milestone: strings | grep AXPDIAG0 (early_map / perm_map / mm_init)
|
||||
# 3) ONLY SysRq-c (no SysRq-x)
|
||||
# 4) Recover combo4 — complete AXPDIAG1,C,<attempt>,0x...,sysrq-c
|
||||
# Does NOT prove pre-early_map FORTIFY coverage. Do not flash v3.
|
||||
set -euo pipefail
|
||||
export PSTORE_ALT_PLAIN=1
|
||||
exec /srv/rom/artifacts/009-axp-los23-port/scripts/009-bisect-ksync-one.sh \
|
||||
pstore-alt-plain
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Server-only diagnostic build. Uses its own sources/output; never resets LIVE.
|
||||
# Usage: bash this-script ROOT <family>
|
||||
# family: see 009-fortify-select-family.py GROUPS
|
||||
set -euo pipefail
|
||||
RUN=${1:?isolated root required}
|
||||
FAMILY=${2:?family required}
|
||||
case "$FAMILY" in
|
||||
full|memory|strings|strings-copy|strings-len|\
|
||||
strings-strcpy-strlen|strings-copy-strlen|strings-copy-strnlen|\
|
||||
strings-strlen-restcopy|strings-strlen-ncopy|strings-strlen-cat|\
|
||||
strings-strlen-strncpy|strings-strlen-strlcpy) ;;
|
||||
*) echo "bad family: $FAMILY" >&2; exit 2;;
|
||||
esac
|
||||
test -d "$RUN/inputs"
|
||||
# Subdir name matches family (strings-copy → strings-copy/)
|
||||
test ! -e "$RUN/$FAMILY"
|
||||
TOP=/srv/rom/src/lineage
|
||||
LIVE=$TOP/kernel/google/msm-4.14
|
||||
PIN=28f9290ae067d3e7857126eb6312720dbe9c7c80
|
||||
CLANG=$TOP/prebuilts/clang/host/linux-x86/clang-r563880c
|
||||
BASE=$RUN/$FAMILY
|
||||
SRC=$BASE/src
|
||||
OUT=$BASE/out
|
||||
mkdir -p "$SRC" "$OUT"
|
||||
git -C "$LIVE" archive "$PIN" | tar -x -C "$SRC"
|
||||
python3 "$RUN/inputs/apply_fortify_clang.py" "$SRC"
|
||||
patch -p1 --batch -d "$SRC" < "$RUN/inputs/0001-driver-bounds-rtac-fils.patch"
|
||||
python3 "$RUN/inputs/009-fortify-select-family.py" "$SRC" "$FAMILY"
|
||||
cp "$RUN/inputs/failed-full.config" "$OUT/.config"
|
||||
cp "$OUT/.config" "$BASE/input.config"
|
||||
export PATH="$TOP/prebuilts/tools-lineage/linux-x86/bin:$TOP/prebuilts/build-tools/linux-x86/bin:$CLANG/bin:$TOP/out/host/linux-x86/bin:/usr/bin:/bin"
|
||||
export HIP_PATH=none
|
||||
export PERL5LIB="$TOP/prebuilts/tools-lineage/common/perl-base"
|
||||
export BISON_PKGDATADIR="$TOP/prebuilts/build-tools/common/bison"
|
||||
export KBUILD_BUILD_USER=nobody KBUILD_BUILD_HOST=android-build
|
||||
# An archived patched tree needs the same release suffix as installed modules.
|
||||
export LOCALVERSION=-g28f9290ae067-dirty
|
||||
MAKE=("$TOP/prebuilts/build-tools/linux-x86/bin/make" -j8
|
||||
"HOSTCFLAGS=--sysroot=$TOP/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/sysroot -I$TOP/prebuilts/kernel-build-tools/linux-x86/include"
|
||||
"HOSTLDFLAGS=--sysroot=$TOP/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/sysroot -Wl,-rpath,$TOP/prebuilts/kernel-build-tools/linux-x86/lib64 -L $TOP/prebuilts/kernel-build-tools/linux-x86/lib64 -fuse-ld=lld --rtlib=compiler-rt"
|
||||
LLVM=1 LLVM_IAS=1 "LZ4=$TOP/prebuilts/kernel-build-tools/linux-x86/bin/lz4"
|
||||
"LEX=$TOP/prebuilts/build-tools/linux-x86/bin/flex"
|
||||
"YACC=$TOP/prebuilts/build-tools/linux-x86/bin/bison"
|
||||
"M4=$TOP/prebuilts/build-tools/linux-x86/bin/m4"
|
||||
"PAHOLE=$TOP/prebuilts/kernel-build-tools/linux-x86/bin/pahole"
|
||||
"LIBCLANG_PATH=$CLANG/lib" "DTC_EXT=$TOP/out/host/linux-x86/bin/dtc"
|
||||
-C "$SRC" "O=$OUT" ARCH=arm64 CC=clang LD=ld.lld)
|
||||
"${MAKE[@]}" olddefconfig
|
||||
diff -u "$BASE/input.config" "$OUT/.config" > "$BASE/config.diff" || {
|
||||
cat "$BASE/config.diff"
|
||||
echo 'STOP: unexpected configuration drift' >&2
|
||||
exit 3
|
||||
}
|
||||
"$CLANG/bin/clang" --version > "$BASE/toolchain.txt"
|
||||
printf '%s\n' "$PIN" > "$BASE/source-commit.txt"
|
||||
printf '%q ' "${MAKE[@]}" > "$BASE/make-command.txt"
|
||||
"${MAKE[@]}" Image.lz4 modules
|
||||
cp "$OUT/.config" "$BASE/final.config"
|
||||
test "$(cat "$OUT/include/config/kernel.release")" = '4.14.357-openela-g28f9290ae067-dirty'
|
||||
if "$CLANG/bin/llvm-nm" "$OUT/vmlinux" | grep -Eq ' [Tt] __((read_overflow[23]?)|(write_overflow))$'; then
|
||||
echo 'STOP: forbidden overflow stubs' >&2
|
||||
exit 4
|
||||
fi
|
||||
mkdir "$BASE/pack"
|
||||
cd "$BASE/pack"
|
||||
MB=$(find /srv/rom/prebuilts/magisk -type f -name magiskboot -print -quit)
|
||||
test -n "$MB"
|
||||
GOOD=/srv/rom/artifacts/009-axp-los23-port/20260918T143547Z-axp-full/boot-make.img
|
||||
"$MB" unpack "$GOOD" > "$BASE/good-header.txt" 2>&1
|
||||
sha256sum ramdisk.cpio > "$BASE/ramdisk.sha256"
|
||||
cp "$OUT/arch/arm64/boot/Image" kernel
|
||||
"$MB" repack "$GOOD" "$BASE/boot-make.img"
|
||||
sha256sum "$BASE/boot-make.img" "$OUT/arch/arm64/boot/Image" "$OUT/vmlinux" > "$BASE/SHA256SUMS"
|
||||
printf 'DIAGNOSTIC ONLY: %s family; not full FORTIFY. Requires local unpack/header/kernel verification before LAB use.\n' "$FAMILY" > "$BASE/README.txt"
|
||||
echo "BUILD COMPLETE: $BASE/boot-make.img"
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# After hi-batch3 BOOT_OK: launch release-keys bacon (US-S2) on rom-dev01.
|
||||
# Does not flash RK zip (needs recovery sideload); only starts bacon + status poll helper.
|
||||
set -euo pipefail
|
||||
SSHCFG="${SSHCFG:-/home/aventura/Workspaces/AXP_Resurection/docs/ssh/config}"
|
||||
BATCH3_LOG="${BATCH3_LOG:-/tmp/009-wait-flash-cve-hi-batch3.log}"
|
||||
LOG="${LOG:-/tmp/009-chain-hi3-to-releasekeys.log}"
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "CHAIN start $(date -Is) wait HI_BATCH3_BOOT_OK"
|
||||
for i in $(seq 1 200); do
|
||||
if grep -q 'HI_BATCH3_BOOT_OK' "$BATCH3_LOG" 2>/dev/null; then
|
||||
echo "seen HI_BATCH3_BOOT_OK"
|
||||
break
|
||||
fi
|
||||
if grep -qE 'BACON_FAILED|NOT_BOOTED|BOOT_TIMEOUT|TIMEOUT' "$BATCH3_LOG" 2>/dev/null; then
|
||||
# allow exit=141 path that still boots — only abort on clear fail without OK
|
||||
if ! grep -q 'HI_BATCH3_BOOT_OK' "$BATCH3_LOG" 2>/dev/null; then
|
||||
if grep -qE 'BACON_FAILED|NOT_BOOTED|BOOT_TIMEOUT' "$BATCH3_LOG" 2>/dev/null; then
|
||||
echo CHAIN_ABORT_BATCH3_FAIL
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
sleep 30
|
||||
done
|
||||
grep -q 'HI_BATCH3_BOOT_OK' "$BATCH3_LOG" || { echo CHAIN_TIMEOUT; exit 1; }
|
||||
|
||||
echo "=== launch release-keys bacon $(date -Is) ==="
|
||||
ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 '
|
||||
test -f /home/android-build/.android-certs/releasekey.pk8
|
||||
install -m 0755 /tmp/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh \
|
||||
/srv/rom/artifacts/009-axp-los23-port/scripts/ 2>/dev/null || true
|
||||
# script must already be on host
|
||||
test -x /srv/rom/artifacts/009-axp-los23-port/scripts/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh
|
||||
/srv/rom/artifacts/bin/rom-detach 009-bacon-cve-hi-releasekeys -- \
|
||||
bash /srv/rom/artifacts/009-axp-los23-port/scripts/009-bacon-axp-stage1-combo4-cve-hi-releasekeys.sh
|
||||
sleep 2
|
||||
cat /srv/rom/artifacts/detach-009-bacon-cve-hi-releasekeys.status
|
||||
'
|
||||
echo CHAIN_RK_STARTED
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Diagnostic-only split of the existing Clang FORTIFY port; never a ship patch.
|
||||
|
||||
Apply after apply_fortify_clang.py. Omitted wrappers resolve to the existing
|
||||
unfortified declarations. No overflow stubs or changes to fortify_panic.
|
||||
"""
|
||||
import argparse
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
STRINGS = {"strncpy", "strcat", "strlen", "strnlen", "strlcpy", "strncat", "strcpy"}
|
||||
MEMORY = {"memset", "memcpy", "memmove", "memscan", "memcmp", "memchr", "memchr_inv", "kmemdup"}
|
||||
STRINGS_COPY = {"strcpy", "strncpy", "strlcpy", "strcat", "strncat"}
|
||||
STRINGS_LEN = {"strlen", "strnlen"}
|
||||
|
||||
GROUPS = {
|
||||
"full": STRINGS | MEMORY,
|
||||
"strings": STRINGS,
|
||||
"memory": MEMORY,
|
||||
# Split of failing strings family (2026-09-27 LAB):
|
||||
"strings-copy": STRINGS_COPY,
|
||||
"strings-len": STRINGS_LEN,
|
||||
# Cross products (copy boots, len boots, both fail → interaction):
|
||||
"strings-strcpy-strlen": {"strcpy", "strlen"},
|
||||
"strings-copy-strlen": STRINGS_COPY | {"strlen"},
|
||||
"strings-copy-strnlen": STRINGS_COPY | {"strnlen"},
|
||||
# copy-strlen fails, strcpy-strlen boots → rest of copy + strlen:
|
||||
"strings-strlen-restcopy": {"strlen", "strncpy", "strlcpy", "strcat", "strncat"},
|
||||
"strings-strlen-ncopy": {"strlen", "strncpy", "strlcpy"},
|
||||
"strings-strlen-cat": {"strlen", "strcat", "strncat"},
|
||||
"strings-strlen-strncpy": {"strlen", "strncpy"},
|
||||
"strings-strlen-strlcpy": {"strlen", "strlcpy"},
|
||||
}
|
||||
|
||||
def select(text, family):
|
||||
if "AXP_FORTIFY_DIAGNOSTIC_FAMILY" in text:
|
||||
raise ValueError("Already selected: start from a fresh fully ported header")
|
||||
if "__pass_object_size" not in text or "__overloadable" not in text:
|
||||
raise ValueError("Apply the Clang FORTIFY port first")
|
||||
pattern = re.compile(r"^__FORTIFY_INLINE[^\n]*?\b(\w+)\([^\n]*\)\n\{", re.M)
|
||||
matches = list(pattern.finditer(text))
|
||||
expected = STRINGS | MEMORY
|
||||
names = [m.group(1) for m in matches]
|
||||
if len(names) != len(expected) or set(names) != expected:
|
||||
raise ValueError(f"Unexpected wrapper inventory: {names}")
|
||||
enabled = GROUPS[family]
|
||||
for match in reversed(matches):
|
||||
name = match.group(1)
|
||||
if name in enabled:
|
||||
continue
|
||||
start = match.end() - 1
|
||||
depth = 1
|
||||
end = start + 1
|
||||
while depth:
|
||||
depth += (text[end] == "{") - (text[end] == "}")
|
||||
end += 1
|
||||
text = (
|
||||
text[: match.start()]
|
||||
+ "#if 0 /* diagnostic: other FORTIFY family */\n"
|
||||
+ text[match.start() : end]
|
||||
+ "\n#endif\n"
|
||||
+ text[end:]
|
||||
)
|
||||
return f"/* AXP_FORTIFY_DIAGNOSTIC_FAMILY={family}; NOT FOR SHIP */\n" + text
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("kernel", type=Path)
|
||||
parser.add_argument("family", choices=sorted(GROUPS))
|
||||
args = parser.parse_args()
|
||||
path = args.kernel / "include/linux/string.h"
|
||||
path.write_text(select(path.read_text(), args.family))
|
||||
print(f"DIAGNOSTIC ONLY: FORTIFY family={args.family}; panic behavior unchanged")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generate project Android + AVB signing keys on rom-dev01 only.
|
||||
# Never run this to a path inside a Git working tree that gets committed.
|
||||
set -euo pipefail
|
||||
|
||||
OUT="${ANDROID_CERTS_DIR:-}"
|
||||
if [[ -z "$OUT" ]]; then
|
||||
if [[ -d /srv/rom/secrets && -w /srv/rom/secrets ]]; then
|
||||
OUT=/srv/rom/secrets/android-certs
|
||||
else
|
||||
# Lineage convention; /srv/rom/secrets is often root-owned (750, no group write).
|
||||
OUT="${HOME}/.android-certs"
|
||||
fi
|
||||
fi
|
||||
LINEAGE_TOP="${LINEAGE_TOP:-/srv/rom/src/lineage}"
|
||||
MAKE_KEY="${LINEAGE_TOP}/development/tools/make_key"
|
||||
|
||||
# Distinct from AOSP testkey DN (android@android.com).
|
||||
SUBJECT="${ANDROID_CERT_SUBJECT:-/C=DE/ST=NA/L=NA/O=AXP-Resurection/OU=sunfish-a16/CN=release}"
|
||||
|
||||
KEYS=(releasekey platform shared media networkstack sdk_sandbox bluetooth nfc)
|
||||
|
||||
if [[ ! -x "$MAKE_KEY" && ! -f "$MAKE_KEY" ]]; then
|
||||
echo "ERROR: make_key not found at $MAKE_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(id -u)" -eq 0 ]]; then
|
||||
echo "ERROR: refuse to generate keys as root; run as android-build" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT"
|
||||
chmod 700 "$OUT"
|
||||
|
||||
existing=0
|
||||
for k in "${KEYS[@]}"; do
|
||||
if [[ -e "$OUT/$k.pk8" || -e "$OUT/$k.x509.pem" ]]; then
|
||||
echo "EXISTS: $OUT/$k.*"
|
||||
existing=1
|
||||
fi
|
||||
done
|
||||
if [[ -e "$OUT/avb.pem" ]]; then
|
||||
echo "EXISTS: $OUT/avb.pem"
|
||||
existing=1
|
||||
fi
|
||||
if [[ "$existing" -eq 1 ]]; then
|
||||
echo "ERROR: refusing to overwrite. Delete specifically if you truly mean to rotate." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Generating APK/OTA keys in $OUT ==="
|
||||
echo "subject=$SUBJECT"
|
||||
for k in "${KEYS[@]}"; do
|
||||
# make_key always exits 1 because of its EXIT trap — ignore status; check files.
|
||||
# Blank password (Lineage/build-server norm); protect via directory mode 700.
|
||||
printf '\n' | bash "$MAKE_KEY" "$OUT/$k" "$SUBJECT" || true
|
||||
if [[ ! -f "$OUT/$k.pk8" || ! -f "$OUT/$k.x509.pem" ]]; then
|
||||
echo "ERROR: failed to create $k" >&2
|
||||
exit 1
|
||||
fi
|
||||
chmod 600 "$OUT/$k.pk8"
|
||||
chmod 644 "$OUT/$k.x509.pem"
|
||||
echo "OK $k"
|
||||
done
|
||||
|
||||
echo "=== Generating AVB RSA-4096 key ==="
|
||||
openssl genrsa -out "$OUT/avb.pem" 4096
|
||||
chmod 600 "$OUT/avb.pem"
|
||||
# Public key metadata for avbtool / optional custom key flash (not used for lock ship)
|
||||
if [[ -x "$LINEAGE_TOP/external/avb/avbtool.py" ]]; then
|
||||
python3 "$LINEAGE_TOP/external/avb/avbtool.py" extract_public_key \
|
||||
--key "$OUT/avb.pem" --output "$OUT/avb_pkmd.bin"
|
||||
chmod 644 "$OUT/avb_pkmd.bin"
|
||||
elif command -v avbtool >/dev/null 2>&1; then
|
||||
avbtool extract_public_key --key "$OUT/avb.pem" --output "$OUT/avb_pkmd.bin"
|
||||
chmod 644 "$OUT/avb_pkmd.bin"
|
||||
else
|
||||
echo "WARN: avbtool not found; skipped avb_pkmd.bin (openssl key still OK)"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "# generated $(date -Is) on $(hostname)"
|
||||
echo "subject=$SUBJECT"
|
||||
echo "dir=$OUT"
|
||||
echo "keys=${KEYS[*]} avb.pem"
|
||||
} >"$OUT/GENERATED.txt"
|
||||
chmod 644 "$OUT/GENERATED.txt"
|
||||
|
||||
echo
|
||||
echo "=== DONE ==="
|
||||
echo "Public releasekey subject:"
|
||||
openssl x509 -in "$OUT/releasekey.x509.pem" -noout -subject
|
||||
echo
|
||||
echo "NEXT (mandatory before first signed ship bacon):"
|
||||
echo " 1. Encrypted offline backup of $OUT"
|
||||
echo " 2. If keys are under \$HOME/.android-certs, have root install -d"
|
||||
echo " /srv/rom/secrets/android-certs and move/copy there (preferred long-term)."
|
||||
echo " 3. Record backup location/date in docs/009-hardening-signing-checklist.md"
|
||||
echo " 4. US-S2: export PRODUCT_DEFAULT_DEV_CERTIFICATE=$OUT/releasekey"
|
||||
echo " 5. Never copy .pk8 / avb.pem into Git"
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wait for CVE-clean bacon on rom-dev01, then one-shot fastboot flash boot + one reboot.
|
||||
# No recovery loops. No auto-recover. Exits if not booted in ~4 min.
|
||||
set -euo pipefail
|
||||
SSHCFG="${SSHCFG:-/home/aventura/Workspaces/AXP_Resurection/docs/ssh/config}"
|
||||
SERIAL="${SERIAL:-11231JEC207477}"
|
||||
LOCAL="${LOCAL:-/home/aventura/Workspaces/AXP_Resurection/.local-artifacts/009-flash-cve-clean}"
|
||||
STATUS=detach-009-bacon-cve-clean.status
|
||||
LOG="${LOG:-/tmp/009-wait-flash-cve-clean.log}"
|
||||
mkdir -p "$LOCAL"
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "WAIT start $(date -Is)"
|
||||
st=""
|
||||
for i in $(seq 1 180); do
|
||||
st=$(ssh -F "$SSHCFG" -o BatchMode=yes -o ConnectTimeout=20 rom-dev01 \
|
||||
"cat /srv/rom/artifacts/$STATUS" 2>/dev/null || echo status_unreadable)
|
||||
echo "poll $i: $st"
|
||||
if echo "$st" | grep -q '^exit=0'; then
|
||||
break
|
||||
fi
|
||||
if echo "$st" | grep -qE '^exit=[1-9]|^exit=killed'; then
|
||||
echo BACON_FAILED
|
||||
exit 1
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
echo "$st" | grep -q '^exit=0' || { echo TIMEOUT; exit 1; }
|
||||
|
||||
ART=$(ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
'ls -dt /srv/rom/artifacts/009-axp-los23-port/*-axp-stage1-combo4-cve-clean 2>/dev/null | head -1')
|
||||
echo "ART=$ART"
|
||||
test -n "$ART"
|
||||
|
||||
rsync -avP -e "ssh -F $SSHCFG -o BatchMode=yes" \
|
||||
"rom-dev01:$ART/boot.img" "rom-dev01:$ART/README.txt" "rom-dev01:$ART/SHA256SUMS" "$LOCAL/"
|
||||
cd "$LOCAL"
|
||||
grep ' boot.img$' SHA256SUMS | sha256sum -c -
|
||||
|
||||
adb start-server >/dev/null 2>&1 || true
|
||||
cur=$(adb -s "$SERIAL" get-state 2>/dev/null || true)
|
||||
if [[ "$cur" == "device" ]]; then
|
||||
echo "adb reboot bootloader once"
|
||||
adb -s "$SERIAL" reboot bootloader
|
||||
fi
|
||||
for j in $(seq 1 40); do
|
||||
fastboot devices 2>/dev/null | grep -q "$SERIAL" && break
|
||||
sleep 2
|
||||
done
|
||||
fastboot devices | grep -q "$SERIAL" || { echo NO_FASTBOOT; exit 1; }
|
||||
|
||||
echo "fastboot flash boot (cve-clean) once"
|
||||
fastboot -s "$SERIAL" flash boot "$LOCAL/boot.img"
|
||||
echo "fastboot reboot once"
|
||||
fastboot -s "$SERIAL" reboot
|
||||
|
||||
for j in $(seq 1 60); do
|
||||
sleep 5
|
||||
cur=$(adb devices | awk -v s="$SERIAL" '$1==s{print $2}')
|
||||
boot=$(adb -s "$SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||
echo "t=$((j*5))s adb=$cur boot=$boot"
|
||||
if [[ "$cur" == "device" && "$boot" == "1" ]]; then
|
||||
adb -s "$SERIAL" shell 'uname -a; getprop ro.boot.slot_suffix; pidof magiskd || true'
|
||||
echo CLEAN_BOOT_OK
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$j" -eq 48 ]]; then
|
||||
echo NOT_BOOTED_4min leave_alone
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
echo BOOT_TIMEOUT
|
||||
exit 2
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wait for hi-batch1 bacon on rom-dev01, then one-shot fastboot flash boot + reboot.
|
||||
# Serial-pinned. No recovery loops. Exit if not booted in ~4 min.
|
||||
set -euo pipefail
|
||||
SSHCFG="${SSHCFG:-/home/aventura/Workspaces/AXP_Resurection/docs/ssh/config}"
|
||||
SERIAL="${SERIAL:-11231JEC207477}"
|
||||
LOCAL="${LOCAL:-/home/aventura/Workspaces/AXP_Resurection/.local-artifacts/009-flash-cve-hi-batch1}"
|
||||
STATUS=detach-009-bacon-cve-hi-batch1.status
|
||||
LOG="${LOG:-/tmp/009-wait-flash-cve-hi-batch1.log}"
|
||||
mkdir -p "$LOCAL"
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "WAIT hi-batch1 start $(date -Is)"
|
||||
st=""
|
||||
for i in $(seq 1 180); do
|
||||
st=$(ssh -F "$SSHCFG" -o BatchMode=yes -o ConnectTimeout=20 rom-dev01 \
|
||||
"cat /srv/rom/artifacts/$STATUS" 2>/dev/null || echo status_unreadable)
|
||||
echo "poll $i: $st"
|
||||
# exit=141 = SIGPIPE from tee after successful bacon (false fail)
|
||||
if echo "$st" | grep -qE '^exit=0|^exit=141'; then
|
||||
break
|
||||
fi
|
||||
if echo "$st" | grep -qE '^exit=[1-9]|^exit=killed'; then
|
||||
if echo "$st" | grep -q '^exit=141'; then
|
||||
break
|
||||
fi
|
||||
echo BACON_FAILED
|
||||
exit 1
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
echo "$st" | grep -qE '^exit=0|^exit=141' || { echo TIMEOUT; exit 1; }
|
||||
|
||||
ART=$(ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
'ls -dt /srv/rom/artifacts/009-axp-los23-port/*-axp-stage1-combo4-cve-hi-batch1 2>/dev/null | head -1')
|
||||
echo "ART=$ART"
|
||||
test -n "$ART"
|
||||
|
||||
rsync -avP -e "ssh -F $SSHCFG -o BatchMode=yes" \
|
||||
"rom-dev01:$ART/boot.img" "rom-dev01:$ART/README.txt" "rom-dev01:$ART/SHA256SUMS" "$LOCAL/"
|
||||
cd "$LOCAL"
|
||||
grep ' boot.img$' SHA256SUMS | sha256sum -c -
|
||||
|
||||
adb start-server >/dev/null 2>&1 || true
|
||||
cur=$(adb -s "$SERIAL" get-state 2>/dev/null || true)
|
||||
if [[ "$cur" == "device" ]]; then
|
||||
echo "adb reboot bootloader once"
|
||||
adb -s "$SERIAL" reboot bootloader
|
||||
fi
|
||||
for j in $(seq 1 40); do
|
||||
fastboot devices 2>/dev/null | grep -q "$SERIAL" && break
|
||||
sleep 2
|
||||
done
|
||||
fastboot devices | grep -q "$SERIAL" || { echo NO_FASTBOOT; exit 1; }
|
||||
|
||||
echo "fastboot flash boot (hi-batch1) once"
|
||||
fastboot -s "$SERIAL" flash boot "$LOCAL/boot.img"
|
||||
echo "fastboot reboot once"
|
||||
fastboot -s "$SERIAL" reboot
|
||||
|
||||
for j in $(seq 1 60); do
|
||||
sleep 5
|
||||
cur=$(adb devices | awk -v s="$SERIAL" '$1==s{print $2}')
|
||||
boot=$(adb -s "$SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||
echo "t=$((j*5))s adb=$cur boot=$boot"
|
||||
if [[ "$cur" == "device" && "$boot" == "1" ]]; then
|
||||
adb -s "$SERIAL" shell 'uname -a; getprop ro.boot.slot_suffix; pidof magiskd || true'
|
||||
echo HI_BATCH1_BOOT_OK
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$j" -eq 48 ]]; then
|
||||
echo NOT_BOOTED_4min leave_alone
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
echo BOOT_TIMEOUT
|
||||
exit 2
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wait for hi-batch2 bacon on rom-dev01, then one-shot fastboot flash boot + reboot.
|
||||
# Serial-pinned. No recovery loops. Exit if not booted in ~4 min.
|
||||
set -euo pipefail
|
||||
SSHCFG="${SSHCFG:-/home/aventura/Workspaces/AXP_Resurection/docs/ssh/config}"
|
||||
SERIAL="${SERIAL:-11231JEC207477}"
|
||||
LOCAL="${LOCAL:-/home/aventura/Workspaces/AXP_Resurection/.local-artifacts/009-flash-cve-hi-batch2}"
|
||||
STATUS=detach-009-bacon-cve-hi-batch2.status
|
||||
LOG="${LOG:-/tmp/009-wait-flash-cve-hi-batch2.log}"
|
||||
mkdir -p "$LOCAL"
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "WAIT hi-batch2 start $(date -Is)"
|
||||
st=""
|
||||
for i in $(seq 1 180); do
|
||||
st=$(ssh -F "$SSHCFG" -o BatchMode=yes -o ConnectTimeout=20 rom-dev01 \
|
||||
"cat /srv/rom/artifacts/$STATUS" 2>/dev/null || echo status_unreadable)
|
||||
echo "poll $i: $st"
|
||||
# exit=141 = SIGPIPE from tee after successful bacon (false fail)
|
||||
if echo "$st" | grep -qE '^exit=0|^exit=141'; then
|
||||
break
|
||||
fi
|
||||
if echo "$st" | grep -qE '^exit=[1-9]|^exit=killed'; then
|
||||
if echo "$st" | grep -q '^exit=141'; then
|
||||
break
|
||||
fi
|
||||
echo BACON_FAILED
|
||||
exit 1
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
echo "$st" | grep -qE '^exit=0|^exit=141' || { echo TIMEOUT; exit 1; }
|
||||
# Confirm artifact exists (guards real failures that somehow report 141)
|
||||
ART_PROBE=$(ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
'ls -dt /srv/rom/artifacts/009-axp-los23-port/*-axp-stage1-combo4-cve-hi-batch2 2>/dev/null | head -1')
|
||||
test -n "$ART_PROBE" || { echo NO_ARTIFACT; exit 1; }
|
||||
|
||||
ART=$(ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
'ls -dt /srv/rom/artifacts/009-axp-los23-port/*-axp-stage1-combo4-cve-hi-batch2 2>/dev/null | head -1')
|
||||
echo "ART=$ART"
|
||||
test -n "$ART"
|
||||
|
||||
rsync -avP -e "ssh -F $SSHCFG -o BatchMode=yes" \
|
||||
"rom-dev01:$ART/boot.img" "rom-dev01:$ART/README.txt" "rom-dev01:$ART/SHA256SUMS" "$LOCAL/"
|
||||
cd "$LOCAL"
|
||||
grep ' boot.img$' SHA256SUMS | sha256sum -c -
|
||||
|
||||
adb start-server >/dev/null 2>&1 || true
|
||||
cur=$(adb -s "$SERIAL" get-state 2>/dev/null || true)
|
||||
if [[ "$cur" == "device" ]]; then
|
||||
echo "adb reboot bootloader once"
|
||||
adb -s "$SERIAL" reboot bootloader
|
||||
fi
|
||||
for j in $(seq 1 40); do
|
||||
fastboot devices 2>/dev/null | grep -q "$SERIAL" && break
|
||||
sleep 2
|
||||
done
|
||||
fastboot devices | grep -q "$SERIAL" || { echo NO_FASTBOOT; exit 1; }
|
||||
|
||||
echo "fastboot flash boot (hi-batch2) once"
|
||||
fastboot -s "$SERIAL" flash boot "$LOCAL/boot.img"
|
||||
echo "fastboot reboot once"
|
||||
fastboot -s "$SERIAL" reboot
|
||||
|
||||
for j in $(seq 1 60); do
|
||||
sleep 5
|
||||
cur=$(adb devices | awk -v s="$SERIAL" '$1==s{print $2}')
|
||||
boot=$(adb -s "$SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||
echo "t=$((j*5))s adb=$cur boot=$boot"
|
||||
if [[ "$cur" == "device" && "$boot" == "1" ]]; then
|
||||
adb -s "$SERIAL" shell 'uname -a; getprop ro.boot.slot_suffix; pidof magiskd || true'
|
||||
echo HI_BATCH2_BOOT_OK
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$j" -eq 48 ]]; then
|
||||
echo NOT_BOOTED_4min leave_alone
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
echo BOOT_TIMEOUT
|
||||
exit 2
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wait for hi-batch3 bacon on rom-dev01, then one-shot fastboot flash boot + reboot.
|
||||
# Treats exit=141 (tee SIGPIPE) as OK when artifact exists.
|
||||
set -euo pipefail
|
||||
SSHCFG="${SSHCFG:-/home/aventura/Workspaces/AXP_Resurection/docs/ssh/config}"
|
||||
SERIAL="${SERIAL:-11231JEC207477}"
|
||||
LOCAL="${LOCAL:-/home/aventura/Workspaces/AXP_Resurection/.local-artifacts/009-flash-cve-hi-batch3}"
|
||||
STATUS=detach-009-bacon-cve-hi-batch3.status
|
||||
LOG="${LOG:-/tmp/009-wait-flash-cve-hi-batch3.log}"
|
||||
mkdir -p "$LOCAL"
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
|
||||
echo "WAIT hi-batch3 start $(date -Is)"
|
||||
st=""
|
||||
for i in $(seq 1 180); do
|
||||
st=$(ssh -F "$SSHCFG" -o BatchMode=yes -o ConnectTimeout=20 rom-dev01 \
|
||||
"cat /srv/rom/artifacts/$STATUS" 2>/dev/null || echo status_unreadable)
|
||||
echo "poll $i: $st"
|
||||
if echo "$st" | grep -qE '^exit=0|^exit=141'; then
|
||||
break
|
||||
fi
|
||||
if echo "$st" | grep -qE '^exit=[1-9]|^exit=killed'; then
|
||||
echo BACON_FAILED
|
||||
exit 1
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
echo "$st" | grep -qE '^exit=0|^exit=141' || { echo TIMEOUT; exit 1; }
|
||||
|
||||
ART=$(ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
'ls -dt /srv/rom/artifacts/009-axp-los23-port/*-axp-stage1-combo4-cve-hi-batch3 2>/dev/null | head -1')
|
||||
echo "ART=$ART"
|
||||
test -n "$ART"
|
||||
# ensure SHA256SUMS exists (tee may have truncated post-bacon)
|
||||
ssh -F "$SSHCFG" -o BatchMode=yes rom-dev01 \
|
||||
"test -f $ART/SHA256SUMS || (cd $ART && sha256sum boot.img boot-make.img lineage-*-UNOFFICIAL-sunfish.zip 2>/dev/null | tee SHA256SUMS)"
|
||||
|
||||
rsync -avP -e "ssh -F $SSHCFG -o BatchMode=yes" \
|
||||
"rom-dev01:$ART/boot.img" "rom-dev01:$ART/README.txt" "rom-dev01:$ART/SHA256SUMS" "$LOCAL/"
|
||||
cd "$LOCAL"
|
||||
grep ' boot.img$' SHA256SUMS | sha256sum -c -
|
||||
|
||||
adb start-server >/dev/null 2>&1 || true
|
||||
cur=$(adb -s "$SERIAL" get-state 2>/dev/null || true)
|
||||
if [[ "$cur" == "device" ]]; then
|
||||
echo "adb reboot bootloader once"
|
||||
adb -s "$SERIAL" reboot bootloader
|
||||
fi
|
||||
for j in $(seq 1 40); do
|
||||
fastboot devices 2>/dev/null | grep -q "$SERIAL" && break
|
||||
sleep 2
|
||||
done
|
||||
fastboot devices | grep -q "$SERIAL" || { echo NO_FASTBOOT; exit 1; }
|
||||
|
||||
echo "fastboot flash boot (hi-batch3) once"
|
||||
fastboot -s "$SERIAL" flash boot "$LOCAL/boot.img"
|
||||
echo "fastboot reboot once"
|
||||
fastboot -s "$SERIAL" reboot
|
||||
|
||||
for j in $(seq 1 60); do
|
||||
sleep 5
|
||||
cur=$(adb devices | awk -v s="$SERIAL" '$1==s{print $2}')
|
||||
boot=$(adb -s "$SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)
|
||||
echo "t=$((j*5))s adb=$cur boot=$boot"
|
||||
if [[ "$cur" == "device" && "$boot" == "1" ]]; then
|
||||
adb -s "$SERIAL" shell 'uname -a; getprop ro.boot.slot_suffix; pidof magiskd || true'
|
||||
echo HI_BATCH3_BOOT_OK
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$j" -eq 48 ]]; then
|
||||
echo NOT_BOOTED_4min leave_alone
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
echo BOOT_TIMEOUT
|
||||
exit 2
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# Wait for release-keys bacon to finish, then start Stage1+combo4+CVE bacon.
|
||||
set -euo pipefail
|
||||
RK_STATUS=/srv/rom/artifacts/detach-009-bacon-axp-stage1-combo4-rk.status
|
||||
CVE_NAME=009-bacon-axp-stage1-combo4-cve
|
||||
CVE_SCRIPT=/srv/rom/artifacts/bin/009-bacon-axp-stage1-combo4-cve.sh
|
||||
DETACH=/srv/rom/artifacts/bin/rom-detach
|
||||
|
||||
echo "watcher: waiting for RK bacon to leave 'running' ($(date -Is))"
|
||||
while true; do
|
||||
if [[ -f "$RK_STATUS" ]]; then
|
||||
if grep -q '^exit=' "$RK_STATUS" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
if ! grep -q '^running ' "$RK_STATUS" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
else
|
||||
# no status → assume free
|
||||
break
|
||||
fi
|
||||
# still building?
|
||||
if ! pgrep -f 'm bacon -j' >/dev/null 2>&1 \
|
||||
&& ! pgrep -f 'combined-lineage_sunfish.ninja' >/dev/null 2>&1; then
|
||||
# status stale?
|
||||
sleep 30
|
||||
if ! pgrep -f 'm bacon -j' >/dev/null 2>&1; then
|
||||
echo "watcher: no mka/ninja; treating RK as done ($(date -Is))"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
|
||||
echo "watcher: RK status now:"
|
||||
cat "$RK_STATUS" 2>/dev/null || true
|
||||
|
||||
if grep -q '^exit=0' "$RK_STATUS" 2>/dev/null; then
|
||||
echo "watcher: RK bacon OK"
|
||||
elif grep -q '^exit=' "$RK_STATUS" 2>/dev/null; then
|
||||
echo "watcher: RK bacon FAILED — still launching CVE (kernel will reset)"
|
||||
else
|
||||
echo "watcher: RK status unclear — launching CVE after short settle"
|
||||
sleep 15
|
||||
fi
|
||||
|
||||
# Ensure scripts synced into lineage vendor
|
||||
KH=/srv/rom/src/lineage/vendor/sunfish-a16/patches/009-kernel-hardening
|
||||
test -x "$CVE_SCRIPT"
|
||||
test -f "$KH/cve-strict.list"
|
||||
test -x "$KH/apply_stage1_combo4_cve.sh"
|
||||
|
||||
"$DETACH" "$CVE_NAME" -- bash "$CVE_SCRIPT"
|
||||
echo "watcher: CVE bacon detached ($(date -Is))"
|
||||
@@ -12,7 +12,7 @@
|
||||
| Readback | `adb shell settings get secure disable_secure_windows` |
|
||||
| UI preference key | `allow_flag_secure_override` (writes the Secure key above) |
|
||||
| Scope | **Global** (all apps); per-app lists not planned |
|
||||
| Note | WMS only applies this on **debuggable** builds (`ro.debuggable`) |
|
||||
| Note | Stock AOSP gated WMS on `ro.debuggable`; project removes that gate (`SUNFISH_A16_008_WMS_DISABLE_SECURE_NO_DEBUGGABLE_GATE`) so `ro.debuggable` stays `0` |
|
||||
|
||||
## Capture behaviour
|
||||
|
||||
|
||||
@@ -39,8 +39,12 @@ has `Settings.Secure.DISABLE_SECURE_WINDOWS` wired through
|
||||
Options switch (preference key `allow_flag_secure_override`) that writes
|
||||
`disable_secure_windows`.
|
||||
|
||||
**Constraint**: WMS applies the setting only on debuggable builds
|
||||
(`ro.debuggable`). LAB `userdebug` is in scope; `user` retest before release.
|
||||
**Constraint (stock AOSP)**: WMS applied the setting only on debuggable builds
|
||||
(`ro.debuggable`). **Project decision (2026-09-18):** remove that gate in
|
||||
`updateDisableSecureWindows()` (`apply_wms_disable_secure_debuggable_gate.py`)
|
||||
so ship images keep `ro.debuggable=0` while the DO toggle works. No other
|
||||
secondary gate found in `WindowState.isSecureLocked` / `Task.isSecure`.
|
||||
LAB `userdebug` with `ro.debuggable=0` was the motivating case.
|
||||
|
||||
**Alternatives rejected**: Magisk `services.jar` dex patchers as shipping
|
||||
mechanism.
|
||||
|
||||
@@ -27,27 +27,39 @@
|
||||
- [ ] Activation documented and completed on LAB
|
||||
- [ ] DenyList-class hides root from a test/banking package
|
||||
|
||||
## Gate E — Banking
|
||||
## Gate E — Banking *(deferred — not MVP)*
|
||||
|
||||
- [ ] Island present; Swissquote PASS in managed profile workflow
|
||||
- [ ] Yuh recorded; not worse than GOLDEN for packaging/spoofing reasons
|
||||
- [ ] Banks do not receive root
|
||||
- [ ] *(Later)* Island present; Swissquote PASS in managed profile workflow
|
||||
- [ ] *(Later)* Yuh recorded; not worse than GOLDEN for packaging/spoofing
|
||||
- [ ] *(Later)* Banks do not receive root
|
||||
|
||||
## Gate F — Usability / WebView
|
||||
|
||||
- [ ] Bundled AXP categories present or documented impossible
|
||||
- [ ] Bundled AXP categories present or documented impossible/deferred
|
||||
- [ ] Versions newest workable (except Phonesky rule)
|
||||
- [ ] WebView default LOS; chooser unlocked
|
||||
|
||||
## Gate G — Hardening / signing class
|
||||
## Gate G — Hardening / signing + kernel
|
||||
|
||||
- [ ] GOLDEN-class hardening/signing/AVB posture present **or** each gap
|
||||
documented as impossible on this stack (no silent omit)
|
||||
- [ ] Staged known-good images retained for bisect
|
||||
- [ ] Project **release / definitive signing keys** on ship images/OTAs (not
|
||||
AOSP test-keys); Phonesky / update identity on that key
|
||||
- [ ] GOLDEN-class **userspace** hardening + AVB *build* posture as applicable
|
||||
on unlocked sunfish **or** each in-scope gap documented (no silent omit)
|
||||
- [x] Updated LOS23-compatible sunfish kernel + hardening attribution list
|
||||
(FR-017 / SC-010) — see `docs/009-gate-g-kernel-attribution.md`
|
||||
(Stage1 + combo4 + Clang FORTIFY; LAB 2026-09-29)
|
||||
- [x] Staged known-good images retained for bisect
|
||||
(`20260929T123401Z-axp-stage1-combo4`, prior combo4-fortify, GOODMAKE)
|
||||
- [x] Localization/location AXP-vs-LOS compare **not** required yet (FR-018)
|
||||
- [x] Bootloader relock **not** a Gate G requirement (AXP/LOS unlocked norm;
|
||||
IOdes-class lock is non-goal) — see research 2026-09-29
|
||||
|
||||
## Non-gates
|
||||
|
||||
- KernelSU presence or SusFS
|
||||
- FLAG_SECURE override (optional)
|
||||
- Custom AXP backup ROM feature
|
||||
- Banking / Swissquote / Yuh (deferred owner future)
|
||||
- Localization hardening policy freeze (FR-018 later)
|
||||
- Yuh PASS if GOLDEN attestation path still FAILs equivalently
|
||||
- Bootloader lock / relock (IOdes-class); unlocked sunfish is the ship model
|
||||
@@ -6,11 +6,13 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Resurrect **AXP.OS Pro on LOS22 / GOLDEN** as a single shippable LineageOS
|
||||
23.2 / Android 16 `sunfish` ROM on **LAB**: vanilla `003` base + full AXP
|
||||
capability set (Google stack, selectable spoofing, Island banking workflow,
|
||||
selectable call-recording unlock, Magisk like GOLDEN, bundled usability apps,
|
||||
GOLDEN-class hardening/signing/AVB posture).
|
||||
Resurrect **AXP.OS Pro on LOS22 / GOLDEN** as an **updated AXP-class clone**
|
||||
on LineageOS 23.2 / Android 16 `sunfish` (**LAB**): vanilla `003` base + AXP
|
||||
capability set (Google stack, selectable spoofing, selectable call-recording
|
||||
unlock, Magisk like GOLDEN, bundled usability apps / options surface,
|
||||
GOLDEN-class userspace hardening/signing/AVB, **updated hardened sunfish
|
||||
kernel**). **Banking/Island/Swissquote validation deferred** (owner future).
|
||||
**Localization hardening AXP-vs-LOS compare deferred** (FR-018).
|
||||
|
||||
**Explicit exceptions:** LOS23 WebView default (Aosmium EOL) with unlocked
|
||||
provider chooser; Phonesky = project's recent patched artifact (reconsider if
|
||||
@@ -22,7 +24,9 @@ packaging where they already match; replace the KernelSU ship path with
|
||||
AXP-style Magisk preinstall (newest Magisk); pin newest stable microG and
|
||||
bundled apps; keep Phonesky on the existing host pipeline; measure Magisk
|
||||
“preinstalled but not fully activated” behaviour on GOLDEN before freezing LAB
|
||||
setup docs.
|
||||
setup docs; port attributable kernel hardening onto current LOS23 sunfish
|
||||
kernel; stage userspace hardening; leave location-policy compare for later.
|
||||
|
||||
|
||||
## Technical Context
|
||||
|
||||
@@ -88,7 +92,7 @@ specs/009-axp-los23-port/
|
||||
│ ├── magisk-preinstall.md
|
||||
│ ├── webview-surface.md
|
||||
│ └── acceptance-gates.md
|
||||
└── tasks.md # /speckit-tasks (not this command)
|
||||
└── tasks.md # /speckit-tasks (generated)
|
||||
```
|
||||
|
||||
### Host + tree
|
||||
|
||||
@@ -49,29 +49,31 @@ adb -s 11231JEC207477 shell settings get secure extendrom_call_recording
|
||||
3. Configure DenyList-class hide for a banking package **before** first open.
|
||||
4. Save Magisk version + screenshots under `…/magisk/`.
|
||||
|
||||
## 4. Banking (Gate E)
|
||||
## 4. Banking (Gate E) — deferred
|
||||
|
||||
1. Aurora → install Swissquote → **do not open**.
|
||||
2. DenyList → Island clone → first launch in Island → login.
|
||||
3. Repeat attempt for Yuh; classify PASS / attestation-like-GOLDEN /
|
||||
packaging regression.
|
||||
4. Confirm banks lack root.
|
||||
Skip for MVP. Owner future. Magisk DenyList can still be smoke-tested with a
|
||||
non-bank test package under Gate D.
|
||||
|
||||
## 5. Usability + WebView (Gate F)
|
||||
|
||||
1. Confirm bundled categories vs pin record.
|
||||
2. `adb shell cmd webviewupdate current` → LOS default; chooser still listed.
|
||||
|
||||
## 6. Hardening / signing class (Gate G)
|
||||
## 6. Hardening / signing + kernel (Gate G)
|
||||
|
||||
1. Run the hardening/signing checklist defined for this build stage.
|
||||
2. Any missing GOLDEN-class item → written impossible/gap note (no silent
|
||||
1. Userspace: follow `docs/009-hardening-signing-checklist.md` (release keys;
|
||||
unlocked AVB; no bootloader lock).
|
||||
2. Kernel: `docs/009-gate-g-kernel-attribution.md` (Stage1+combo4+FORTIFY).
|
||||
2. Record kernel rev + hardening patches applied/skipped (FR-017).
|
||||
3. Any missing GOLDEN-class item → written impossible/gap note (no silent
|
||||
skip).
|
||||
4. Do **not** block on localization AXP-vs-LOS compare (FR-018 later).
|
||||
|
||||
## Pass criteria
|
||||
|
||||
All boxes in [acceptance-gates.md](./contracts/acceptance-gates.md) for the
|
||||
claimed stage. Full resurrection acceptance = Gates A–G.
|
||||
claimed stage **except Gate E** (deferred). Full clone acceptance for current
|
||||
owner priority = Gates A–D + F–G.
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -79,3 +81,4 @@ claimed stage. Full resurrection acceptance = Gates A–G.
|
||||
- Call-recording legality is the user’s responsibility.
|
||||
- If project Phonesky misbehaves vs GOLDEN needs → stop and reconsider; do
|
||||
not accept Gate B.
|
||||
- Localization hardening compare is explicitly postponed.
|
||||
@@ -111,15 +111,140 @@ Document impossible-on-sunfish gaps rather than silent omit.
|
||||
**Alternatives considered**: Defer all of `011`–`013` — rejected by owner.
|
||||
One mega-commit everything — rejected (attribution / bisect).
|
||||
|
||||
## Decision: Banking workflow = GOLDEN Magisk DenyList + Island
|
||||
## Decision: Release keys yes; bootloader lock no (2026-09-29)
|
||||
|
||||
**Decision**: Restore constitution banking steps with **Magisk DenyList**
|
||||
(not KSU profiles) + Island: Aurora install → do not open → DenyList → clone
|
||||
to Island → first launch in Island. Swissquote PASS hard gate; Yuh honest vs
|
||||
GOLDEN attestation FAIL.
|
||||
**Decision**:
|
||||
|
||||
1. **Sign with definitive / project release keys** — required for Gate G
|
||||
userspace. Move off AOSP test-keys for ship images/OTAs; keep Phonesky and
|
||||
update identity on that key. Keys live only on `rom-dev01`
|
||||
(`/srv/rom/secrets/`), never in the laptop Git tree.
|
||||
2. **Do not pursue bootloader relock** as a ship goal. AXP and LineageOS do
|
||||
not lock the bootloader as their normal product path; Magisk preroot and
|
||||
recovery sideload assume unlocked. IOdes-style locked bootloader is an
|
||||
explicit non-goal for this track.
|
||||
|
||||
**Rationale**: Clone AXP/LOS norms; avoid a locked-device model that fights
|
||||
Magisk EXTENDROM preroot. Signing still matters for update trust and
|
||||
PRESIGNED / same-identity sideload.
|
||||
|
||||
**Alternatives considered**: IOdes-class locked AVB ship — rejected by owner
|
||||
(2026-09-29). Skip release keys entirely — rejected (Gate G / FR signing).
|
||||
|
||||
## Decision: Banking workflow deferred (owner future)
|
||||
|
||||
**Decision (2026-09-17)**: Banking / Island / Swissquote / Yuh validation is
|
||||
**deferred**. Not an MVP acceptance gate. Magisk DenyList-class capability
|
||||
still ships (general). Owner may resume US3 later.
|
||||
|
||||
**Rationale**: Owner wants updated AXP clone (features, options, hardening,
|
||||
security, kernel) first; banks are a personal future problem.
|
||||
|
||||
**Alternatives considered**: Keep Swissquote as hard gate — rejected by owner.
|
||||
|
||||
## Decision: Updated hardened LOS23 sunfish kernel (FR-017)
|
||||
|
||||
**Decision (refined 2026-09-18):** Ship current LineageOS 23.2–compatible
|
||||
`sunfish` kernel (`msm-4.14`) with attributable hardening. **Not** an
|
||||
unrelated Graphene A13 / stock prebuilt as base. Record applied/skipped list
|
||||
in `docs/009-kernel-hardening-map.md`.
|
||||
|
||||
**Source priority (owner):**
|
||||
|
||||
1. **AXP** — maximum priority; clone their sunfish kernel hardening first
|
||||
(build sources / OTA oracle / GOLDEN). Inherited Divest-era commits that
|
||||
already live *inside* the AXP stack are fine as part of that clone; do
|
||||
**not** separately mine DivestOS EOL trees.
|
||||
2. **LOS 23.2** — inventory what the lineage kernel already has; avoid
|
||||
duplicate work.
|
||||
3. **IodéOS** — LOS fork, more hardened/deblobbed; clone sources on
|
||||
`rom-dev01` and diff for 4.14-safe ideas worth porting.
|
||||
4. **GrapheneOS** — optional extras only when they make sense on non-GKI
|
||||
4.14 sunfish: prefer portable techniques from modern Pixel kernels /
|
||||
docs; historical sunfish A13 patches only if still clearly valuable.
|
||||
Do **not** treat GOS A13 sunfish tree as the base.
|
||||
|
||||
**Out of hunt:** DivestOS as a separate research target (EOL).
|
||||
|
||||
**Rationale**: AXP-first resurrection; GOS/Iodé as additive; honest skips on
|
||||
4.14.
|
||||
|
||||
**Inventory (2026-09-18):** LOS `msm-4.14` @ `28f9290ae067` (`4.14.357-openela`).
|
||||
AXP `kernel_patches` @ `df3cab2155b3` on host. Graphene/AH sequential probe:
|
||||
OK=30 / SKIP_ALREADY=4 / FAIL=12. Iodé `v5-staging` manifest has no sunfish
|
||||
4.14 kernel fork. Stage 1 allowlist + apply script under
|
||||
`vendor/sunfish-a16/patches/009-kernel-hardening/`. CVE mega deferred.
|
||||
Ledger: `docs/009-kernel-hardening-map.md`.
|
||||
|
||||
## Decision: Location / localization hardening — do not extra-cap (FR-018)
|
||||
|
||||
**Decision (2026-09-18):** For this Magisk track, **do not** port AXP-class
|
||||
aggressive location lockdown (kernel or userspace) beyond stock LOS 23.2
|
||||
defaults. No “non-hardening location” Settings toggle for MVP — that is
|
||||
extra product surface; simpler and matches owner GPS frustration to **leave
|
||||
LOS location behaviour**. FR-018 compare doc may still note what AXP did,
|
||||
for later curiosity, without shipping those caps.
|
||||
|
||||
**Alternatives considered**: (1) Clone AXP location caps — rejected (slow /
|
||||
frustrating fixes). (2) Owner toggle to disable caps — deferred; only if
|
||||
LOS defaults prove insufficient and owner asks later.
|
||||
|
||||
|
||||
## Decision: Bundled store client = Droidify; no NeoLauncher
|
||||
|
||||
**Decision (2026-09-17):** Ship **Droidify** as the F-Droid-class client
|
||||
instead of stock F-Droid (lighter; many repos by default). Do **not**
|
||||
integrate NeoLauncher — keep LOS Launcher3. Aurora remains for Play-sideload
|
||||
workflow.
|
||||
|
||||
## Decision: No AXP external repos / OTA servers
|
||||
|
||||
**Decision:** Do not wire AXP market/F-Droid remote repos or AXP OTA update
|
||||
endpoints. AXP infra is EOL / servers down — no product sense. Periodic
|
||||
system-package refresh is **owner sideload** (FR-019), not network OTA.
|
||||
|
||||
## Decision: Sideloadable system package refreshes (FR-019)
|
||||
|
||||
**Decision (2026-09-17):** Final ROM MUST keep **microG**, **Magisk**,
|
||||
**project Phonesky**, and other bundled system/privileged apps
|
||||
**updateable without full reflash**, on a ~**2–3 month** cadence the owner
|
||||
drives. Prefer PackageManager-compatible sideload (same signing identity;
|
||||
PRESIGNED microG; continuous project key for Phonesky). Magisk: document
|
||||
manager self-update and/or recovery/boot re-patch when APK sideload alone is
|
||||
not enough. Deliver a short recovery/sideload runbook before ship; do **not**
|
||||
reintroduce AXP OTA.
|
||||
|
||||
## Decision: Private DNS + Internet connectivity (sans axp.os)
|
||||
|
||||
**Decision:** Port AXP-class **Private DNS** provider presets. Keep AXP-class
|
||||
**Internet connectivity** / special INTERNET permission behaviour where it
|
||||
still fits LOS 23.2, but strip any hard dependency on `axp.os` branding or
|
||||
endpoints.
|
||||
|
||||
## Decision: Restore Disable app on Android 16
|
||||
|
||||
**Decision:** Investigate and re-expose classic **Disable application** UX on
|
||||
A16/LOS23 where Archive replaced or hid it. Owner prefers Disable over
|
||||
Archive. Exact Settings/PackageManager patch path TBD from AXP/LOS delta
|
||||
research — must remain attributable and reversible.
|
||||
|
||||
## Decision: AXP build sources as compile oracle
|
||||
|
||||
**Decision:** On `rom-dev01`, prefer cloning/checking out AXP **build** +
|
||||
EXTENDROM (and axpos.org developer building docs already mirrored under
|
||||
`/srv/rom/references/axp/archive/`) to see how Magisk preroot / product packages
|
||||
are wired — before treating GOLDEN `adb` as the compile guide. GOLDEN stays the
|
||||
runtime compatibility oracle.
|
||||
|
||||
**Decision**: Do **not** freeze localization/location lockdown policy in this
|
||||
feature’s acceptance. Later compare how much AXP “capea” location vs stock
|
||||
LOS (owner historically complains AXP is aggressive). Until then, avoid
|
||||
inventing extra location lockdown beyond what the clone already implies;
|
||||
matrix row = deferred.
|
||||
|
||||
**Alternatives considered**: Blind-copy all AXP location patches now —
|
||||
rejected (owner wants a deliberate compare first).
|
||||
|
||||
**Alternatives considered**: Rootless-only banking gate — incomplete vs AXP.
|
||||
Insular rename — GOLDEN runs Island.
|
||||
|
||||
## Decision: Version freshness policy
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
**Created**: 2026-09-16
|
||||
|
||||
**Status**: Clarified — ready for `/speckit-plan`
|
||||
**Status**: Spec clarified 2026-09-17 (banking deferred; kernel hardening in;
|
||||
localization compare later) — tasks updated; ready for `/speckit-implement`
|
||||
|
||||
**Input**: User description: "009-axp based LOS22 feature port to LOS23 —
|
||||
take vanilla LineageOS 23 for sunfish and integrate the full AXP.OS (LOS22 /
|
||||
@@ -24,6 +25,29 @@ with that Phonesky; signature spoofing and call recording **selectable**
|
||||
existing functional kernels if useful; otherwise everything equal to
|
||||
AXP/GOLDEN.
|
||||
|
||||
**Owner clarifications (2026-09-17):** Primary ship interest = an **updated
|
||||
AXP clone on LOS23** (features, options, userspace hardening/security, updated
|
||||
hardened sunfish kernel). Banking / Island / Swissquote / Yuh **deferred**
|
||||
(owner future). Localization AXP-vs-LOS compare **later** (FR-018). Prefer AXP
|
||||
**build sources + docs** on `rom-dev01` as the compile oracle (how Magisk /
|
||||
product packaging is wired); GOLDEN `adb` for *runtime* behaviour, not the
|
||||
first place to reverse “how to build”. **Do not** ship NeoLauncher — keep LOS
|
||||
Launcher3. Prefer **Droidify** over stock F-Droid client (lighter; many repos
|
||||
by default) unless packaging forces otherwise. **Do not** integrate AXP
|
||||
**external** market repos or AXP **OTA** servers (EOL / servers down — no
|
||||
sense). **Do** clone AXP-class **Private DNS** presets (many provider entries).
|
||||
**Do** keep AXP-class **Internet connectivity** / special INTERNET permission
|
||||
UX where practical, but **do not** hard-wire `axp.os` branding/endpoints.
|
||||
**Wanted:** restore classic **Disable app** behaviour on Android 16 (LOS/AOSP
|
||||
replaced much of this with **Archive**, which the owner dislikes) — research
|
||||
and re-expose Disable where still feasible on A16. **Later (final ROM):**
|
||||
system components (microG, Magisk, project Phonesky, other bundled system
|
||||
apps) MUST remain **sideload-updatable** on a shipping build — owner plans
|
||||
refreshes every **2–3 months** without a full ROM reflash. Packaging MUST
|
||||
preserve update paths (same signing identity / PRESIGNED where applicable;
|
||||
document Magisk update path separately from APK sideload if boot-preroot).
|
||||
|
||||
|
||||
## Context / non-goals
|
||||
|
||||
**Product intent (this feature is normative for the AXP resurrection ship):**
|
||||
@@ -83,30 +107,39 @@ AXP/GOLDEN.
|
||||
- Building a custom AXP-style backup/restore ROM feature (personal backup
|
||||
remains an external user tool if needed).
|
||||
- Claiming Yuh hardware-attestation PASS if GOLDEN itself currently FAILs that
|
||||
path — reproduce GOLDEN's *workflow* and document attestation parity honestly.
|
||||
path — banking attestation is deferred with the banking workflow (owner
|
||||
future); do not treat Swissquote/Yuh as ship gates here.
|
||||
- Deleting or rewriting the standby KernelSU / split-roadmap specs
|
||||
(`004`–`008`/`007`) — they remain valid on the standby branch/track.
|
||||
- Shipping KernelSU-Next as this track’s root (out of ship here; Magisk is
|
||||
the resurrection root). Optional later reuse of `007` kernels is allowed
|
||||
under FR-016 but MUST NOT delay Magisk acceptance.
|
||||
- Resolving localization/location-hardening policy vs LOS defaults in this
|
||||
feature’s acceptance (deferred research FR-018 — compare AXP vs LOS later).
|
||||
- Integrating AXP **external** F-Droid/market repos or AXP **OTA** update
|
||||
servers (EOL; servers down — no sense).
|
||||
- Shipping NeoLauncher.
|
||||
- Hard-wiring `axp.os` branding/endpoints into Internet-connectivity /
|
||||
network UX (keep the permission/connectivity *behaviour* where practical).
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - AXP resurrection daily-driver on LAB (Priority: P1)
|
||||
|
||||
As the owner, after flashing one LAB build produced under this feature, the
|
||||
phone boots and presents the same class of daily-driver capabilities I rely on
|
||||
with AXP on GOLDEN (Google compatibility stack, Play, managed banking profile
|
||||
workflow, selectable call recording unlock, Magisk root/hide workflow like
|
||||
GOLDEN, AXP hardening/signing posture, and AXP bundled usability apps —
|
||||
except WebView as defined here), without a checklist of deferred AXP features.
|
||||
phone boots and presents an **updated AXP-class clone on LOS23**: Google
|
||||
compatibility stack, Play, selectable call recording unlock, Magisk root/hide
|
||||
workflow like GOLDEN, AXP options/settings surface, userspace hardening /
|
||||
signing posture, bundled usability apps, and an updated hardened sunfish
|
||||
kernel — except WebView as defined here. Banking/Island validation is
|
||||
**out of this story’s acceptance** (deferred to owner future / US3).
|
||||
|
||||
**Why this priority**: This is the whole reason for the resurrection.
|
||||
|
||||
**Independent Test**: Flash one `009` build to LAB; walk the GOLDEN daily
|
||||
checklist (microG Self-Check, Play open/install, Island profile, call-record
|
||||
checklist minus banking (microG Self-Check, Play open/install, call-record
|
||||
toggle off/on, spoofing toggle off/on, Magisk present in AXP-like install
|
||||
state, bundled apps present, hardening/signing checks that GOLDEN implies);
|
||||
state, bundled apps present, hardening/signing + kernel hardening checks);
|
||||
compare against `002` inventory categories.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
@@ -115,13 +148,13 @@ compare against `002` inventory categories.
|
||||
**When** the `009` image is flashed, **Then** the device boots to home and
|
||||
cellular/Wi‑Fi/basic hardware still work as in the vanilla smoke.
|
||||
2. **Given** that build, **When** I compare shipped capability categories to
|
||||
GOLDEN/AXP Pro (Google stack, Play, selectable spoofing, managed profile
|
||||
tool, selectable call recording unlock, Magisk/DenyList-class path,
|
||||
DNS/hosts privacy helpers if present on GOLDEN, F‑Droid/Aurora/launcher/
|
||||
gallery-class bundled apps, hardening/signing/AVB class), **Then** no
|
||||
category is left as “decide / later” without an explicit obsolescence note
|
||||
tied to Android 16 / sunfish impossibility (WebView exception allowed per
|
||||
FR-015).
|
||||
GOLDEN/AXP Pro (Google stack, Play, selectable spoofing, selectable call
|
||||
recording unlock, Magisk/DenyList-class path, DNS/hosts privacy helpers if
|
||||
present on GOLDEN, F‑Droid/Aurora/launcher/gallery-class bundled apps,
|
||||
userspace hardening/signing/AVB class, kernel update + hardening class),
|
||||
**Then** no category is left as “decide / later” without an explicit
|
||||
obsolescence or **deferred** note (WebView exception FR-015; banking
|
||||
deferred FR-006/FR-007; localization hardening compare deferred FR-018).
|
||||
3. **Given** Git and host artifact policy, **When** inspected, **Then** no
|
||||
proprietary Phonesky APK bytes or secrets were committed.
|
||||
|
||||
@@ -165,22 +198,22 @@ behaviour; push notifications smoke for a known test app.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Banking profile workflow parity (Priority: P1)
|
||||
### User Story 3 - Banking profile workflow parity (Priority: P3 — deferred)
|
||||
|
||||
As the owner, I can recreate the GOLDEN banking layout on LAB: install via the
|
||||
same store path I use on AXP, place banks in Island, and keep banking apps
|
||||
free of root via Magisk DenyList-class hiding like GOLDEN.
|
||||
As the owner, **later** I can recreate the GOLDEN banking layout on LAB:
|
||||
Island + Magisk DenyList-class hiding + Swissquote/Yuh. This is explicitly
|
||||
**not** required to accept the AXP-on-LOS23 clone for functionalities,
|
||||
options, hardening, security, or kernel work.
|
||||
|
||||
**Why this priority**: Compatibility hard gates; daily-driver without banks
|
||||
fails the resurrection.
|
||||
**Why this priority**: Owner (2026-09-17) — banking is a future personal
|
||||
problem; do not block the updated AXP clone on bank gates.
|
||||
|
||||
**Independent Test**: Install Swissquote (hard gate) and attempt Yuh; run
|
||||
inside Island; Magisk DenyList (or AXP-equivalent) applied; record PASS/FAIL
|
||||
honestly vs GOLDEN.
|
||||
**Independent Test** *(when owner resumes)*: Install Swissquote and attempt
|
||||
Yuh; Island; Magisk DenyList; record PASS/FAIL honestly vs GOLDEN.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
**Acceptance Scenarios** *(deferred — not ship gates)*:
|
||||
|
||||
1. **Given** Island on LAB, **When** I follow the documented GOLDEN banking
|
||||
1. **Given** Island on LAB, **When** the owner follows the GOLDEN banking
|
||||
install order, **Then** Swissquote reaches a usable logged-in state in the
|
||||
managed profile.
|
||||
2. **Given** Yuh on the same workflow, **When** tested, **Then** either it
|
||||
@@ -211,32 +244,38 @@ recording unlock off (restricted) and on (record allowed).
|
||||
with GOLDEN measurement, using the newest Magisk stable that works on this
|
||||
stack.
|
||||
2. **Given** Magisk setup completed on LAB, **When** DenyList-class hiding is
|
||||
configured for a banking package, **Then** that package does not receive
|
||||
root.
|
||||
configured for a test package, **Then** that package does not receive root
|
||||
(banking packages deferred with US3).
|
||||
3. **Given** selectable call recording unlock, **When** OFF, **Then** stock
|
||||
LOS country/carrier style restrictions apply; **When** ON, **Then** Dialer
|
||||
can record on LAB without that block.
|
||||
|
||||
---
|
||||
|
||||
### User Story 5 - AXP usability, privacy, hardening (Priority: P2)
|
||||
### User Story 5 - AXP usability, options, hardening + kernel (Priority: P1)
|
||||
|
||||
As the owner, the ROM ships the rest of the AXP usability/privacy surface and
|
||||
GOLDEN-class hardening/signing/AVB posture at newest workable stables, with
|
||||
LOS23 WebView default and an unlocked provider chooser.
|
||||
As the owner, the ROM ships the rest of the AXP usability/privacy surface,
|
||||
AXP-class options/settings behaviour, GOLDEN-class userspace hardening /
|
||||
signing / AVB posture, and an **updated LOS 23.2 sunfish kernel with
|
||||
attributable hardening** (AXP / Graphene / Divest class where still valid on
|
||||
non-GKI 4.14), at newest workable stables, with LOS23 WebView default and an
|
||||
unlocked provider chooser. Localization/location-hardening delta vs LOS is
|
||||
**out of scope for now** (FR-018 later).
|
||||
|
||||
**Why this priority**: Completes resurrection beyond Google/banking/root core.
|
||||
**Why this priority**: Owner (2026-09-17) — this is the core of “clon
|
||||
actualizado de AXP”, ahead of banking.
|
||||
|
||||
**Independent Test**: Package list vs `002`; open bundled apps; confirm
|
||||
default WebView is LOS and another WebView can be selected if installed;
|
||||
hardening/signing checks agreed for GOLDEN-class parity.
|
||||
default WebView is LOS; userspace hardening/signing checks; kernel version /
|
||||
hardening patch attribution recorded for the accepted build.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the `009` build, **When** I list bundled system/user apps in the
|
||||
AXP usability set, **Then** each GOLDEN/AXP category is present or
|
||||
explicitly marked impossible on Android 16/sunfish with rationale
|
||||
(Aosmium absence is the allowed WebView exception).
|
||||
(Aosmium absence is the allowed WebView exception; banking tools may ship
|
||||
as packages without Gate E validation).
|
||||
2. **Given** Developer options, **When** I open WebView implementation,
|
||||
**Then** LOS23 WebView is available/default and the chooser is not locked
|
||||
against future alternate providers.
|
||||
@@ -244,9 +283,13 @@ hardening/signing checks agreed for GOLDEN-class parity.
|
||||
FR-004) are recorded, **Then** each is newest stable that still runs on
|
||||
the ROM.
|
||||
4. **Given** GOLDEN/AXP hardening and signing expectations, **When** the
|
||||
accepted build is evaluated, **Then** equivalent class of protections /
|
||||
signing posture is present or each gap is documented as impossible on
|
||||
this stack — not silently dropped.
|
||||
accepted build is evaluated, **Then** equivalent class of userspace
|
||||
protections / signing posture is present or each gap is documented as
|
||||
impossible on this stack — not silently dropped.
|
||||
5. **Given** the LOS 23.2 sunfish kernel tree, **When** the accepted boot
|
||||
image is built, **Then** it is an updated lineage/sunfish-compatible
|
||||
kernel (not an unrelated prebuilt) with attributable hardening patches
|
||||
applied or each skipped hardening item documented.
|
||||
|
||||
---
|
||||
|
||||
@@ -291,6 +334,9 @@ work when published.
|
||||
silently fall back to FakeStore.
|
||||
- Alternate WebView installed by user later: selection must remain possible;
|
||||
default remains LOS23 WebView until the user changes it.
|
||||
- Localization/location hardening: AXP historically more aggressive than LOS
|
||||
in places the owner dislikes; **do not decide** AXP-vs-LOS location policy
|
||||
in this feature’s acceptance — compare later (FR-018).
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
@@ -298,9 +344,11 @@ work when published.
|
||||
|
||||
- **FR-001**: The project MUST produce a flashable LineageOS 23.2 / Android 16
|
||||
`sunfish` build that resurrects the AXP.OS on LOS22 / GOLDEN capability set
|
||||
(including Magisk-class root and GOLDEN-class hardening / signing / AVB
|
||||
posture), without leaving AXP capabilities as open “decide” omissions
|
||||
except the WebView exception in FR-015.
|
||||
(including Magisk-class root, GOLDEN-class userspace hardening / signing /
|
||||
AVB posture, and an updated hardened sunfish kernel per FR-017), without
|
||||
leaving AXP capabilities as open “decide” omissions except documented
|
||||
exceptions/deferrals (WebView FR-015; banking FR-006/FR-007; localization
|
||||
compare FR-018).
|
||||
- **FR-002**: Version selection for system and bundled components (except
|
||||
Phonesky per FR-004) MUST prefer the newest stable (or newest tagged
|
||||
pre-release upstream currently ships) that still works on sunfish /
|
||||
@@ -316,10 +364,13 @@ work when published.
|
||||
microG + Phonesky path (owner-controlled toggle; default safe/off or
|
||||
project-documented default). Spoofing MUST remain restricted/controlled —
|
||||
not unrestricted platform spoofing for all apps.
|
||||
- **FR-006**: The ROM MUST support the GOLDEN managed-profile banking workflow
|
||||
(Island as measured on GOLDEN) including Swissquote PASS as a hard gate.
|
||||
- **FR-007**: Banking applications MUST run without being granted root
|
||||
(Magisk DenyList-class hiding).
|
||||
- **FR-006**: *(Deferred — owner future)* The ROM SHOULD support the GOLDEN
|
||||
managed-profile banking workflow (Island as measured on GOLDEN) including
|
||||
Swissquote PASS. This is **not** an acceptance gate for the AXP clone MVP.
|
||||
- **FR-007**: *(Deferred — owner future)* Banking applications SHOULD run
|
||||
without being granted root (Magisk DenyList-class hiding). Magisk MUST still
|
||||
provide DenyList-class capability for general use (FR-010); bank-specific
|
||||
validation is deferred with FR-006.
|
||||
- **FR-008**: The ROM MUST include **selectable** AXP-equivalent call
|
||||
recording unlock (toggle; OFF = stock LOS restrictions, ON = unlock).
|
||||
- **FR-009**: The ROM MUST include the AXP usability/privacy bundled surface
|
||||
@@ -329,12 +380,12 @@ work when published.
|
||||
- **FR-010**: The ROM MUST ship **Magisk** like GOLDEN: newest Magisk stable
|
||||
that works on this stack, in an AXP-like preinstalled but not fully
|
||||
activated layout (exact first-boot/setup behaviour measured from GOLDEN),
|
||||
with DenyList-class hiding sufficient for FR-007. KernelSU is **out of
|
||||
ship for now** (not the resurrection root path).
|
||||
with DenyList-class hiding available. KernelSU is **out of ship for now**
|
||||
(not the resurrection root path).
|
||||
- **FR-011**: The feature acceptance gate MUST include GOLDEN/AXP-class
|
||||
hardening and signing / AVB posture (as applicable on LOS 23.2 / sunfish),
|
||||
not only apps and Google compatibility. Gaps MUST be documented as
|
||||
impossible on this stack rather than silently omitted.
|
||||
userspace hardening and signing / AVB posture (as applicable on LOS 23.2 /
|
||||
sunfish), not only apps and Google compatibility. Gaps MUST be documented
|
||||
as impossible on this stack rather than silently omitted.
|
||||
- **FR-012**: Acceptance flashing MUST use LAB only; GOLDEN MUST remain
|
||||
unmodified by this feature's work.
|
||||
- **FR-013**: Each shipped capability MUST be attributable (what upstream or
|
||||
@@ -354,6 +405,32 @@ work when published.
|
||||
Such reuse is **optional** (“si se puede, ok”), MUST NOT become an
|
||||
acceptance requirement for Magisk resurrection, and MUST NOT imply KernelSU
|
||||
is back in the ship path unless a future spec explicitly says so.
|
||||
- **FR-017**: The ship MUST use an **updated** LineageOS 23.2–compatible
|
||||
`sunfish` kernel (current lineage/kernel_google_sunfish or project-tracked
|
||||
equivalent — not an unrelated Graphene A13 / stock A13 prebuilt), with
|
||||
**attributable kernel hardening** ported from AXP / Graphene / Divest where
|
||||
still valid on non-GKI 4.14. Skipped items MUST be documented with rationale.
|
||||
- **FR-018**: *(Deferred research — look later)* Compare how AXP/GOLDEN
|
||||
hardens or constrains **localization / location** (network location,
|
||||
backends, permissions, privacy toggles) versus stock LineageOS 23 behaviour.
|
||||
Owner historically finds AXP aggressive here; do **not** freeze a
|
||||
clone-or-LOS policy in this feature’s acceptance until that comparison
|
||||
exists. Default until then: do not silently invent extra location lockdown
|
||||
beyond what the rest of the AXP clone already implies; record the open
|
||||
question in the capability matrix.
|
||||
- **FR-019**: On a **final** shipping `009` image, owner MUST be able to
|
||||
refresh bundled **system / privileged** packages by **sideload** (or the
|
||||
documented Magisk-equivalent path) roughly every **2–3 months**, without
|
||||
requiring a full ROM reflash for routine bumps of at least: **microG
|
||||
(GmsCore / companions)**, **Magisk**, **project Phonesky**, and other
|
||||
project-bundled system apps that the capability inventory treats as
|
||||
updatable. Packaging MUST preserve PackageManager update eligibility
|
||||
(matching signing identity; **PRESIGNED** where upstream expects
|
||||
self-updates; project-key continuity for Phonesky). Magisk MAY use its
|
||||
normal manager / boot-image update flow when APK-only sideload is
|
||||
insufficient — that path MUST be documented in the recovery/sideload
|
||||
runbook. This does **not** restore AXP external repos or OTA (still
|
||||
forbidden); updates are owner-driven sideload / recovery packages.
|
||||
|
||||
### Key Entities
|
||||
|
||||
@@ -364,13 +441,16 @@ work when published.
|
||||
(resurrection target).
|
||||
- **Version pin record**: Documented package/component versions chosen for the
|
||||
accepted `009` build (newest workable stable each; Phonesky = project
|
||||
artifact id/version).
|
||||
artifact id/version; kernel rev + hardening patch list).
|
||||
- **Phonesky host artifact**: Project patched/signed Play APK and permission
|
||||
metadata kept outside Git on the build host.
|
||||
- **Magisk preinstall state**: Measured GOLDEN/AXP layout for Magisk present
|
||||
but not fully activated, plus LAB setup steps.
|
||||
- **LAB acceptance build**: Flashable image set + hashes + smoke/banking /
|
||||
Magisk / hardening results for this feature.
|
||||
- **Hardened sunfish kernel**: Updated LOS23-compatible kernel build +
|
||||
attributed hardening patch set for FR-017.
|
||||
- **LAB acceptance build**: Flashable image set + hashes + smoke / Magisk /
|
||||
userspace+kernel hardening results for this feature (banking evidence
|
||||
optional/deferred).
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
@@ -380,15 +460,16 @@ work when published.
|
||||
hardware smoke within the same session as flash (owner can place a call,
|
||||
use Wi‑Fi, and unlock the device).
|
||||
- **SC-002**: 100% of AXP resurrection capability categories from the agreed
|
||||
inventory are either demonstrated on LAB or explicitly documented as
|
||||
impossible on Android 16/sunfish — zero silent omissions (WebView exception
|
||||
allowed only as FR-015).
|
||||
inventory are either demonstrated on LAB, marked deferred (banking,
|
||||
localization compare), or explicitly documented as impossible on Android
|
||||
16/sunfish — zero silent omissions (WebView exception allowed only as
|
||||
FR-015).
|
||||
- **SC-003**: With spoofing enabled as required, microG Self-Check required
|
||||
items and project Phonesky open/install succeed on LAB for ordinary apps on
|
||||
the first accepted build candidate (or within one documented fix iteration).
|
||||
- **SC-004**: Swissquote managed-profile + Magisk DenyList-class workflow
|
||||
PASSes on LAB; Yuh result is recorded and is not worse than GOLDEN for
|
||||
packaging/spoofing reasons.
|
||||
- **SC-004**: *(Deferred with US3)* Swissquote managed-profile + Magisk
|
||||
DenyList-class workflow PASSes on LAB when owner resumes banking; not
|
||||
required for AXP-clone MVP acceptance.
|
||||
- **SC-005**: Every bundled/system app version in the acceptance record
|
||||
(except Phonesky) is newer than or equal to GOLDEN's measured version,
|
||||
unless a newer release was tried and failed with a written regression note;
|
||||
@@ -399,7 +480,16 @@ work when published.
|
||||
can be fully activated on LAB using documented steps measured from GOLDEN.
|
||||
- **SC-008**: Default WebView is LOS23's; provider selection remains available.
|
||||
- **SC-009**: Owner can perform the GOLDEN-equivalent daily checklist on LAB
|
||||
without consulting a scatter of conflicting feature specs for what “ships”.
|
||||
**excluding deferred banking** without consulting a scatter of conflicting
|
||||
feature specs for what “ships”.
|
||||
- **SC-010**: Accepted build records kernel revision + hardening attribution
|
||||
list (applied / skipped+why) satisfying FR-017.
|
||||
- **SC-011**: Acceptance docs list, for each FR-019 component, the intended
|
||||
update channel (sideload APK / recovery zip / Magisk self-update) and confirm
|
||||
signing identity is not broken by packaging (PRESIGNED or project key as
|
||||
applicable). Full 2–3 month refresh drill MAY wait until a final ROM
|
||||
candidate; packaging regressions that block updates MUST be fixed before
|
||||
ship.
|
||||
|
||||
## Assumptions
|
||||
|
||||
@@ -408,11 +498,12 @@ work when published.
|
||||
- GOLDEN inventory (`002`) plus AXP Pro docs are sufficient to enumerate the
|
||||
capability set; live `adb` re-query of GOLDEN is allowed (especially Magisk
|
||||
preinstall/activation details).
|
||||
- “AXP resurrection” means Magisk + GOLDEN-class hardening/signing/AVB + full
|
||||
AXP user surface on LOS23, with only the stated WebView and Phonesky-artifact
|
||||
exceptions.
|
||||
- Island remains the managed-profile tool because that is what GOLDEN
|
||||
actually runs (AXP docs saying “Insular” are historical naming).
|
||||
- “AXP resurrection” / updated clone means Magisk + GOLDEN-class userspace
|
||||
hardening/signing/AVB + AXP user/options surface + updated hardened kernel
|
||||
on LOS23, with WebView, Phonesky-artifact, banking-deferral, and
|
||||
localization-compare exceptions as stated.
|
||||
- Island / banking validation is owner-future; shipping Island as a bundled
|
||||
app is optional and does not imply Gate E.
|
||||
- FakeStore is never the primary Play path.
|
||||
- Selectable spoofing and selectable call recording follow the same class of
|
||||
Developer Options UX already explored in `005`/`008` runbooks where useful.
|
||||
@@ -424,3 +515,10 @@ work when published.
|
||||
- Prior KernelSU LAB experiments (including the two functional kernels already
|
||||
built) are **out of ship for now** but kept as recyclable assets: reuse if
|
||||
helpful, never required for Magisk acceptance.
|
||||
- Localization hardening AXP-vs-LOS comparison is intentionally postponed
|
||||
(FR-018); do not block MVP on it.
|
||||
- No AXP-style OTA or external repos; periodic system-package refresh is
|
||||
**owner sideload** (FR-019), not a network updater in the ROM.
|
||||
- microG stays PRESIGNED / replace-prebuilt so same-signer updates remain
|
||||
possible; Phonesky stays on the project signing key across releases;
|
||||
Magisk update docs cover manager + any boot re-patch when needed.
|
||||
@@ -0,0 +1,339 @@
|
||||
# Tasks: AXP LOS22 feature port to LOS23 (resurrection)
|
||||
|
||||
**Input**: Design documents from `/specs/009-axp-los23-port/`
|
||||
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`,
|
||||
`contracts/`, `quickstart.md`; constitution Magisk-resurrection track;
|
||||
standby KernelSU track (`004`–`008`/`007`) remains untouched
|
||||
|
||||
**Tests**: LAB acceptance only (Gates A–G in `contracts/acceptance-gates.md`).
|
||||
No unit/contract TDD suite requested — validation tasks are adb/flash checks.
|
||||
|
||||
**Organization**: Setup → Foundational → US1 / US2 / US4 / US5 (MVP) → US6 →
|
||||
Polish. **US3 banking is deferred (P3)** — skip for MVP. US5 includes
|
||||
**kernel update + hardening** (FR-017). Localization AXP-vs-LOS (FR-018) =
|
||||
look later, not a ship gate. Full US1 Independent Test needs US2+US4+US5
|
||||
(not banking).
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: Can run in parallel (different files, no incomplete deps)
|
||||
- **[Story]**: US1…US6 from `spec.md`
|
||||
- Include exact file paths in descriptions
|
||||
|
||||
## Path conventions
|
||||
|
||||
- Meta repo: `vendor/sunfish-a16/`, `docs/`, `specs/009-axp-los23-port/`
|
||||
- Build host: `/srv/rom/src/lineage/`, `/srv/rom/prebuilts/`,
|
||||
`/srv/rom/artifacts/009-axp-los23-port/`, `/srv/rom/secrets/`
|
||||
- LAB: `11231JEC207477` only — never GOLDEN flash/modify
|
||||
- GOLDEN: `adb` read-only oracle (esp. Magisk preinstall layout)
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Host dirs, runbook stubs, capability inventory scaffold
|
||||
|
||||
- [x] T001 Create host dirs `/srv/rom/prebuilts/{magisk,axp-apps}/`,
|
||||
`/srv/rom/artifacts/009-axp-los23-port/`, `/srv/rom/logs/009-build/`
|
||||
on `rom-dev01` (android-build writable)
|
||||
- [x] T002 [P] Add stub `docs/009-magisk-preinstall-runbook.md` (GOLDEN
|
||||
measure checklist, activation steps, DenyList banking order, LAB serial)
|
||||
- [x] T003 [P] Add stub `docs/009-version-pins.md` (VersionPinRecord table:
|
||||
component / version_name / version_code / upstream_ref / policy /
|
||||
verified_on)
|
||||
- [x] T004 [P] Add stub `docs/009-capability-matrix.md` mapping
|
||||
`docs/002-golden-inventory.md` + `docs/axp-pro-parity.md` rows →
|
||||
`required` / `exception` / `impossible` per `data-model.md`
|
||||
AxpCapabilitySet
|
||||
- [x] T005 [P] Create `vendor/sunfish-a16/patches/009-axp-los23-port/README.md`
|
||||
(Magisk-resurrection apply order; reuse `005`/`008`; no KernelSU ship;
|
||||
attribute upstreams)
|
||||
|
||||
**Checkpoint**: Dirs + stubs exist; no bacon yet
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Freshness policy, GOLDEN Magisk measurement, product wiring
|
||||
baseline — MUST complete before story packages land on LAB acceptance builds
|
||||
|
||||
**⚠️ CRITICAL**: Blocks user-story packaging/flash acceptance
|
||||
|
||||
- [x] T006 Refresh microG + GSF to newest stable upstream (fetch tags /
|
||||
releases; no stale host cache) into `/srv/rom/prebuilts/microg/` +
|
||||
`VERSIONS.txt`; record pins in `docs/009-version-pins.md`
|
||||
- [x] T007 [P] Confirm project patched Phonesky still present under
|
||||
`/srv/rom/prebuilts/phonesky/` + XMLs; record artifact id in
|
||||
`docs/009-version-pins.md` (`policy=project_phonesky`); halt note if
|
||||
GOLDEN-class gap suspected
|
||||
- [x] T008 [P] Fetch newest Magisk stable that targets this stack into
|
||||
`/srv/rom/prebuilts/magisk/` + `VERSIONS.txt`; record pin in
|
||||
`docs/009-version-pins.md`
|
||||
- [x] T009 Measure GOLDEN Magisk/Magia preinstall layout via `adb` only
|
||||
(paths, packages, first-boot/setup UX) and write results into
|
||||
`docs/009-magisk-preinstall-runbook.md` (FR-010 / contracts/
|
||||
magisk-preinstall.md)
|
||||
- [x] T010 Fill `docs/009-capability-matrix.md` for all GOLDEN/AXP categories
|
||||
(google-stack, spoofing, call-rec, Magisk, bundled apps, DNS/hosts,
|
||||
userspace hardening/signing/AVB, **kernel hardening**, WebView=exception,
|
||||
banking=deferred, localization=deferred FR-018); zero silent omissions
|
||||
- [x] T011 Wire Magisk-resurrection product includes in
|
||||
`vendor/sunfish-a16/` (extend `gms.mk` / add `magisk.mk` or equivalent;
|
||||
keep Phonesky priv-app path; **no FakeStore**; **no KernelSU** product
|
||||
packages) and document include hook in
|
||||
`vendor/sunfish-a16/patches/009-axp-los23-port/README.md`
|
||||
- [x] T012 Confirm `003` vanilla (or documented equivalent) known-good
|
||||
baseline is available for LAB clean-flash acceptance; note rev in
|
||||
`docs/009-version-pins.md` VanillaBaseline row
|
||||
- [x] T013 [P] Confirm optional `007` kernel artifacts remain on host under
|
||||
`/srv/rom/artifacts/007-*/` for FR-016 recycle only; list paths in
|
||||
`docs/009-magisk-preinstall-runbook.md` as non-ship
|
||||
|
||||
**Checkpoint**: Prebuilts fresh, Magisk UX measured, product wire documented —
|
||||
story work can begin
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 — AXP resurrection daily-driver on LAB (Priority: P1) 🎯 MVP framing
|
||||
|
||||
**Goal**: One flashable `009` composition path and Gate A smoke; full
|
||||
daily-driver Independent Test completes after US2+US4+US5 (banking deferred)
|
||||
|
||||
**Independent Test**: Flash one `009` build to LAB; walk GOLDEN checklist
|
||||
**minus banking** from `docs/009-capability-matrix.md`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [x] T014 [US1] Define staged known-good image policy in
|
||||
`docs/009-magisk-preinstall-runbook.md` (retain prior LAB image hashes
|
||||
under `/srv/rom/artifacts/009-axp-los23-port/<build-id>/` per FR-013)
|
||||
- [ ] T015 [US1] Add LAB flash/acceptance checklist linking Gates A–G to
|
||||
`specs/009-axp-los23-port/quickstart.md` and
|
||||
`contracts/acceptance-gates.md` (artifact subdirs `gate-a/`…`gate-g/`)
|
||||
- [ ] T016 [US1] Produce first Magisk-track bacon on `rom-dev01` (detached
|
||||
`/srv/rom/artifacts/bin/rom-detach` / tmux) with current wired packages;
|
||||
logs under `/srv/rom/logs/009-build/`; images + SHA-256 under
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/`
|
||||
- [ ] T017 [US1] Clean-flash LAB `11231JEC207477` only; complete Gate A
|
||||
(boot/home/call/Wi‑Fi/unlock); save `getprop` + notes under
|
||||
`…/<build-id>/gate-a/`
|
||||
- [ ] T018 [US1] After US2+US4+US5 land, re-flash accepted candidate and mark
|
||||
SC-001…SC-003 + SC-005…SC-010 / Gates A–D + F–G in
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/acceptance.md`
|
||||
against `docs/009-capability-matrix.md` (skip Gate E / SC-004)
|
||||
- [ ] T019 [US1] Verify Git/meta-repo contains no proprietary Phonesky APK
|
||||
bytes or secrets; document check in
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/acceptance.md`
|
||||
|
||||
**Checkpoint**: Gate A proven; full US1 Independent Test after US2+US4+US5
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 — Google stack: newest microG + project Phonesky (Priority: P1)
|
||||
|
||||
**Goal**: Newest microG/GSF + project Phonesky + selectable restricted spoofing
|
||||
|
||||
**Independent Test**: microG Self-Check; Phonesky open/install; spoofing
|
||||
OFF/ON per `contracts/toggles-surface.md`
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [ ] T020 [P] [US2] Ensure `vendor/sunfish-a16/gms.mk` +
|
||||
`vendor/sunfish-a16/Android.mk` package refreshed microG/GSF + Phonesky
|
||||
without FakeStore; privilege XMLs remain under
|
||||
`vendor/sunfish-a16/permissions/` and
|
||||
`vendor/sunfish-a16/default-permissions/`
|
||||
- [ ] T021 [P] [US2] Re-apply / verify selectable signature spoofing via
|
||||
`vendor/sunfish-a16/patches/005-sigspoof/apply_005_sigspoof.py` on LOS
|
||||
23.2 tree; document A16 deltas in `docs/005-spoofing-runbook.md` (or
|
||||
`docs/009-magisk-preinstall-runbook.md` cross-link)
|
||||
- [ ] T022 [US2] Build+flash LAB image including Google stack; run Gate B
|
||||
(Self-Check, Phonesky open, ordinary app install/update); evidence under
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/gate-b/`
|
||||
- [ ] T023 [US2] Verify Secure key `allow_signature_fake` OFF/ON behaviour per
|
||||
`contracts/toggles-surface.md`; record in
|
||||
`…/<build-id>/gate-c/spoofing.md`
|
||||
- [x] T024 [US2] Finalize microG/GSF/Phonesky rows in `docs/009-version-pins.md`;
|
||||
if Phonesky lacks GOLDEN-class daily fix → FAIL closed note in
|
||||
`…/<build-id>/gate-b/phonesky-halt.md` (do not accept)
|
||||
|
||||
**Checkpoint**: Gate B + spoofing half of Gate C pass (or explicit Phonesky halt)
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 — Banking (Priority: P3 — deferred)
|
||||
|
||||
**Goal**: Island + Magisk DenyList banking — **owner future; not MVP**
|
||||
|
||||
**Independent Test**: *(when resumed)* Swissquote in Island; Yuh honest; no root
|
||||
|
||||
### Deferred tasks (do not block acceptance)
|
||||
|
||||
- [ ] T025 [P] [US3] *(Deferred)* Stage Island under
|
||||
`/srv/rom/prebuilts/axp-apps/` and wire into `vendor/sunfish-a16/` if
|
||||
desired as optional package; pin in `docs/009-version-pins.md`
|
||||
- [ ] T026 [US3] *(Deferred)* Document GOLDEN banking order in
|
||||
`docs/009-magisk-preinstall-runbook.md`
|
||||
- [ ] T027 [US3] *(Deferred)* Swissquote Gate E under
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/gate-e/swissquote/`
|
||||
- [ ] T028 [US3] *(Deferred)* Yuh classify in `…/gate-e/yuh.md`
|
||||
- [ ] T029 [US3] *(Deferred)* Banks lack root note in `…/gate-e/root-check.md`
|
||||
|
||||
**Checkpoint**: Skipped for MVP — resume only when owner asks
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 4 — Magisk like GOLDEN + selectable call recording (Priority: P1)
|
||||
|
||||
**Goal**: Magisk AXP-like preinstall + DenyList; selectable call-rec unlock
|
||||
|
||||
**Independent Test**: Preinstall state vs GOLDEN notes; activation; DenyList
|
||||
test app; call-rec OFF/ON
|
||||
|
||||
### Implementation for User Story 4
|
||||
|
||||
- [ ] T030 [US4] Implement Magisk AXP-like preinstall packaging from
|
||||
`/srv/rom/prebuilts/magisk/` into `vendor/sunfish-a16/magisk.mk` (or
|
||||
equivalent) matching `docs/009-magisk-preinstall-runbook.md` measured
|
||||
layout (`contracts/magisk-preinstall.md`)
|
||||
- [ ] T031 [P] [US4] Re-apply / verify selectable call-rec unlock via
|
||||
`vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py`
|
||||
(`extendrom_call_recording`); keep default OFF; optional FLAG_SECURE
|
||||
not required for AXP acceptance — document in
|
||||
`docs/008-call-rec-flag-secure-runbook.md`
|
||||
- [ ] T032 [US4] Build+flash LAB; document pre-activation Magisk state vs
|
||||
GOLDEN under `…/<build-id>/magisk/pre-activation.md` (Gate D)
|
||||
- [ ] T033 [US4] Complete Magisk activation on LAB per runbook; configure
|
||||
DenyList-class hide for a **test** package (not bank gate); save version +
|
||||
screenshots under `…/<build-id>/magisk/`
|
||||
- [ ] T034 [US4] Verify `extendrom_call_recording` OFF = stock restrictions,
|
||||
ON = Dialer can record; evidence under
|
||||
`…/<build-id>/gate-c/call-rec.md`
|
||||
- [ ] T035 [US4] Record Magisk version pin (newest workable stable) in
|
||||
`docs/009-version-pins.md`
|
||||
|
||||
**Checkpoint**: Gates C (call-rec) + D pass
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: User Story 5 — Usability, options, hardening + kernel (Priority: P1)
|
||||
|
||||
**Goal**: Bundled AXP surface; LOS23 WebView; userspace hardening/signing;
|
||||
**updated hardened sunfish kernel** (FR-017). Localization compare = later.
|
||||
|
||||
**Independent Test**: Packages vs matrix; WebView LOS; Gate G userspace +
|
||||
kernel attribution (SC-010)
|
||||
|
||||
### Implementation for User Story 5
|
||||
|
||||
- [ ] T036 [P] [US5] Enumerate bundled usability packages from
|
||||
`docs/009-capability-matrix.md` (Aurora, F-Droid/repos as on GOLDEN,
|
||||
launcher/gallery-class, DNS/hosts helpers if required); stage newest
|
||||
workable APKs under `/srv/rom/prebuilts/axp-apps/`
|
||||
- [ ] T037 [US5] Wire bundled apps into `vendor/sunfish-a16/` product
|
||||
makefiles; pin all versions in `docs/009-version-pins.md`
|
||||
- [ ] T038 [P] [US5] Verify WebView policy: no Aosmium; default LOS23
|
||||
provider; chooser unlocked — document in
|
||||
`…/<build-id>/gate-f/webview.md` per `contracts/webview-surface.md`
|
||||
- [ ] T039 [US5] Build+flash LAB; confirm bundled categories present or
|
||||
marked impossible/deferred in `docs/009-capability-matrix.md`; Gate F
|
||||
evidence under `…/<build-id>/gate-f/`
|
||||
- [x] T040 [US5] Define staged userspace hardening/signing/AVB checklist in
|
||||
`docs/009-hardening-signing-checklist.md` (GOLDEN vs LAB measured
|
||||
2026-09-29; release keys yes / bootloader lock wont; stages US-S0…S6)
|
||||
- [ ] T041 [US5] Implement first attributable userspace hardening/signing
|
||||
stage under `vendor/sunfish-a16/patches/009-axp-los23-port/` (US-S1
|
||||
keygen + US-S2 wire); keep known-good prior image
|
||||
(`20260929T123401Z-axp-stage1-combo4`)
|
||||
- [ ] T042 [US5] Inventory LOS23 sunfish kernel tree on `rom-dev01`
|
||||
(`/srv/rom/src/lineage/kernel/google/sunfish` or manifest path); record
|
||||
baseline rev in `docs/009-version-pins.md`
|
||||
- [ ] T043 [US5] Build attributable kernel hardening patch list (AXP /
|
||||
Graphene / Divest → 4.14-safe) in
|
||||
`docs/009-kernel-hardening-map.md` (applied vs skip+why)
|
||||
- [ ] T044 [US5] Apply first kernel hardening stage on LOS23 sunfish kernel;
|
||||
rebuild boot; flash LAB; evidence under `…/<build-id>/gate-g/kernel/`
|
||||
- [ ] T045 [US5] Run Gate G userspace+kernel on accepted candidate; gaps in
|
||||
`…/<build-id>/gate-g/gaps.md`; **do not** block on FR-018 localization
|
||||
- [x] T046 [P] [US5] *(Look later — FR-018)* Stub only:
|
||||
`docs/009-localization-axp-vs-los.md` outlining what to compare later
|
||||
(AXP location lockdown vs stock LOS); no policy decision in MVP
|
||||
- [ ] T046a [P] [US5] *(FR-019 — before final ship)* Write
|
||||
`docs/009-sideload-system-updates.md`: how to refresh microG, Magisk,
|
||||
Phonesky, and other system apps every ~2–3 months without full reflash
|
||||
(signing identity / PRESIGNED / Magisk manager+boot path); verify
|
||||
packaging does not break update eligibility
|
||||
|
||||
**Checkpoint**: Gates F + G (userspace + kernel) for claimed stage; FR-018 stub
|
||||
only; FR-019 runbook before final ship
|
||||
|
||||
---
|
||||
|
||||
## Phase 8: User Story 6 — Parallel tracks stay honest (Priority: P2)
|
||||
|
||||
**Goal**: Docs/branches make Magisk `009` active vs KernelSU standby clear
|
||||
|
||||
**Independent Test**: `specs/004`–`008`/`007` still present; `009` does not
|
||||
retire standby track
|
||||
|
||||
### Implementation for User Story 6
|
||||
|
||||
- [ ] T047 [P] [US6] Update `docs/README.md` (and `AGENTS.md` if needed) to
|
||||
state active Magisk-resurrection track = `009` / this repo; standby
|
||||
KernelSU = sibling `sunfish-a16-rom` + specs `004`–`008`/`007`
|
||||
- [ ] T048 [P] [US6] Add short track note to
|
||||
`specs/009-axp-los23-port/spec.md` only if needed (do **not** rewrite
|
||||
standby feature specs)
|
||||
- [ ] T049 [US6] Remap relevant `docs/axp-pro-parity.md` rows to `009`
|
||||
- [ ] T050 [US6] Confirm `specs/001`–`008`/`007` directories still exist; record in
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/acceptance.md`
|
||||
- [ ] T051 [P] [US6] Document optional FR-016 KSU recycle (non-ship) in
|
||||
`docs/009-magisk-preinstall-runbook.md` + `docs/007-kernelsu-runbook.md`
|
||||
cross-link
|
||||
|
||||
**Checkpoint**: Parallel-track honesty readable without rewriting history
|
||||
|
||||
---
|
||||
|
||||
## Phase 9: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Freshness audit, quickstart validation, handoff
|
||||
|
||||
- [ ] T052 [P] Audit all `docs/009-version-pins.md` rows against freshness
|
||||
policy; fix stale host copies if found
|
||||
- [ ] T053 [P] Run `specs/009-axp-los23-port/quickstart.md` on LAB
|
||||
(**skip Gate E**); fix doc gaps
|
||||
- [ ] T054 Collect final artifacts under
|
||||
`/srv/rom/artifacts/009-axp-los23-port/<build-id>/`
|
||||
- [ ] T055 [P] Add/update `docs/009-gate-handoff.md` (next: banking later;
|
||||
localization compare FR-018 later; sideload refresh cadence FR-019)
|
||||
- [ ] T056 Mark `specs/009-axp-los23-port/spec.md` Status after Gates A–D +
|
||||
F–G
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### MVP order (owner 2026-09-17)
|
||||
|
||||
1. Setup + Foundational
|
||||
2. US2 Google stack
|
||||
3. US4 Magisk + call-rec
|
||||
4. US5 usability + **hardening + kernel**
|
||||
5. US1 full acceptance (T018) **without banking**
|
||||
6. US6 docs
|
||||
7. *(Later)* US3 banking + FR-018 localization compare
|
||||
|
||||
### Suggested MVP scope
|
||||
|
||||
**T001–T024 + T030–T046** (skip T025–T029)
|
||||
|
||||
## Notes
|
||||
|
||||
- Banking Gate E / T025–T029 = deferred (owner future)
|
||||
- Kernel hardening = in-scope (FR-017); localization policy = later (FR-018)
|
||||
- LAB only; never flash GOLDEN
|
||||
- Long builds detached on `rom-dev01`
|
||||
- Owner handles git commit / push / MR
|
||||
@@ -0,0 +1 @@
|
||||
certs/
|
||||
Vendored
+48
@@ -13,6 +13,8 @@ LOCAL_OVERRIDES_PACKAGES := com.google.android.gms
|
||||
LOCAL_SRC_FILES := prebuilt/GmsCore.apk
|
||||
LOCAL_REPLACE_PREBUILT_APK_INSTALLED := $(LOCAL_PATH)/prebuilt/GmsCore.apk
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
# microG v0.3.16+ declares required uses-library com.android.location.provider
|
||||
LOCAL_USES_LIBRARIES := com.android.location.provider
|
||||
LOCAL_OPTIONAL_USES_LIBRARIES := \
|
||||
org.apache.http.legacy \
|
||||
androidx.window.extensions \
|
||||
@@ -47,3 +49,49 @@ LOCAL_OPTIONAL_USES_LIBRARIES := \
|
||||
androidx.window.extensions \
|
||||
androidx.window.sidecar
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
# 009 bundled apps (PRESIGNED; host prebuilts via symlink) → product
|
||||
# Optional window libs: same manifest tags as Phonesky/GmsCore (A16 enforce check).
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := AuroraStore
|
||||
LOCAL_MODULE_CLASS := APPS
|
||||
LOCAL_PRODUCT_MODULE := true
|
||||
LOCAL_CERTIFICATE := PRESIGNED
|
||||
LOCAL_SRC_FILES := prebuilt/AuroraStore.apk
|
||||
LOCAL_REPLACE_PREBUILT_APK_INSTALLED := $(LOCAL_PATH)/prebuilt/AuroraStore.apk
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
LOCAL_OPTIONAL_USES_LIBRARIES := \
|
||||
androidx.window.extensions \
|
||||
androidx.window.sidecar
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Droidify
|
||||
LOCAL_MODULE_CLASS := APPS
|
||||
LOCAL_PRODUCT_MODULE := true
|
||||
LOCAL_CERTIFICATE := PRESIGNED
|
||||
LOCAL_SRC_FILES := prebuilt/Droidify.apk
|
||||
LOCAL_REPLACE_PREBUILT_APK_INSTALLED := $(LOCAL_PATH)/prebuilt/Droidify.apk
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
LOCAL_OPTIONAL_USES_LIBRARIES := \
|
||||
androidx.window.extensions \
|
||||
androidx.window.sidecar
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := FossifyGallery
|
||||
LOCAL_MODULE_CLASS := APPS
|
||||
LOCAL_PRODUCT_MODULE := true
|
||||
LOCAL_CERTIFICATE := PRESIGNED
|
||||
LOCAL_OVERRIDES_PACKAGES := Gallery Gallery2 Glimpse
|
||||
LOCAL_SRC_FILES := prebuilt/FossifyGallery.apk
|
||||
LOCAL_REPLACE_PREBUILT_APK_INSTALLED := $(LOCAL_PATH)/prebuilt/FossifyGallery.apk
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
# US-S4-2 — AXP PRO has no Jelly (system_ext noDefaultBrowserWebView).
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := NoLineageJelly
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_OVERRIDES_PACKAGES := Jelly
|
||||
include $(BUILD_PHONY_PACKAGE)
|
||||
Vendored
+19
@@ -7,3 +7,22 @@
|
||||
# official microG (which breaks F-Droid same-signer updates).
|
||||
|
||||
BOARD_SUPER_PARTITION_ERROR_LIMIT := 9441378304
|
||||
|
||||
# Product LINEAGE_VERSION id: set in vendor/extra/product.mk (via bacon
|
||||
# symlink to extra-product.mk) — BoardConfig is too late for version.mk.
|
||||
# Keep a duplicate here only as documentation / get_build_var fallback.
|
||||
TARGET_UNOFFICIAL_BUILD_ID := AXP-Resurection-Pro
|
||||
|
||||
# US-S3 — project AVB *signing* key (Gate G infrastructure).
|
||||
# Included after device/google/sunfish BoardConfig-common.mk → override here.
|
||||
# Keep WITH_AVB unset → BoardConfigLineage adds vbmeta --flags 3
|
||||
# (HASHTREE_DISABLED|VERIFICATION_DISABLED). Magisk-friendly unlocked LAB;
|
||||
# NOT runtime AVB enforcement / "hardened verified boot".
|
||||
# Bootloader relock = wont. OEM unlocking: leave enabled (escape hatch only).
|
||||
_AXP_AVB_KEY := vendor/sunfish-a16/certs/avb.pem
|
||||
ifneq ($(wildcard $(_AXP_AVB_KEY)),)
|
||||
BOARD_AVB_ALGORITHM := SHA256_RSA4096
|
||||
BOARD_AVB_KEY_PATH := $(_AXP_AVB_KEY)
|
||||
BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA4096
|
||||
BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := $(_AXP_AVB_KEY)
|
||||
endif
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
# Bundled user apps (009) — Aurora Store, Droidify, Fossify Gallery.
|
||||
# APKs live on host at /srv/rom/prebuilts/axp-apps/ (never Git).
|
||||
# Symlink into vendor/sunfish-a16/prebuilt/ before bacon.
|
||||
|
||||
PRODUCT_PACKAGES += \
|
||||
AuroraStore \
|
||||
Droidify \
|
||||
FossifyGallery
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
# AXP Resurection Pro product / OTA identity (009).
|
||||
#
|
||||
# "Pro" marks the full Magisk-resurrection track (not a future slim/minimal
|
||||
# variant). GOLDEN used releasetype PRO + ro.lineage.version=…-sunfish-pro.
|
||||
#
|
||||
# TARGET_UNOFFICIAL_BUILD_ID is set in vendor/extra/product.mk (early Lineage
|
||||
# hook, before version.mk). BoardConfig + this file are not early enough alone.
|
||||
# Ship scripts also publish AXP-Resurection-Pro-*.zip from lineage-*.zip.
|
||||
|
||||
# Identity props (not axp.os endpoints). Empty on GOLDEN for ro.axp.version —
|
||||
# local track marker only.
|
||||
PRODUCT_PRODUCT_PROPERTIES += \
|
||||
ro.axp.resurection.track=pro
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
# Early Lineage hook (vendor/lineage/config/common.mk inherits this *before*
|
||||
# version.mk). Required so LINEAGE_VERSION picks up the unofficial id.
|
||||
# BoardConfig.mk is too late for TARGET_UNOFFICIAL_BUILD_ID.
|
||||
|
||||
TARGET_UNOFFICIAL_BUILD_ID := AXP-Resurection-Pro
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
# US-S4 — userspace hardening (AXP Resurection Pro).
|
||||
# Match AXP.OS PRO sunfish product surface (see hardening/README.md +
|
||||
# docs/009-axp-pro-product-apps-20260324.md).
|
||||
#
|
||||
# Real strips:
|
||||
# US-S4-1 apply_009_drop_openssh_packages.py (common.mk)
|
||||
# US-S4-2 apply_009_drop_jelly_gallery2.py (Jelly + Gallery2)
|
||||
# PRODUCT_PACKAGES filter-out via inherit alone has failed before — keep as
|
||||
# belt-and-suspenders only.
|
||||
|
||||
PRODUCT_PACKAGES := $(filter-out \
|
||||
scp \
|
||||
sftp \
|
||||
ssh \
|
||||
sshd \
|
||||
sshd_config \
|
||||
ssh-keygen \
|
||||
start-ssh \
|
||||
rsync \
|
||||
Jelly \
|
||||
Gallery2 \
|
||||
Glimpse \
|
||||
,$(PRODUCT_PACKAGES))
|
||||
|
||||
PRODUCT_PACKAGES += NoLineageJelly
|
||||
|
||||
PRODUCT_PACKAGES_DEBUG := $(filter-out procmem,$(PRODUCT_PACKAGES_DEBUG))
|
||||
|
||||
# Keep init.openssh.rc — AXP PRO still ships it (mkdir /data/ssh* only).
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
# Magisk preroot (009) — clean Magisk, stock UI, no modules.
|
||||
# Wiring: vendor/sunfish-a16/magisk/{prepare_magisk.sh,patch.sh,apply_releasetools_hook.py}
|
||||
# Runtime: SUNFISH_A16_MAGISK_PREROOT=1 + prepare_magisk.sh before packaging.
|
||||
# Magisk is NOT a PRODUCT_PACKAGE (EXTENDROM-style preroot).
|
||||
|
||||
# No packages — boot is patched at releasetools time.
|
||||
|
||||
# US-S2 release keys (PRODUCT_DEFAULT_DEV_CERTIFICATE) — see signing.mk
|
||||
$(call inherit-product-if-exists, vendor/sunfish-a16/signing.mk)
|
||||
|
||||
# OTA / version branding (TARGET_UNOFFICIAL_BUILD_ID=AXP-Resurection-Pro)
|
||||
$(call inherit-product-if-exists, vendor/sunfish-a16/branding.mk)
|
||||
|
||||
# US-S4-1 userspace hardening (drop product OpenSSH, etc.)
|
||||
$(call inherit-product-if-exists, vendor/sunfish-a16/hardening.mk)
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
# Magisk preroot (sunfish-a16 / 009)
|
||||
|
||||
**Policy:** clone AXP / EXTENDROM `EXTENDROM_PREROOT_BOOT` — do not invent.
|
||||
Diverge only if LOS23 or Magisk version breaks that path.
|
||||
|
||||
**Clean Magisk**, stock UI. No GOLDEN modules. No KernelSU in ship kernel.
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `prepare_magisk.sh` | Unzip Magisk APK → `$OUT_DIR/.magisk` (same as extendrom `er.sh`) |
|
||||
| `patch.sh` | From sfX extendrom — patches boot.img via Magisk `boot_patch.sh` |
|
||||
| `apply_releasetools_hook.py` | Inject into releasetools `common.py` (A16) |
|
||||
|
||||
AXP virgin UX: Magisk not a `PRODUCT_PACKAGE`; root inactive until user
|
||||
Additional Setup. See `docs/009-magisk-preinstall-runbook.md`.
|
||||
|
||||
```bash
|
||||
export SUNFISH_A16_MAGISK_PREROOT=1 # optional; READY file is the real gate
|
||||
MAGISK_STAGE_DIR=$ANDROID_BUILD_TOP/out/.magisk \
|
||||
vendor/sunfish-a16/magisk/prepare_magisk.sh
|
||||
python3 vendor/sunfish-a16/magisk/apply_releasetools_hook.py --top "$ANDROID_BUILD_TOP" --force
|
||||
```
|
||||
|
||||
Hook **v2** runs when `out/.magisk/READY` exists (preferred) and/or
|
||||
`SUNFISH_A16_MAGISK_PREROOT=1`. Env alone is unreliable under soong/ninja.
|
||||
Without READY / env the hook no-ops.
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Idempotent Magisk preroot hook into releasetools common.py (LOS 23.2 / A16).
|
||||
|
||||
Gate (either is enough):
|
||||
- ``out/.magisk/READY`` present (preferred — survives ninja/soong env scrubbing)
|
||||
- ``SUNFISH_A16_MAGISK_PREROOT=1``
|
||||
|
||||
Matches sfX extendrom inject (always-on once staged), adapted for A16 + our
|
||||
vendor path. ``RunAndCheckOutput`` env is merged with ``os.environ`` so PATH /
|
||||
ANDROID_BUILD_TOP survive (extendrom only passed ``system_root_image``; that
|
||||
works via shebang but is fragile under sandboxes).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
MARKER = "SUNFISH_A16: Magisk preroot hook"
|
||||
MARKER_VER = "SUNFISH_A16: Magisk preroot hook v2"
|
||||
|
||||
BUILD_HOOK = '''
|
||||
# SUNFISH_A16: Magisk preroot hook v2 (before AVB)
|
||||
# Gate: staged out/.magisk/READY and/or SUNFISH_A16_MAGISK_PREROOT=1
|
||||
_sf_top = os.getenv("ANDROID_BUILD_TOP") or os.environ.get("PWD") or os.getcwd()
|
||||
_sf_ready = os.path.isfile(os.path.join(_sf_top, "out", ".magisk", "READY"))
|
||||
_sf_env = os.environ.get("SUNFISH_A16_MAGISK_PREROOT") == "1"
|
||||
if _sf_ready or _sf_env:
|
||||
if ((partition_name == "boot" and info_dict.get("init_boot") != "true")
|
||||
or partition_name == "init_boot"):
|
||||
mpatcher = [
|
||||
os.path.join(_sf_top, "vendor/sunfish-a16/magisk/patch.sh"),
|
||||
img.name,
|
||||
_sf_top,
|
||||
]
|
||||
logger.info("SUNFISH_A16 Magisk patching (build): %s", img.name)
|
||||
_sf_penv = os.environ.copy()
|
||||
_sf_penv["system_root_image"] = info_dict.get("system_root_image", "false")
|
||||
_sf_penv.setdefault("ANDROID_BUILD_TOP", _sf_top)
|
||||
RunAndCheckOutput(mpatcher, verbose=True, env=_sf_penv)
|
||||
'''
|
||||
|
||||
PREBUILT_HOOK = '''
|
||||
# SUNFISH_A16: Magisk preroot hook v2 (prebuilt)
|
||||
_sf_top = os.getenv("ANDROID_BUILD_TOP") or os.environ.get("PWD") or os.getcwd()
|
||||
_sf_ready = os.path.isfile(os.path.join(_sf_top, "out", ".magisk", "READY"))
|
||||
_sf_env = os.environ.get("SUNFISH_A16_MAGISK_PREROOT") == "1"
|
||||
if _sf_ready or _sf_env:
|
||||
if ((prebuilt_name == "boot.img" or prebuilt_name == "init_boot.img")
|
||||
and os.path.exists(prebuilt_path)):
|
||||
if info_dict is None:
|
||||
info_dict = OPTIONS.info_dict
|
||||
bimg = os.path.join(_sf_top, prebuilt_path)
|
||||
logger.info("SUNFISH_A16 Magisk patching (prebuilt): %s", bimg)
|
||||
mpatcher = [
|
||||
os.path.join(_sf_top, "vendor/sunfish-a16/magisk/patch.sh"),
|
||||
bimg,
|
||||
_sf_top,
|
||||
]
|
||||
_sf_penv = os.environ.copy()
|
||||
_sf_penv["system_root_image"] = info_dict.get("system_root_image", "false")
|
||||
_sf_penv.setdefault("ANDROID_BUILD_TOP", _sf_top)
|
||||
RunAndCheckOutput(mpatcher, verbose=True, env=_sf_penv)
|
||||
'''
|
||||
|
||||
|
||||
def _strip_old_hooks(text: str) -> str:
|
||||
"""Remove prior SUNFISH Magisk hook blocks (v1 gated or v2)."""
|
||||
# Build hook: from our comment through just before AVB block
|
||||
text = re.sub(
|
||||
r"\n # SUNFISH_A16: Magisk preroot hook(?: v2)? \(before AVB\).*?"
|
||||
r"(?=\n # AVB: if enabled)",
|
||||
"\n",
|
||||
text,
|
||||
count=1,
|
||||
flags=re.S,
|
||||
)
|
||||
# Prebuilt hook: after BOOTABLE_IMAGES assign, before "if os.path.exists(prebuilt_path)"
|
||||
text = re.sub(
|
||||
r"( prebuilt_path = os\.path\.join\(unpack_dir, \"BOOTABLE_IMAGES\", prebuilt_name\)\n)"
|
||||
r"\n # SUNFISH_A16: Magisk preroot hook(?: v2)? \(prebuilt\).*?"
|
||||
r"(?=\n if os\.path\.exists\(prebuilt_path\):)",
|
||||
r"\1",
|
||||
text,
|
||||
count=1,
|
||||
flags=re.S,
|
||||
)
|
||||
return text
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--top", default=os.environ.get("ANDROID_BUILD_TOP", ""))
|
||||
ap.add_argument("--dry-run", action="store_true")
|
||||
ap.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Replace an existing SUNFISH Magisk hook with v2",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
top = pathlib.Path(args.top or ".")
|
||||
target = top / "build/make/tools/releasetools/common.py"
|
||||
if not target.is_file():
|
||||
print(f"ERROR: missing {target}", file=sys.stderr)
|
||||
return 2
|
||||
text = target.read_text()
|
||||
|
||||
if MARKER_VER in text and not args.force:
|
||||
print(f"already applied (v2): {target}")
|
||||
return 0
|
||||
|
||||
if MARKER in text or MARKER_VER in text:
|
||||
if not args.force and MARKER_VER not in text:
|
||||
# old v1 present — upgrade
|
||||
pass
|
||||
text = _strip_old_hooks(text)
|
||||
|
||||
needle_avb = (
|
||||
' # AVB: if enabled, calculate and add hash to boot.img or recovery.img.\n'
|
||||
' if info_dict.get("avb_enable") == "true":\n'
|
||||
' avbtool = info_dict["avb_avbtool"]\n'
|
||||
' if partition_name == "recovery":'
|
||||
)
|
||||
idx = text.find(needle_avb)
|
||||
if idx < 0:
|
||||
print("ERROR: AVB anchor not found", file=sys.stderr)
|
||||
return 3
|
||||
text = text[:idx] + BUILD_HOOK + "\n" + text[idx:]
|
||||
|
||||
assign = ' prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name)\n'
|
||||
idx2 = text.find(assign)
|
||||
if idx2 < 0:
|
||||
print("ERROR: prebuilt assign not found", file=sys.stderr)
|
||||
return 4
|
||||
insert_at = idx2 + len(assign)
|
||||
text = text[:insert_at] + PREBUILT_HOOK + "\n" + text[insert_at:]
|
||||
|
||||
if args.dry_run:
|
||||
print("dry-run OK (v2)")
|
||||
return 0
|
||||
target.write_text(text)
|
||||
print(f"applied v2 -> {target}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
#########################################################################################################
|
||||
#
|
||||
# simple patch wrapper for patching a boot.img during the build process
|
||||
#
|
||||
#########################################################################################################
|
||||
#
|
||||
# Copyright (C) 2023-2024 steadfasterX <steadfasterX -AT- binbash #DOT# rocks>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#########################################################################################################
|
||||
#
|
||||
# usage:
|
||||
# ./patch.sh <full-path-of-boot.img>
|
||||
#
|
||||
#########################################################################################################
|
||||
|
||||
# DO NOT set -e !
|
||||
|
||||
# parse calling params
|
||||
export BOOTIMG="$1"
|
||||
export TOP="$2"
|
||||
[ -z "$TOP" -o ! -d "$TOP" ] && TOP=$PWD
|
||||
|
||||
# colored (optional) output
|
||||
PRINT(){
|
||||
MSG="$2"
|
||||
case $1 in
|
||||
[1-9]*|E|ERROR)
|
||||
echo -e "\e[0;31m$0 - ERROR: ${MSG}\e[0m" ;;
|
||||
I|INFO)
|
||||
echo -e "\e[1;34m$0 - INFO: ${MSG}\e[0m" ;;
|
||||
0|OK|SUCCESS)
|
||||
echo -e "\e[0;32m$0 - OK: ${MSG}\e[0m" ;;
|
||||
*)
|
||||
echo -e "$0 - ${MSG}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
PRINT I "Starting: $0 with: >$BOOTIMG< (TOP=$TOP)"
|
||||
|
||||
# LEGACYSAR can't be detected by the magisk patcher so must be set by us where needed (e.g. fajita).
|
||||
# LEGACYSAR ensures kernel gets patched if required.
|
||||
# https://github.com/topjohnwu/Magisk/blob/9aa466c7730ef4ef73195b476f9804ebf86932d2/scripts/boot_patch.sh#L220-L243
|
||||
export LEGACYSAR=${system_root_image}
|
||||
PRINT I "system_root_image=$LEGACYSAR"
|
||||
|
||||
# PREINITDEVICE can't be detected during build so must be set manually
|
||||
# otherwise "Requires Additional Setup" on first start will not be able to patch w/o direct flash
|
||||
# which is a problem on locked devices (obviously)
|
||||
# https://github.com/AXP-OS/build/wiki/Frequently-Asked-Questions#magisk-requires-additional-setup-on-start
|
||||
export PREINITDEVICE=userdata
|
||||
|
||||
# tell magisk that we are not in booted android
|
||||
export BOOTMODE=false
|
||||
|
||||
# set output file descriptor to pts0 which *should* be the current shell
|
||||
export OUTFD=0
|
||||
|
||||
# do not remove verity nor encryption
|
||||
export KEEPVERITY=true
|
||||
export KEEPFORCEENCRYPT=true
|
||||
|
||||
# set magisk environment
|
||||
export OUT_DIR=$TOP/out
|
||||
export MAG_DIR="$OUT_DIR/.magisk"
|
||||
|
||||
# disable due to not allowed binary or useless within the build process
|
||||
alias dos2unix=
|
||||
alias mount=echo
|
||||
alias umount=echo
|
||||
|
||||
# enable a fallback to get properties, according to:
|
||||
# https://github.com/topjohnwu/Magisk/blob/4eaf701cb79cd9255333abad8482e69987f86280/scripts/util_functions.sh#L59
|
||||
getprop(){
|
||||
find $OUT_DIR/target/product -type f -name build.prop -exec grep $1 {} \; | tail -n1
|
||||
}; export -f getprop
|
||||
|
||||
test -e $BOOTIMG
|
||||
PRINT $? "testing existence of >$BOOTIMG< returned: $?"
|
||||
|
||||
# do the magisk magic
|
||||
/bin/bash $MAG_DIR/boot_patch.sh "$BOOTIMG" \
|
||||
&& cp -v $MAG_DIR/new-boot.img "$BOOTIMG"
|
||||
RET=$?
|
||||
|
||||
# simple check if magisk can be found in the resulting boot.img
|
||||
grep -q --text 'magisk' $BOOTIMG
|
||||
MCHK=$?
|
||||
|
||||
# sometimes the above is not valid even though patching was successful
|
||||
if [ $MCHK -ne 0 ];then
|
||||
PRINT I "Simple magisk check failed, unpacking for a detailed test..\n"
|
||||
[ -d "$MAG_DIR/test" ] && rm -rf $MAG_DIR/test
|
||||
mkdir $MAG_DIR/test
|
||||
cd $MAG_DIR/test
|
||||
$MAG_DIR/magiskboot unpack $BOOTIMG && $MAG_DIR/magiskboot cpio ramdisk.cpio test
|
||||
case $? in
|
||||
1|4) MCHK=0;;
|
||||
*) ;;
|
||||
esac
|
||||
cd $TOP
|
||||
rm -rf $MAG_DIR/test
|
||||
fi
|
||||
|
||||
# check & print result
|
||||
if [ "$MCHK" -eq 0 ];then PRINT OK "MAGISK found in $BOOTIMG!";else PRINT E "Magisk not found in $BOOTIMG!";fi
|
||||
RET=$((RET + $MCHK))
|
||||
|
||||
PRINT $RET "ended with: $RET\n\n"
|
||||
exit $RET
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Stage Magisk v22+ APK into $OUT_DIR/.magisk (or MAGISK_STAGE_DIR) for preroot.
|
||||
# Attribute: sfX-android extendrom er.sh MAGISK block + Magisk upstream.
|
||||
set -euo pipefail
|
||||
TOP="${ANDROID_BUILD_TOP:-${1:-}}"
|
||||
OUT_DIR="${OUT_DIR:-$TOP/out}"
|
||||
STAGE="${MAGISK_STAGE_DIR:-$OUT_DIR/.magisk}"
|
||||
APK="${MAGISK_APK:-/srv/rom/prebuilts/magisk/Magisk-v30.7.apk}"
|
||||
ARCH="${MAGISK_TARGET_ARCH:-arm64}"
|
||||
|
||||
if [ -z "$TOP" ] || [ ! -d "$TOP" ]; then
|
||||
echo "Usage: ANDROID_BUILD_TOP=/path prepare_magisk.sh" >&2
|
||||
exit 2
|
||||
fi
|
||||
test -f "$APK" || { echo "Missing Magisk APK: $APK" >&2; exit 4; }
|
||||
|
||||
rm -rf "$STAGE"
|
||||
mkdir -p "$STAGE"
|
||||
unzip -q "$APK" -d "$STAGE/src"
|
||||
|
||||
# Host tools (x86_64) for patching during build
|
||||
cp "$STAGE/src/lib/x86_64/libmagiskboot.so" "$STAGE/magiskboot" 2>/dev/null \
|
||||
|| cp "$STAGE/src/lib/x86/libmagiskboot.so" "$STAGE/magiskboot"
|
||||
chmod 755 "$STAGE/magiskboot"
|
||||
|
||||
if [ "$ARCH" = "arm64" ]; then
|
||||
if [ -f "$STAGE/src/lib/arm64-v8a/libmagisk64.so" ]; then
|
||||
cp "$STAGE/src/lib/arm64-v8a/libmagisk64.so" "$STAGE/magisk64"
|
||||
else
|
||||
cp "$STAGE/src/lib/arm64-v8a/libmagisk.so" "$STAGE/magisk"
|
||||
fi
|
||||
cp "$STAGE/src/lib/arm64-v8a/libmagiskinit.so" "$STAGE/magiskinit"
|
||||
[ -f "$STAGE/src/lib/arm64-v8a/libinit-ld.so" ] && cp "$STAGE/src/lib/arm64-v8a/libinit-ld.so" "$STAGE/init-ld"
|
||||
[ -f "$STAGE/src/lib/arm64-v8a/libmagiskpolicy.so" ] && cp "$STAGE/src/lib/arm64-v8a/libmagiskpolicy.so" "$STAGE/magiskpolicy"
|
||||
else
|
||||
echo "Unsupported MAGISK_TARGET_ARCH=$ARCH" >&2
|
||||
exit 4
|
||||
fi
|
||||
|
||||
chmod 755 "$STAGE/src/assets/boot_patch.sh"
|
||||
rm -rf "$STAGE/src/assets/dexopt" "$STAGE/src/assets/chromeos" 2>/dev/null || true
|
||||
cp "$STAGE/src/assets/"* "$STAGE/"
|
||||
cp "$STAGE/src/assets/boot_patch.sh" "$STAGE/root_boot.sh"
|
||||
chmod 755 "$STAGE/boot_patch.sh" "$STAGE/magiskinit" "$STAGE/magiskboot"
|
||||
[ -f "$STAGE/magisk64" ] && chmod 755 "$STAGE/magisk64"
|
||||
[ -f "$STAGE/magisk" ] && chmod 755 "$STAGE/magisk"
|
||||
[ -f "$STAGE/init-ld" ] && chmod 755 "$STAGE/init-ld"
|
||||
|
||||
# Point patch.sh at our vendor copy
|
||||
MARKER="$STAGE/READY"
|
||||
echo "apk=$(basename "$APK")" > "$MARKER"
|
||||
echo "arch=$ARCH" >> "$MARKER"
|
||||
echo "staged=$(date -u -Iseconds)" >> "$MARKER"
|
||||
echo "OK Magisk staged at $STAGE"
|
||||
cat "$MARKER"
|
||||
@@ -10,9 +10,11 @@ python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_f
|
||||
|
||||
- **Call recording**: EXTENDROM `er.sh` F_CALLREC / AXP GOLDEN
|
||||
(`extendrom_call_recording`). steadfasterX EXTENDROM.
|
||||
- **FLAG_SECURE**: AOSP `Settings.Secure.DISABLE_SECURE_WINDOWS` already
|
||||
wired in `WindowManagerService` on A16; DO preference
|
||||
`allow_flag_secure_override` writes that key.
|
||||
- **FLAG_SECURE**: AOSP `Settings.Secure.DISABLE_SECURE_WINDOWS` + DO
|
||||
preference `allow_flag_secure_override`. Stock WMS only applies the
|
||||
setting when `ro.debuggable=1`; we remove that gate via
|
||||
`apply_wms_disable_secure_debuggable_gate.py` so ship images keep
|
||||
`ro.debuggable=0` while the toggle still works.
|
||||
|
||||
## Touched paths
|
||||
|
||||
@@ -24,9 +26,15 @@ python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_f
|
||||
| Settings controllers | `…/ER_CallRec*.java`, `…/FlagSecureOverride*.java` |
|
||||
| Settings DO XML + strings | `res/xml/development_settings.xml`, `res/values/strings.xml` |
|
||||
| Dashboard | `DevelopmentSettingsDashboardFragment.java` |
|
||||
| Capture path | stock WMS `disable_secure_windows` (no extra WM patch) |
|
||||
| Capture path | WMS `updateDisableSecureWindows()` — **no** `ro.debuggable` gate |
|
||||
| WMS apply | `apply_wms_disable_secure_debuggable_gate.py` |
|
||||
|
||||
```bash
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
```
|
||||
|
||||
Backups: `/srv/rom/artifacts/008-call-rec-flag-secure/bak-snapshots/`
|
||||
Marker: `SUNFISH_A16_008_CALL_REC_FLAG_SECURE`
|
||||
Markers: `SUNFISH_A16_008_CALL_REC_FLAG_SECURE`,
|
||||
`SUNFISH_A16_008_WMS_DISABLE_SECURE_NO_DEBUGGABLE_GATE`
|
||||
|
||||
See `docs/008-call-rec-flag-secure-runbook.md`.
|
||||
+23
-8
@@ -5,16 +5,18 @@ Call recording (AXP GOLDEN / EXTENDROM F_CALLREC):
|
||||
- Settings.Secure.ER_ALLOW_ANY_CALL_REC = \"extendrom_call_recording\"
|
||||
- DO switch + Dialer CallRecorder.canRecordInCurrentCountry early-return
|
||||
|
||||
FLAG_SECURE (AOSP A16 already implements WM path):
|
||||
FLAG_SECURE (AOSP A16 WM path + project WMS gate removal):
|
||||
- DO switch writes Settings.Secure.DISABLE_SECURE_WINDOWS
|
||||
(\"disable_secure_windows\"). WindowManagerService.updateDisableSecureWindows()
|
||||
already honours it on debuggable builds (LAB userdebug).
|
||||
(\"disable_secure_windows\").
|
||||
- Also run apply_wms_disable_secure_debuggable_gate.py so WMS honours the
|
||||
setting with ro.debuggable=0 (stock AOSP required debuggable).
|
||||
|
||||
Attribution: EXTENDROM (steadfasterX) for call-rec; AOSP DISABLE_SECURE_WINDOWS
|
||||
for capture; sunfish-a16 DO wiring.
|
||||
for capture; sunfish-a16 DO + WMS gate wiring.
|
||||
|
||||
Run on rom-dev01:
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_wms_disable_secure_debuggable_gate.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -125,8 +127,9 @@ public class ER_CallRecInfo extends DeveloperOptionsPreferenceController
|
||||
|
||||
FLAG_SECURE_CTRL = """/*
|
||||
* sunfish-a16-rom ({marker}): Developer Options gate for AOSP
|
||||
* Settings.Secure.DISABLE_SECURE_WINDOWS (WindowManagerService already
|
||||
* honours this on debuggable builds).
|
||||
* Settings.Secure.DISABLE_SECURE_WINDOWS. Pair with
|
||||
* apply_wms_disable_secure_debuggable_gate.py so WMS honours the setting
|
||||
* when ro.debuggable=0.
|
||||
*/
|
||||
|
||||
package com.android.settings.development;
|
||||
@@ -406,8 +409,8 @@ def patch_strings() -> None:
|
||||
<!-- {MARKER}: FLAG_SECURE override (writes AOSP disable_secure_windows) -->
|
||||
<string name="flag_secure_override_category">Secure window screenshots</string>
|
||||
<string name="allow_flag_secure_override">Allow screenshots of secure windows</string>
|
||||
<string name="allow_flag_secure_override_summary">When enabled, apps that set FLAG_SECURE can still be captured by the system screenshot / screen record paths (debuggable builds). Weakens app privacy.</string>
|
||||
<string name="allow_flag_secure_override_details">Writes Settings.Secure.disable_secure_windows. On userdebug/eng, WindowManager treats FLAG_SECURE windows as capturable. Default OFF restores stock secure-window behaviour.</string>
|
||||
<string name="allow_flag_secure_override_summary">When enabled, apps that set FLAG_SECURE can still be captured by the system screenshot / screen record paths. Weakens app privacy. Does not change ro.debuggable.</string>
|
||||
<string name="allow_flag_secure_override_details">Writes Settings.Secure.disable_secure_windows. WindowManager treats FLAG_SECURE windows as capturable while this is ON (project build; ro.debuggable stays 0). Default OFF restores stock secure-window behaviour.</string>
|
||||
"""
|
||||
text = text.replace("</resources>", add + "</resources>", 1)
|
||||
path.write_text(text)
|
||||
@@ -458,6 +461,17 @@ def verify_dialer_config() -> None:
|
||||
print("Dialer config.xml: call_recording_audio_source=4 (OK)")
|
||||
|
||||
|
||||
def apply_wms_gate() -> None:
|
||||
"""Invoke sibling script that drops the ro.debuggable gate in WMS."""
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
sibling = Path(__file__).resolve().parent / "apply_wms_disable_secure_debuggable_gate.py"
|
||||
r = subprocess.run([sys.executable, str(sibling)], check=False)
|
||||
if r.returncode != 0:
|
||||
raise SystemExit(f"WMS disable-secure gate apply failed: {r.returncode}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not TREE.is_dir():
|
||||
raise SystemExit(f"LOS tree missing: {TREE}")
|
||||
@@ -475,6 +489,7 @@ def main() -> None:
|
||||
patch_development_xml()
|
||||
patch_dashboard()
|
||||
verify_dialer_config()
|
||||
apply_wms_gate()
|
||||
print("done:", MARKER)
|
||||
|
||||
|
||||
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Remove AOSP ro.debuggable gate on Settings.Secure.DISABLE_SECURE_WINDOWS.
|
||||
|
||||
LOS 23.2 / A16 WindowManagerService.updateDisableSecureWindows() returns early
|
||||
unless SystemProperties.getBoolean(\"ro.debuggable\") is true. That blocks the
|
||||
Developer Options toggle on builds that keep ro.debuggable=0 (including this
|
||||
project's LAB image labelled userdebug).
|
||||
|
||||
This patch removes ONLY that gate. Behaviour:
|
||||
disable_secure_windows=0 → stock FLAG_SECURE (mDisableSecureWindows=false)
|
||||
disable_secure_windows=1 → mDisableSecureWindows=true; isSecureLocked()/Task.isSecure()
|
||||
honour the override (no second debuggable check elsewhere)
|
||||
|
||||
Does NOT change ro.debuggable, Build.IS_DEBUGGABLE, ViewServer, or screen-share
|
||||
protections (DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS).
|
||||
|
||||
Audit (LOS23 frameworks/base, 2026-09-18): sole gate is updateDisableSecureWindows();
|
||||
WindowState.isSecureLocked / Task.isSecure only call getDisableSecureWindows().
|
||||
|
||||
Run on rom-dev01:
|
||||
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/\\
|
||||
apply_wms_disable_secure_debuggable_gate.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
TREE = Path("/srv/rom/src/lineage")
|
||||
MARKER = "SUNFISH_A16_008_WMS_DISABLE_SECURE_NO_DEBUGGABLE_GATE"
|
||||
BAK_ROOT = Path("/srv/rom/artifacts/008-call-rec-flag-secure/bak-snapshots")
|
||||
WMS = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/wm/"
|
||||
"WindowManagerService.java"
|
||||
)
|
||||
|
||||
OLD = """ void updateDisableSecureWindows() {
|
||||
if (!SystemProperties.getBoolean(SYSTEM_DEBUGGABLE, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean disableSecureWindows;
|
||||
"""
|
||||
|
||||
NEW = f""" void updateDisableSecureWindows() {{
|
||||
// {MARKER}: honour Settings.Secure.DISABLE_SECURE_WINDOWS even when
|
||||
// ro.debuggable=0. Stock AOSP gated this on SYSTEM_DEBUGGABLE; ship
|
||||
// builds keep debuggable off and use the Secure setting alone.
|
||||
boolean disableSecureWindows;
|
||||
"""
|
||||
|
||||
|
||||
def backup(path: Path) -> None:
|
||||
BAK_ROOT.mkdir(parents=True, exist_ok=True)
|
||||
dest = BAK_ROOT / path.name
|
||||
if not dest.exists():
|
||||
shutil.copy2(path, dest)
|
||||
print(f"backup -> {dest}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not WMS.is_file():
|
||||
print(f"ERROR: missing {WMS}")
|
||||
return 2
|
||||
text = WMS.read_text()
|
||||
if MARKER in text:
|
||||
print(f"already applied: {WMS}")
|
||||
return 0
|
||||
if OLD not in text:
|
||||
print("ERROR: expected updateDisableSecureWindows debuggable gate not found")
|
||||
print("(tree already diverged — inspect manually)")
|
||||
return 3
|
||||
backup(WMS)
|
||||
WMS.write_text(text.replace(OLD, NEW, 1))
|
||||
print(f"applied -> {WMS}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Attribute: AXP GOLDEN ConnectivityCheckPreferenceController (Settings.apk),
|
||||
* cloned for LOS 23.2 without axp.os / captiveportal.axpos.org endpoints.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
package com.android.settings.network;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
/** Internet connectivity check provider list (captive portal URLs). */
|
||||
public class ConnectivityCheckPreferenceController extends BasePreferenceController
|
||||
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener, OnResume {
|
||||
|
||||
private static final String KEY = "connectivity_check_settings";
|
||||
|
||||
private static final int DISABLED = 0;
|
||||
private static final int AMAZON = 1;
|
||||
private static final int CLOUDFLARE = 2;
|
||||
private static final int GOOGLE = 3;
|
||||
private static final int HUAWEI = 4;
|
||||
private static final int KUKETZ = 5;
|
||||
private static final int MICROSOFT = 6;
|
||||
private static final int OPENSUSE = 7;
|
||||
private static final int UBUNTU = 8;
|
||||
|
||||
private ListPreference mConnectivityPreference;
|
||||
|
||||
public ConnectivityCheckPreferenceController(Context context) {
|
||||
super(context, KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return isDisabledByAdmin() ? DISABLED_FOR_USER : AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
ListPreference pref = new ListPreference(screen.getContext());
|
||||
pref.setKey(KEY);
|
||||
pref.setOrder(30);
|
||||
pref.setIcon(R.drawable.ic_settings_language);
|
||||
pref.setTitle(R.string.connectivity_check_title);
|
||||
pref.setSummary(R.string.connectivity_check_summary);
|
||||
pref.setEntries(R.array.connectivity_check_entries);
|
||||
pref.setEntryValues(R.array.connectivity_check_values);
|
||||
pref.setOnPreferenceChangeListener(this);
|
||||
if (mConnectivityPreference == null) {
|
||||
screen.addPreference(pref);
|
||||
mConnectivityPreference = pref;
|
||||
}
|
||||
super.displayPreference(screen);
|
||||
updatePreferenceState();
|
||||
}
|
||||
|
||||
private void updatePreferenceState() {
|
||||
if (mConnectivityPreference == null) {
|
||||
return;
|
||||
}
|
||||
ContentResolver cr = mContext.getContentResolver();
|
||||
int mode = Settings.Global.getInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, 1);
|
||||
if (mode == 0) {
|
||||
mConnectivityPreference.setValueIndex(DISABLED);
|
||||
return;
|
||||
}
|
||||
String http = Settings.Global.getString(cr, Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
|
||||
int idx = GOOGLE;
|
||||
if ("http://fireoscaptiveportal.com/generate_204".equals(http)) {
|
||||
idx = AMAZON;
|
||||
} else if ("http://cp.cloudflare.com".equals(http)) {
|
||||
idx = CLOUDFLARE;
|
||||
} else if ("http://connectivitycheck.gstatic.com/generate_204".equals(http)) {
|
||||
idx = GOOGLE;
|
||||
} else if ("http://connectivitycheck.platform.hicloud.com/generate_204".equals(http)) {
|
||||
idx = HUAWEI;
|
||||
} else if ("http://captiveportal.kuketz.de".equals(http)) {
|
||||
idx = KUKETZ;
|
||||
} else if ("http://edge-http.microsoft.com/captiveportal/generate_204".equals(http)) {
|
||||
idx = MICROSOFT;
|
||||
} else if ("http://conncheck.opensuse.org".equals(http)) {
|
||||
idx = OPENSUSE;
|
||||
} else if ("http://connectivity-check.ubuntu.com".equals(http)) {
|
||||
idx = UBUNTU;
|
||||
}
|
||||
mConnectivityPreference.setValueIndex(idx);
|
||||
}
|
||||
|
||||
private void setCaptivePortalURLs(ContentResolver cr, int value) {
|
||||
final String httpKey = Settings.Global.CAPTIVE_PORTAL_HTTP_URL;
|
||||
final String httpsKey = Settings.Global.CAPTIVE_PORTAL_HTTPS_URL;
|
||||
final String fallbackKey = Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL;
|
||||
final String otherKey = Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
|
||||
final String modeKey = Settings.Global.CAPTIVE_PORTAL_MODE;
|
||||
|
||||
String http;
|
||||
String https;
|
||||
String fallback;
|
||||
String other;
|
||||
int mode = 1;
|
||||
|
||||
switch (value) {
|
||||
case DISABLED:
|
||||
// Match GOLDEN: write Google URLs then mode=0
|
||||
http = "http://connectivitycheck.gstatic.com/generate_204";
|
||||
https = "https://www.google.com/generate_204";
|
||||
fallback = "http://www.google.com/gen_204";
|
||||
other = "http://play.googleapis.com/generate_204";
|
||||
mode = 0;
|
||||
break;
|
||||
case AMAZON:
|
||||
http = "http://fireoscaptiveportal.com/generate_204";
|
||||
https = "https://fireoscaptiveportal.com/generate_204";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case CLOUDFLARE:
|
||||
http = "http://cp.cloudflare.com";
|
||||
https = "https://cp.cloudflare.com";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case HUAWEI:
|
||||
http = "http://connectivitycheck.platform.hicloud.com/generate_204";
|
||||
https = "https://connectivitycheck.platform.hicloud.com/generate_204";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case KUKETZ:
|
||||
http = "http://captiveportal.kuketz.de";
|
||||
https = "https://captiveportal.kuketz.de";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case MICROSOFT:
|
||||
http = "http://edge-http.microsoft.com/captiveportal/generate_204";
|
||||
https = http;
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case OPENSUSE:
|
||||
http = "http://conncheck.opensuse.org";
|
||||
https = "https://conncheck.opensuse.org";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case UBUNTU:
|
||||
http = "http://connectivity-check.ubuntu.com";
|
||||
https = "https://connectivity-check.ubuntu.com";
|
||||
fallback = http;
|
||||
other = http;
|
||||
break;
|
||||
case GOOGLE:
|
||||
default:
|
||||
http = "http://connectivitycheck.gstatic.com/generate_204";
|
||||
https = "https://www.google.com/generate_204";
|
||||
fallback = "http://www.google.com/gen_204";
|
||||
other = "http://play.googleapis.com/generate_204";
|
||||
break;
|
||||
}
|
||||
|
||||
Settings.Global.putString(cr, httpKey, http);
|
||||
Settings.Global.putString(cr, httpsKey, https);
|
||||
Settings.Global.putString(cr, fallbackKey, fallback);
|
||||
Settings.Global.putString(cr, otherKey, other);
|
||||
Settings.Global.putInt(cr, modeKey, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (KEY.equals(preference.getKey())) {
|
||||
setCaptivePortalURLs(
|
||||
mContext.getContentResolver(), Integer.parseInt((String) newValue));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
updatePreferenceState();
|
||||
if (mConnectivityPreference != null && mConnectivityPreference.getValue() != null) {
|
||||
setCaptivePortalURLs(
|
||||
mContext.getContentResolver(),
|
||||
Integer.parseInt(mConnectivityPreference.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
private EnforcedAdmin getEnforcedAdmin() {
|
||||
return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
|
||||
mContext, UserManager.DISALLOW_CONFIG_PRIVATE_DNS, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
private boolean isDisabledByAdmin() {
|
||||
return getEnforcedAdmin() != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
# 009 AXP LOS23 port — patch / packaging README
|
||||
|
||||
**Track**: Magisk AXP resurrection on LOS 23.2 sunfish (`AXP_Resurection`).
|
||||
**Not ship**: KernelSU / SusFS (`007` standby / optional recycle only).
|
||||
|
||||
## Apply order (host tree under `/srv/rom/src/lineage/`)
|
||||
|
||||
1. **Google stack** — `vendor/sunfish-a16/gms.mk` + `Android.mk` (microG, GSF,
|
||||
Phonesky). Host APKs: `/srv/rom/prebuilts/{microg,phonesky}/` (never Git).
|
||||
2. **Signature spoofing** — `vendor/sunfish-a16/patches/005-sigspoof/`
|
||||
(`apply_005_sigspoof.py`). Attribute: LOS restricted spoofing + AXP/005.
|
||||
3. **Call recording unlock** — `vendor/sunfish-a16/patches/008-call-rec-flag-secure/`
|
||||
(`extendrom_call_recording`). Attribute: EXTENDROM `F_CALLREC`.
|
||||
4. **Magisk preroot** — EXTENDROM-class boot/`init_boot` patch using Magisk APK
|
||||
from `/srv/rom/prebuilts/magisk/` (see `docs/009-magisk-preinstall-runbook.md`).
|
||||
Stub: `vendor/sunfish-a16/magisk.mk`. Attribute: Magisk upstream + sfX
|
||||
extendrom Magisk patcher. **Host tree currently has no `vendor/extendrom`**
|
||||
— must vendor minimal patcher or checkout extendrom before first Magisk bacon.
|
||||
5. **Bundled apps** — `/srv/rom/prebuilts/axp-apps/` + `apps.mk` (Aurora,
|
||||
Droidify, Fossify Gallery). Symlink APKs into `vendor/sunfish-a16/prebuilt/`.
|
||||
6. **Private DNS presets** — `apply_009_private_dns_providers.py` (GOLDEN list).
|
||||
7. **Internet connectivity check** — `apply_009_connectivity_check.py` (GOLDEN
|
||||
list **minus** AXP.OS / `axpos.org`).
|
||||
8. **Disable for user apps** — `apply_009_disable_user_apps.py` (SPA gate).
|
||||
9. **Userspace hardening / signing** — staged: see `signing/README.md`,
|
||||
`hardening/README.md` (US-S4-1 OpenSSH trim), and
|
||||
`docs/009-hardening-signing-checklist.md` (US-S1 keys → US-S2 wire →
|
||||
US-S3 AVB → US-S4+ harden). Bootloader lock = wont.
|
||||
10. **Kernel hardening** — LOS23 `msm-4.14` + map in
|
||||
`docs/009-kernel-hardening-map.md` (FR-017). Stage 1:
|
||||
`vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1.sh`
|
||||
(AXP Graphene/AH allowlist). Priority: AXP → LOS → Iodé → optional
|
||||
Graphene; no Divest hunt; no extra location lockdown.
|
||||
|
||||
## Product includes
|
||||
|
||||
Wire Magisk-resurrection product from `vendor/sunfish-a16/` into
|
||||
`lineage_sunfish` (same pattern as `004`/`005`). Keep Phonesky priv-app path.
|
||||
**No FakeStore. No KernelSU product packages.**
|
||||
|
||||
## Deferred
|
||||
|
||||
- Banking Gate E / Island validation (owner future).
|
||||
- Localization AXP-vs-LOS compare (`docs/009-localization-axp-vs-los.md` stub).
|
||||
|
||||
## Host paths (rom-dev01)
|
||||
|
||||
| What | Path |
|
||||
|------|------|
|
||||
| Magisk APK | `/srv/rom/prebuilts/magisk/Magisk-v30.7.apk` |
|
||||
| EXTENDROM Magisk patcher | `/srv/rom/references/extendrom/config/magisk/` |
|
||||
| Kernel source | `/srv/rom/src/lineage/kernel/google/msm-4.14` |
|
||||
| Product include (gms) | `device/google/sunfish/lineage_sunfish.mk` → `vendor/sunfish-a16/gms.mk` |
|
||||
| Vanilla baseline | `/srv/rom/artifacts/003-vanilla/20260914-lineage-23.2-sunfish/` |
|
||||
| Optional KSU boots | `/srv/rom/artifacts/007-kernelsu/` (non-ship) |
|
||||
|
||||
**Gap:** `vendor/extendrom` is **not** checked out in the lineage tree yet.
|
||||
Magisk bacon blocked on T011 (symlink/checkout + PREROOT or slim wire).
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: port GOLDEN Internet connectivity check UI (sans axp.os).
|
||||
|
||||
Copies ConnectivityCheckPreferenceController, adds string/array resources,
|
||||
wires into NetworkDashboardFragment. Idempotent.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
MARKER = "sunfish-a16-009-connectivity-check"
|
||||
|
||||
ENTRIES = """ <!-- {m}: GOLDEN connectivity providers minus AXP.OS -->
|
||||
<string-array name="connectivity_check_entries" translatable="false">
|
||||
<item>Disabled</item>
|
||||
<item>Amazon Fire OS (US)</item>
|
||||
<item>Cloudflare (US)</item>
|
||||
<item>Google (US) [default]</item>
|
||||
<item>Huawei (CN)</item>
|
||||
<item>Kuketz (DE)</item>
|
||||
<item>Microsoft Edge (US)</item>
|
||||
<item>openSUSE (DE)</item>
|
||||
<item>Ubuntu (UK)</item>
|
||||
</string-array>
|
||||
<string-array name="connectivity_check_values" translatable="false">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
</string-array>
|
||||
""".format(
|
||||
m=MARKER
|
||||
)
|
||||
|
||||
STRINGS = f""" <!-- {MARKER} -->
|
||||
<string name="connectivity_check_title" translatable="false">Internet connectivity check</string>
|
||||
<string name="connectivity_check_summary" translatable="false">HTTP endpoints to use for performing internet connectivity checks.</string>
|
||||
"""
|
||||
|
||||
|
||||
def ensure_arrays(path: pathlib.Path) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if "connectivity_check_entries" in text:
|
||||
return
|
||||
if "</resources>" not in text:
|
||||
raise SystemExit(f"FAIL: no </resources> in {path}")
|
||||
path.write_text(text.replace("</resources>", ENTRIES + "</resources>", 1), encoding="utf-8")
|
||||
|
||||
|
||||
def ensure_strings(path: pathlib.Path) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if "connectivity_check_title" in text:
|
||||
return
|
||||
path.write_text(text.replace("</resources>", STRINGS + "</resources>", 1), encoding="utf-8")
|
||||
|
||||
|
||||
def wire_fragment(path: pathlib.Path) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if "ConnectivityCheckPreferenceController" in text:
|
||||
return
|
||||
if "controllers.add(privateDnsPreferenceController);" not in text:
|
||||
raise SystemExit("FAIL: expected PrivateDns add site missing")
|
||||
text = text.replace(
|
||||
"controllers.add(privateDnsPreferenceController);",
|
||||
"controllers.add(privateDnsPreferenceController);\n"
|
||||
f" // {MARKER}\n"
|
||||
" controllers.add(new ConnectivityCheckPreferenceController(context));",
|
||||
1,
|
||||
)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
root = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
||||
here = pathlib.Path(__file__).resolve().parent
|
||||
src = here / "ConnectivityCheckPreferenceController.java"
|
||||
dst = root / (
|
||||
"packages/apps/Settings/src/com/android/settings/network/"
|
||||
"ConnectivityCheckPreferenceController.java"
|
||||
)
|
||||
arrays = root / "packages/apps/Settings/res/values/arrays.xml"
|
||||
# Prefer cm_strings for non-translated titles; fall back to strings.xml end
|
||||
cm = root / "packages/apps/Settings/res/values/cm_strings.xml"
|
||||
frag = root / (
|
||||
"packages/apps/Settings/src/com/android/settings/network/NetworkDashboardFragment.java"
|
||||
)
|
||||
for p in (src, arrays, cm, frag):
|
||||
if not p.is_file():
|
||||
print(f"FAIL: missing {p}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if dst.is_file() and MARKER.split("-")[0] and "sans axp" in dst.read_text(encoding="utf-8"):
|
||||
# already copied
|
||||
pass
|
||||
else:
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
ensure_arrays(arrays)
|
||||
ensure_strings(cm)
|
||||
wire_fragment(frag)
|
||||
print(f"OK: connectivity check wired -> {dst}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: allow classic Disable for non-system apps (A16 Archive era).
|
||||
|
||||
LOS AppDisableButton returns null for !isSystemApp. Graphene/AXP-class UX
|
||||
keeps Disable usable for user apps. Attribute: AXP/owner preference over Archive.
|
||||
Idempotent.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
MARKER = "sunfish-a16-009-disable-user-apps"
|
||||
|
||||
CANDIDATES = [
|
||||
pathlib.Path("packages/apps/Settings/src/com/android/settings/spa/app/appinfo/AppDisableButton.kt"),
|
||||
]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
root = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
||||
path = None
|
||||
for rel in CANDIDATES:
|
||||
p = root / rel
|
||||
if p.is_file():
|
||||
path = p
|
||||
break
|
||||
if path is None:
|
||||
print("FAIL: AppDisableButton.kt not found", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if MARKER in text:
|
||||
print(f"OK: already applied ({path})")
|
||||
return 0
|
||||
|
||||
old = " if (!app.isSystemApp) return null\n"
|
||||
if old not in text:
|
||||
print("FAIL: expected isSystemApp gate not found", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
new = (
|
||||
f" // {MARKER}: allow Disable for user apps (not only system)\n"
|
||||
f" // if (!app.isSystemApp) return null\n"
|
||||
)
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
print(f"OK: patched {path}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
"""US-S4-2 — drop Lineage Jelly + Gallery2 to match AXP.OS PRO product surface.
|
||||
|
||||
Oracle: AXP.OS-22.2-20260324-PRO-sunfish.zip product/app has neither Jelly nor
|
||||
Gallery2 (browser stub + FossifyGallery_FD live on system_ext). See
|
||||
docs/009-axp-pro-product-apps-20260324.md.
|
||||
|
||||
FossifyGallery already declares LOCAL_OVERRIDES_PACKAGES := Gallery Gallery2
|
||||
Glimpse, but Gallery2 still landed in product/app on the 162840Z ship — same
|
||||
class of failure as OpenSSH filter-out. Patch the Lineage PRODUCT_PACKAGES
|
||||
add sites and add belt-and-suspenders stubs.
|
||||
|
||||
Usage (from ANDROID_BUILD_TOP):
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_jelly_gallery2.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MARKER = "sunfish-a16-009-uss4-2-jelly-gallery2"
|
||||
|
||||
# Common Lineage shapes (tolerant).
|
||||
JELLY_BLOCK = re.compile(
|
||||
r"# Browser\n"
|
||||
r"PRODUCT_PACKAGES \+= \\\n"
|
||||
r" Jelly\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
# ExactCalculator + Jelly list (common Lineage shape) → keep ExactCalculator only.
|
||||
JELLY_WITH_CALC = re.compile(
|
||||
r"(PRODUCT_PACKAGES \+= \\\n"
|
||||
r" ExactCalculator) \\\n"
|
||||
r" Jelly\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
GALLERY2_IN_LIST = re.compile(
|
||||
r"( DeskClock \\\n)"
|
||||
r" Gallery2 \\\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
def patch_text(text: str, path: Path) -> tuple[str, list[str]]:
|
||||
notes: list[str] = []
|
||||
bad = f"# Jelly stripped ({MARKER})" in text or f"# Gallery2 stripped ({MARKER})" in text
|
||||
has_pkg = bool(re.search(r"(?m)^[ \t]*Jelly( \\)?$", text)) or bool(
|
||||
re.search(r"(?m)^[ \t]*Gallery2( \\)?$", text)
|
||||
)
|
||||
if MARKER in text and not bad and not has_pkg:
|
||||
notes.append("already")
|
||||
return text, notes
|
||||
|
||||
orig = text
|
||||
|
||||
text, n = JELLY_BLOCK.subn(
|
||||
f"# Browser (Jelly) omitted ({MARKER}) — AXP PRO uses noDefaultBrowserWebView\n",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
if n:
|
||||
notes.append(f"jelly_block={n}")
|
||||
|
||||
text, n = JELLY_WITH_CALC.subn(
|
||||
rf"\1\n",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
if n:
|
||||
notes.append(f"jelly_calc={n}")
|
||||
|
||||
text, n = GALLERY2_IN_LIST.subn(
|
||||
rf"\1",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
if n:
|
||||
notes.append(f"gallery2_list={n}")
|
||||
|
||||
# Remove leftover broken comment-only continuations from older applicator.
|
||||
text2 = re.sub(
|
||||
r"^[ \t]*# (?:Jelly|Gallery2) stripped \(" + re.escape(MARKER) + r"\)\n",
|
||||
"",
|
||||
text,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
if text2 != text:
|
||||
notes.append("scrub_bad_comments")
|
||||
text = text2
|
||||
|
||||
if text == orig and not notes:
|
||||
return orig, notes
|
||||
if MARKER not in text and text != orig:
|
||||
text = f"# {MARKER}\n" + text
|
||||
return text, notes
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
candidates = [
|
||||
top / "vendor/lineage/config/common.mk",
|
||||
top / "vendor/lineage/config/common_mobile.mk",
|
||||
top / "vendor/lineage/config/common_full.mk",
|
||||
top / "vendor/lineage/config/telephony.mk",
|
||||
top / "build/make/target/product/handheld_product.mk",
|
||||
top / "build/make/target/product/handheld_system.mk",
|
||||
top / "build/make/target/product/generic_system.mk",
|
||||
]
|
||||
# Also scan device trees that often force Gallery2
|
||||
for p in (top / "device").rglob("*.mk") if (top / "device").is_dir() else []:
|
||||
if p.name in ("device.mk", "lineage.mk", "lineage_sunfish.mk", "aosp_sunfish.mk"):
|
||||
candidates.append(p)
|
||||
|
||||
touched = 0
|
||||
still_present = []
|
||||
for mk in candidates:
|
||||
if not mk.is_file():
|
||||
continue
|
||||
text = mk.read_text(encoding="utf-8", errors="replace")
|
||||
if "Jelly" not in text and "Gallery2" not in text:
|
||||
continue
|
||||
# Ignore mention-only in comments/docs after a clean strip.
|
||||
has_pkg = bool(re.search(r"(?m)^[ \t]*Jelly( \\)?$", text)) or bool(
|
||||
re.search(r"(?m)^[ \t]*Gallery2( \\)?$", text)
|
||||
)
|
||||
bad = f"# Jelly stripped ({MARKER})" in text or f"# Gallery2 stripped ({MARKER})" in text
|
||||
if not has_pkg and not bad:
|
||||
continue
|
||||
new, notes = patch_text(text, mk)
|
||||
if notes == ["already"]:
|
||||
print(f"OK: already applied ({mk})")
|
||||
touched += 1
|
||||
continue
|
||||
if new == text:
|
||||
print(f"WARN: {mk} mentions Jelly/Gallery2 but no pattern matched: {notes}")
|
||||
still_present.append(str(mk))
|
||||
continue
|
||||
mk.write_text(new, encoding="utf-8")
|
||||
print(f"OK: patched {mk} ({', '.join(notes)})")
|
||||
touched += 1
|
||||
|
||||
if still_present:
|
||||
print(
|
||||
"FAIL: Jelly/Gallery2 still present, patterns missed: "
|
||||
+ ", ".join(still_present),
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
if touched == 0:
|
||||
print("OK: Jelly/Gallery2 already absent from PRODUCT_PACKAGES sites")
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""US-S4-1 — strip OpenSSH/rsync/procmem packages from Lineage common.mk.
|
||||
|
||||
AXP.OS PRO sunfish (A15) product/system lack sshd/ssh/rsync/procmem binaries but
|
||||
still ship init.openssh.rc. PRODUCT_PACKAGES filter-out via inherit-product did
|
||||
*not* remove them from the 20261002T125259Z ship image — patch the source block
|
||||
instead (same place Lineage adds them).
|
||||
|
||||
Keeps PRODUCT_COPY_FILES for init.openssh.rc (AXP surface).
|
||||
|
||||
Usage:
|
||||
python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_drop_openssh_packages.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MARKER = "sunfish-a16-009-uss4-openssh"
|
||||
|
||||
OPENSSH_PACKAGES = re.compile(
|
||||
r"# Openssh\n"
|
||||
r"PRODUCT_PACKAGES \+= \\\n"
|
||||
r"(?: \S+ \\\n)*"
|
||||
r" start-ssh\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
RSYNC_PACKAGES = re.compile(
|
||||
r"# rsync\n"
|
||||
r"PRODUCT_PACKAGES \+= \\\n"
|
||||
r" rsync\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
PROCMEM_DEBUG = re.compile(
|
||||
r"# These packages are excluded from user builds\n"
|
||||
r"PRODUCT_PACKAGES_DEBUG \+= \\\n"
|
||||
r" procmem\n"
|
||||
r"\n"
|
||||
r"ifneq \(\$\(TARGET_BUILD_VARIANT\),user\)\n"
|
||||
r"PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST \+= \\\n"
|
||||
r" system/bin/procmem\n"
|
||||
r"endif\n",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
mk = top / "vendor/lineage/config/common.mk"
|
||||
if not mk.is_file():
|
||||
print(f"FAIL: missing {mk}", file=sys.stderr)
|
||||
return 1
|
||||
text = mk.read_text()
|
||||
if MARKER in text:
|
||||
print(f"OK: already applied ({mk})")
|
||||
return 0
|
||||
|
||||
orig = text
|
||||
text, n1 = OPENSSH_PACKAGES.subn(
|
||||
f"# Openssh packages stripped ({MARKER}) — keep init.openssh.rc below\n",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
text, n2 = RSYNC_PACKAGES.subn(
|
||||
f"# rsync stripped ({MARKER})\n",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
text, n3 = PROCMEM_DEBUG.subn(
|
||||
f"# procmem debug package stripped ({MARKER})\n",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
if n1 != 1 or n2 != 1:
|
||||
print(
|
||||
f"FAIL: Openssh/rsync block match n1={n1} n2={n2} n3={n3}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
# procmem block optional if layout drifted
|
||||
if n3 == 0:
|
||||
print("WARN: procmem debug block not matched (layout drift)")
|
||||
|
||||
if "init.openssh.rc" not in text:
|
||||
print("FAIL: init.openssh.rc COPY_FILES missing after patch", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
mk.write_text(text)
|
||||
print(f"OK: patched {mk} (openssh_pkgs={n1} rsync={n2} procmem={n3})")
|
||||
return 0 if text != orig else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+498
@@ -0,0 +1,498 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: expand Private DNS presets to AXP GOLDEN list (no axp.os).
|
||||
|
||||
Clones GOLDEN Settings radios/hostnames into LOS PrivateDnsModeDialogPreference
|
||||
(which already has a Cloudflare stub). Idempotent via marker comments.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
MARKER = "sunfish-a16-009-private-dns"
|
||||
|
||||
# key, UI label, DoT hostname — GOLDEN order (cloudflare hostname = security.*)
|
||||
PROVIDERS = [
|
||||
("adguard", "AdGuard (CT)", "dns.adguard.com"),
|
||||
("appliedprivacy", "AppliedPrivacy (AT)", "dot1.applied-privacy.net"),
|
||||
("cira", "CIRA (CA)", "protected.canadianshield.cira.ca"),
|
||||
("controld", "Control D (CA)", "p2.freedns.controld.com"),
|
||||
("cleanbrowsing", "CleanBrowsing (US)", "security-filter-dns.cleanbrowsing.org"),
|
||||
("cznic", "CZ.NIC (CZ)", "odvr.nic.cz"),
|
||||
("cloudflare", "Cloudflare (US)", "security.cloudflare-dns.com"),
|
||||
("dnszero", "DNS0 (FR)", "zero.dns0.eu"),
|
||||
("dnssb", "DNS.SB (DE)", "dot.sb"),
|
||||
("google", "Google (US)", "dns.google"),
|
||||
("mullvad", "Mullvad (SE)", "base.dns.mullvad.net"),
|
||||
("quadnine", "Quad9 (CH)", "dns.quad9.net"),
|
||||
("restena", "Restena (LU)", "kaitain.restena.lu"),
|
||||
("switch", "SWITCH (CH)", "dns.switch.ch"),
|
||||
("uncensoreddns", "UncensoredDNS (DK)", "anycast.censurfridns.dk"),
|
||||
]
|
||||
|
||||
|
||||
def patch_layout(path: pathlib.Path) -> bool:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if MARKER in text:
|
||||
return False
|
||||
# Insert provider radios after off, before opportunistic (keep provider+hostname)
|
||||
includes = []
|
||||
for key, _, _ in PROVIDERS:
|
||||
includes.append(
|
||||
f' <!-- {MARKER} -->\n'
|
||||
f' <include\n'
|
||||
f' android:id="@+id/private_dns_mode_{key}"\n'
|
||||
f' layout="@layout/preference_widget_dialog_radiobutton"/>\n'
|
||||
)
|
||||
block = "".join(includes)
|
||||
# Remove ALL existing cloudflare includes (re-added once via PROVIDERS)
|
||||
text2 = re.sub(
|
||||
r'\s*(?:<!--.*?-->\s*)?<include\s*\n\s*android:id="@\+id/private_dns_mode_cloudflare"\s*\n\s*layout="@layout/preference_widget_dialog_radiobutton"/>\s*',
|
||||
"\n",
|
||||
text,
|
||||
flags=re.DOTALL,
|
||||
)
|
||||
text2 = re.sub(
|
||||
r'\s*<include\s+android:id="@\+id/private_dns_mode_cloudflare"[^/]*/>\s*',
|
||||
"\n",
|
||||
text2,
|
||||
)
|
||||
needle = (
|
||||
' <include\n'
|
||||
' android:id="@+id/private_dns_mode_opportunistic"\n'
|
||||
' layout="@layout/preference_widget_dialog_radiobutton"/>'
|
||||
)
|
||||
if needle not in text2:
|
||||
# alternate formatting
|
||||
needle = 'android:id="@+id/private_dns_mode_opportunistic"'
|
||||
idx = text2.find(needle)
|
||||
if idx < 0:
|
||||
raise SystemExit(f"FAIL: opportunistic radio not in {path}")
|
||||
# find start of include element
|
||||
start = text2.rfind("<include", 0, idx)
|
||||
text2 = text2[:start] + block + text2[start:]
|
||||
else:
|
||||
text2 = text2.replace(needle, block + needle, 1)
|
||||
path.write_text(text2, encoding="utf-8")
|
||||
return True
|
||||
|
||||
|
||||
def patch_cm_strings(path: pathlib.Path) -> bool:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if MARKER in text and "private_dns_hostname_quadnine" in text:
|
||||
return False
|
||||
# Replace/extend cloudflare hostname to GOLDEN security.cloudflare-dns.com
|
||||
text = re.sub(
|
||||
r'<string name="private_dns_hostname_cloudflare"[^>]*>.*?</string>',
|
||||
'<string name="private_dns_hostname_cloudflare" translatable="false">'
|
||||
"security.cloudflare-dns.com</string>",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
text = re.sub(
|
||||
r'<string name="private_dns_mode_cloudflare"[^>]*>.*?</string>',
|
||||
'<string name="private_dns_mode_cloudflare" translatable="false">'
|
||||
"Cloudflare (US)</string>",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
lines = [f" <!-- {MARKER}: AXP GOLDEN Private DNS presets -->"]
|
||||
for key, label, host in PROVIDERS:
|
||||
if key == "cloudflare":
|
||||
continue # already present
|
||||
lines.append(
|
||||
f' <string name="private_dns_mode_{key}" translatable="false">{label}</string>'
|
||||
)
|
||||
lines.append(
|
||||
f' <string name="private_dns_hostname_{key}" translatable="false">{host}</string>'
|
||||
)
|
||||
insert = "\n".join(lines) + "\n"
|
||||
if "</resources>" not in text:
|
||||
raise SystemExit(f"FAIL: no </resources> in {path}")
|
||||
text = text.replace("</resources>", insert + "</resources>", 1)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
return True
|
||||
|
||||
|
||||
def write_preference_java(path: pathlib.Path) -> None:
|
||||
"""Rewrite PrivateDnsModeDialogPreference with data-driven GOLDEN presets."""
|
||||
# Keep copyright / package; replace body after class declaration via full file.
|
||||
providers_java = ",\n".join(
|
||||
f' new Provider("{key}", R.id.private_dns_mode_{key}, '
|
||||
f"R.string.private_dns_mode_{key}, R.string.private_dns_hostname_{key})"
|
||||
for key, _, _ in PROVIDERS
|
||||
)
|
||||
# Assign custom mode ints starting at 4 (LOS cloudflare used 4)
|
||||
mode_consts = "\n".join(
|
||||
f" private static final int PRIVATE_DNS_MODE_{key.upper()} = {4 + i};"
|
||||
for i, (key, _, _) in enumerate(PROVIDERS)
|
||||
)
|
||||
map_puts = "\n".join(
|
||||
f" PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_{key.upper()}, "
|
||||
f"R.id.private_dns_mode_{key});"
|
||||
for key, _, _ in PROVIDERS
|
||||
)
|
||||
content = f'''/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.network;
|
||||
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||
|
||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivitySettingsManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
import com.android.settingslib.CustomDialogPreferenceCompat;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Dialog to set the Private DNS.
|
||||
* {MARKER}: AXP GOLDEN provider presets (hostnames from GOLDEN Settings.apk).
|
||||
*/
|
||||
public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat implements
|
||||
RadioGroup.OnCheckedChangeListener, TextWatcher {{
|
||||
|
||||
public static final String ANNOTATION_URL = "url";
|
||||
|
||||
private static final String TAG = "PrivateDnsModeDialog";
|
||||
private static final Map<Integer, Integer> PRIVATE_DNS_MAP;
|
||||
|
||||
{mode_consts}
|
||||
|
||||
private static final Provider[] PROVIDERS = new Provider[] {{
|
||||
{providers_java}
|
||||
}};
|
||||
|
||||
static {{
|
||||
PRIVATE_DNS_MAP = new HashMap<>();
|
||||
PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_OFF, R.id.private_dns_mode_off);
|
||||
PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_OPPORTUNISTIC, R.id.private_dns_mode_opportunistic);
|
||||
PRIVATE_DNS_MAP.put(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, R.id.private_dns_mode_provider);
|
||||
{map_puts}
|
||||
}}
|
||||
|
||||
private static final class Provider {{
|
||||
final String key;
|
||||
final int radioId;
|
||||
final int labelRes;
|
||||
final int hostnameRes;
|
||||
|
||||
Provider(String key, int radioId, int labelRes, int hostnameRes) {{
|
||||
this.key = key;
|
||||
this.radioId = radioId;
|
||||
this.labelRes = labelRes;
|
||||
this.hostnameRes = hostnameRes;
|
||||
}}
|
||||
}}
|
||||
|
||||
@VisibleForTesting
|
||||
TextInputLayout mHostnameLayout;
|
||||
@VisibleForTesting
|
||||
EditText mHostnameText;
|
||||
@VisibleForTesting
|
||||
RadioGroup mRadioGroup;
|
||||
@VisibleForTesting
|
||||
int mMode;
|
||||
|
||||
public PrivateDnsModeDialogPreference(Context context) {{
|
||||
super(context);
|
||||
}}
|
||||
|
||||
public PrivateDnsModeDialogPreference(Context context, AttributeSet attrs) {{
|
||||
super(context, attrs);
|
||||
}}
|
||||
|
||||
public PrivateDnsModeDialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {{
|
||||
super(context, attrs, defStyleAttr);
|
||||
}}
|
||||
|
||||
public PrivateDnsModeDialogPreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {{
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}}
|
||||
|
||||
private final AnnotationSpan.LinkInfo mUrlLinkInfo = new AnnotationSpan.LinkInfo(
|
||||
ANNOTATION_URL, (widget) -> {{
|
||||
final Context context = widget.getContext();
|
||||
final Intent intent = HelpUtils.getHelpIntent(context,
|
||||
context.getString(R.string.help_uri_private_dns),
|
||||
context.getClass().getName());
|
||||
if (intent != null) {{
|
||||
try {{
|
||||
widget.startActivityForResult(intent, 0);
|
||||
}} catch (ActivityNotFoundException e) {{
|
||||
Log.w(TAG, "Activity was not found for intent, " + intent.toString());
|
||||
}}
|
||||
}}
|
||||
}});
|
||||
|
||||
private static int modeForRadioId(int radioId) {{
|
||||
if (radioId == R.id.private_dns_mode_off) return PRIVATE_DNS_MODE_OFF;
|
||||
if (radioId == R.id.private_dns_mode_opportunistic) return PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||
if (radioId == R.id.private_dns_mode_provider) return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||
for (int i = 0; i < PROVIDERS.length; i++) {{
|
||||
if (PROVIDERS[i].radioId == radioId) {{
|
||||
return 4 + i;
|
||||
}}
|
||||
}}
|
||||
return PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||
}}
|
||||
|
||||
private static Provider providerForMode(int mode) {{
|
||||
int idx = mode - 4;
|
||||
if (idx >= 0 && idx < PROVIDERS.length) {{
|
||||
return PROVIDERS[idx];
|
||||
}}
|
||||
return null;
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {{
|
||||
super.onBindViewHolder(holder);
|
||||
if (isDisabledByAdmin()) {{
|
||||
holder.itemView.setEnabled(true);
|
||||
}}
|
||||
setSaveButtonListener();
|
||||
}}
|
||||
|
||||
@Override
|
||||
protected void onBindDialogView(View view) {{
|
||||
final Context context = getContext();
|
||||
mMode = ConnectivitySettingsManager.getPrivateDnsMode(context);
|
||||
if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {{
|
||||
final String host = ConnectivitySettingsManager.getPrivateDnsHostname(context);
|
||||
for (int i = 0; i < PROVIDERS.length; i++) {{
|
||||
if (host != null && host.equals(context.getString(PROVIDERS[i].hostnameRes))) {{
|
||||
mMode = 4 + i;
|
||||
break;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
mRadioGroup = view.findViewById(R.id.private_dns_radio_group);
|
||||
mRadioGroup.check(PRIVATE_DNS_MAP.getOrDefault(mMode, R.id.private_dns_mode_opportunistic));
|
||||
mRadioGroup.setOnCheckedChangeListener(this);
|
||||
|
||||
final RadioButton offRadioButton = view.findViewById(R.id.private_dns_mode_off);
|
||||
offRadioButton.setText(com.android.settingslib.R.string.private_dns_mode_off);
|
||||
for (Provider p : PROVIDERS) {{
|
||||
final RadioButton rb = view.findViewById(p.radioId);
|
||||
if (rb != null) {{
|
||||
rb.setText(p.labelRes);
|
||||
}}
|
||||
}}
|
||||
final RadioButton opportunisticRadioButton =
|
||||
view.findViewById(R.id.private_dns_mode_opportunistic);
|
||||
opportunisticRadioButton.setText(
|
||||
com.android.settingslib.R.string.private_dns_mode_opportunistic);
|
||||
final RadioButton providerRadioButton = view.findViewById(R.id.private_dns_mode_provider);
|
||||
providerRadioButton.setText(com.android.settingslib.R.string.private_dns_mode_provider);
|
||||
|
||||
mHostnameLayout = view.findViewById(R.id.private_dns_mode_provider_hostname_layout);
|
||||
mHostnameText = view.findViewById(R.id.private_dns_mode_provider_hostname);
|
||||
if (mHostnameText != null) {{
|
||||
mHostnameText.setText(ConnectivitySettingsManager.getPrivateDnsHostname(context));
|
||||
mHostnameText.addTextChangedListener(this);
|
||||
}}
|
||||
|
||||
final TextView helpTextView = view.findViewById(R.id.private_dns_help_info);
|
||||
helpTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
final Intent helpIntent = HelpUtils.getHelpIntent(context,
|
||||
context.getString(R.string.help_uri_private_dns),
|
||||
context.getClass().getName());
|
||||
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(context,
|
||||
ANNOTATION_URL, helpIntent);
|
||||
if (linkInfo.isActionable()) {{
|
||||
helpTextView.setText(AnnotationSpan.linkify(
|
||||
context.getText(R.string.private_dns_help_message), linkInfo));
|
||||
}} else {{
|
||||
helpTextView.setText("");
|
||||
}}
|
||||
|
||||
updateDialogInfo();
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(RadioGroup group, int checkedId) {{
|
||||
mMode = modeForRadioId(checkedId);
|
||||
updateDialogInfo();
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {{
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {{
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {{
|
||||
updateDialogInfo();
|
||||
}}
|
||||
|
||||
@Override
|
||||
public void performClick() {{
|
||||
EnforcedAdmin enforcedAdmin = getEnforcedAdmin();
|
||||
if (enforcedAdmin == null) {{
|
||||
super.performClick();
|
||||
}} else {{
|
||||
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), enforcedAdmin);
|
||||
}}
|
||||
}}
|
||||
|
||||
private EnforcedAdmin getEnforcedAdmin() {{
|
||||
return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
|
||||
getContext(), UserManager.DISALLOW_CONFIG_PRIVATE_DNS, UserHandle.myUserId());
|
||||
}}
|
||||
|
||||
private boolean isDisabledByAdmin() {{
|
||||
return getEnforcedAdmin() != null;
|
||||
}}
|
||||
|
||||
private void updateDialogInfo() {{
|
||||
final boolean modeProvider = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mMode;
|
||||
if (mHostnameLayout != null) {{
|
||||
mHostnameLayout.setEnabled(modeProvider);
|
||||
mHostnameLayout.setErrorEnabled(false);
|
||||
}}
|
||||
}}
|
||||
|
||||
private void setSaveButtonListener() {{
|
||||
View.OnClickListener onClickListener = v -> doSaveButton();
|
||||
DialogInterface.OnShowListener onShowListener = dialog -> {{
|
||||
if (dialog == null) {{
|
||||
Log.e(TAG, "The DialogInterface is null!");
|
||||
return;
|
||||
}}
|
||||
Button saveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
if (saveButton == null) {{
|
||||
Log.e(TAG, "Can't get the save button!");
|
||||
return;
|
||||
}}
|
||||
saveButton.setOnClickListener(onClickListener);
|
||||
}};
|
||||
setOnShowListener(onShowListener);
|
||||
}}
|
||||
|
||||
@VisibleForTesting
|
||||
void doSaveButton() {{
|
||||
Context context = getContext();
|
||||
int modeToSet = mMode;
|
||||
Provider preset = providerForMode(mMode);
|
||||
if (preset != null) {{
|
||||
ConnectivitySettingsManager.setPrivateDnsHostname(context,
|
||||
context.getString(preset.hostnameRes));
|
||||
modeToSet = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||
}} else if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {{
|
||||
if (mHostnameLayout == null || mHostnameText == null) {{
|
||||
Log.e(TAG, "Can't find hostname resources!");
|
||||
return;
|
||||
}}
|
||||
if (mHostnameText.getText().isEmpty()) {{
|
||||
mHostnameLayout.setError(context.getString(R.string.private_dns_field_require));
|
||||
Log.w(TAG, "The hostname is empty!");
|
||||
return;
|
||||
}}
|
||||
if (!InternetDomainName.isValid(mHostnameText.getText().toString())) {{
|
||||
mHostnameLayout.setError(context.getString(R.string.private_dns_hostname_invalid));
|
||||
Log.w(TAG, "The hostname is invalid!");
|
||||
return;
|
||||
}}
|
||||
ConnectivitySettingsManager.setPrivateDnsHostname(context,
|
||||
mHostnameText.getText().toString());
|
||||
}}
|
||||
|
||||
ConnectivitySettingsManager.setPrivateDnsMode(context, modeToSet);
|
||||
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
|
||||
.action(context, SettingsEnums.ACTION_PRIVATE_DNS_MODE, modeToSet);
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog != null) {{
|
||||
dialog.dismiss();
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
# Fix f-string doubled braces - we used {{ for literal braces in the template
|
||||
# But MARKER was intended as comment - replace
|
||||
content = content.replace("{MARKER}", MARKER)
|
||||
path.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
root = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
||||
layout = root / "packages/apps/Settings/res/layout/private_dns_mode_dialog.xml"
|
||||
cm = root / "packages/apps/Settings/res/values/cm_strings.xml"
|
||||
java = root / (
|
||||
"packages/apps/Settings/src/com/android/settings/network/"
|
||||
"PrivateDnsModeDialogPreference.java"
|
||||
)
|
||||
for p in (layout, cm, java):
|
||||
if not p.is_file():
|
||||
print(f"FAIL: missing {p}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if MARKER in java.read_text(encoding="utf-8") and "quadnine" in layout.read_text(
|
||||
encoding="utf-8"
|
||||
):
|
||||
print("OK: private DNS already applied")
|
||||
return 0
|
||||
|
||||
patch_layout(layout)
|
||||
patch_cm_strings(cm)
|
||||
write_preference_java(java)
|
||||
print(f"OK: private DNS providers applied ({len(PROVIDERS)} presets)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Apply early TARGET_UNOFFICIAL_BUILD_ID to device product makefile.
|
||||
# Must run before breakfast: inherit-product of vendor/lineage parses version.mk
|
||||
# immediately; vendor/extra inherit-product is too late.
|
||||
#
|
||||
# Usage (on rom-dev01 tree):
|
||||
# python3 vendor/sunfish-a16/patches/009-axp-los23-port/apply_009_unofficial_build_id.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
|
||||
MARKER = "TARGET_UNOFFICIAL_BUILD_ID := AXP-Resurection-Pro"
|
||||
NEEDLE = "# Inherit some common Lineage stuff.\n"
|
||||
INSERT = (
|
||||
"# sunfish-a16: must precede vendor/lineage version.mk (via inherit below)\n"
|
||||
f"{MARKER}\n\n"
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
mk = top / "device/google/sunfish/lineage_sunfish.mk"
|
||||
if not mk.is_file():
|
||||
print(f"FAIL: missing {mk}", file=sys.stderr)
|
||||
return 1
|
||||
text = mk.read_text()
|
||||
if MARKER in text:
|
||||
print(f"OK: already applied ({mk})")
|
||||
return 0
|
||||
if NEEDLE not in text:
|
||||
print(f"FAIL: needle not found in {mk}", file=sys.stderr)
|
||||
return 1
|
||||
mk.write_text(text.replace(NEEDLE, INSERT + NEEDLE, 1))
|
||||
print(f"OK: patched {mk}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,67 @@
|
||||
# US-S4-1 — drop Lineage product OpenSSH binaries / rsync / procmem
|
||||
|
||||
**Track**: AXP Resurection Pro (Magisk), unlocked sunfish.
|
||||
**Not**: slim variant; not bootloader lock; not Yama (kernel).
|
||||
|
||||
## AXP reference (mandatory)
|
||||
|
||||
Oracle: `AXP.OS-22.2-20260324-PRO-sunfish.zip` → `payload.bin` → `product.img`
|
||||
(+ GOLDEN `ro.lineage.version=22.2-2026.003-sunfish-pro`, Android 15):
|
||||
|
||||
| Path | AXP PRO (A15) |
|
||||
|------|----------------|
|
||||
| `/bin/sshd`, `ssh`, `scp`, `sftp`, `ssh-keygen`, `start-ssh` | **absent** |
|
||||
| `/bin/rsync`, `/bin/procmem` | **absent** |
|
||||
| `/etc/init/init.openssh.rc` | **present** (`mkdir /data/ssh*`) |
|
||||
|
||||
### Was this an A16 Lineage add?
|
||||
|
||||
**No.** Lineage `vendor/lineage/config/common.mk` has shipped the Openssh
|
||||
block since 2012; lineage-20 / 21 / 22.2 all still include it. AXP PRO on
|
||||
A15 therefore **actively omitted** the binaries (same lineage generation
|
||||
still lists them upstream). Public `AXP.OS/android_vendor_lineage`
|
||||
`upstream_*` mirrors keep the Lineage Openssh block — use the **PRO zip /
|
||||
GOLDEN**, not that mirror, as product oracle.
|
||||
|
||||
## What we ship
|
||||
|
||||
Match AXP PRO product surface by stripping Lineage `common.mk` package
|
||||
adds (see `apply_009_drop_openssh_packages.py`) — a plain
|
||||
`PRODUCT_PACKAGES := $(filter-out …)` inherit did **not** drop `sshd` from
|
||||
ship `20261002T125259Z`:
|
||||
|
||||
- Remove packages: `scp`, `sftp`, `ssh`, `sshd`, `sshd_config`, `ssh-keygen`,
|
||||
`start-ssh`, `rsync`, `procmem` (debug)
|
||||
- **Keep** `init.openssh.rc` copy (AXP has it)
|
||||
|
||||
Remote shell / file transfer on this track remains **adb** (+ Magisk); the
|
||||
rc only creates `/data/ssh*` and does not start `sshd` without the binary.
|
||||
|
||||
## Verify (LAB after flash)
|
||||
|
||||
```text
|
||||
adb shell ls /product/bin/sshd # expect: No such file
|
||||
adb shell ls /product/bin/rsync # expect: No such file
|
||||
adb shell ls /product/etc/init/init.openssh.rc # expect: present (AXP)
|
||||
adb shell pidof magiskd # expect: non-empty
|
||||
```
|
||||
|
||||
## US-S4-2 — drop Jelly + Gallery2 (AXP PRO product)
|
||||
|
||||
**Oracle**: same PRO zip — `product/app` has **no** Jelly / Gallery2;
|
||||
`system_ext` ships Fossify + `noDefaultBrowserWebView`. Inventory:
|
||||
`docs/009-axp-pro-product-apps-20260324.md`.
|
||||
|
||||
- `apply_009_drop_jelly_gallery2.py` — remove Lineage `PRODUCT_PACKAGES`
|
||||
adds for Jelly / Gallery2
|
||||
- `NoLineageJelly` uninstallable override module (AXP stub class)
|
||||
- Keep `FossifyGallery` (already overrides Gallery/Gallery2/Glimpse)
|
||||
|
||||
LAB after flash: no `/product/app/Jelly`, no `/product/app/Gallery2`,
|
||||
FossifyGallery present.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- `CONFIG_SECURITY_YAMA` (kernel / US-S5 — **done** on `162840Z`)
|
||||
- Switching lunch to `user` (US-S6)
|
||||
- NeoLauncher / Aosmium (wont / exception)
|
||||
@@ -0,0 +1,89 @@
|
||||
# 009 signing / AVB (userspace Gate G)
|
||||
|
||||
Clone AXP/GOLDEN posture: **`user` + `release-keys`**, device **unlocked**
|
||||
(`orange`). Not IOdes locked-bootloader.
|
||||
|
||||
Full checklist: `docs/009-hardening-signing-checklist.md`.
|
||||
|
||||
## Stages
|
||||
|
||||
| Stage | What |
|
||||
|-------|------|
|
||||
| US-S1 | Generate keys → `/srv/rom/secrets/android-certs/` |
|
||||
| US-S2 | Wire `PRODUCT_DEFAULT_DEV_CERTIFICATE` into bacon |
|
||||
| US-S3 | Project AVB key (`AVB_CUSTOM_KEY_PATH`); decide `WITH_AVB` |
|
||||
| US-S4+ | Userspace harden / CVE — separate patches |
|
||||
|
||||
## Generate (rom-dev01 only)
|
||||
|
||||
```bash
|
||||
# from synced repo copy or laptop scp of scripts/
|
||||
sudo -u android-build bash /srv/rom/src/lineage/vendor/sunfish-a16/../../../../\
|
||||
# prefer:
|
||||
bash /path/to/AXP_Resurection/scripts/009-generate-release-keys.sh
|
||||
```
|
||||
|
||||
Script writes under `/srv/rom/secrets/android-certs/` when that parent is
|
||||
writable, otherwise `$HOME/.android-certs` (Lineage default). On rom-dev01
|
||||
(2026-09-29) secrets/ is root-owned without group write → keys live in
|
||||
`/home/android-build/.android-certs/`. Refuses overwrite. Reminds about
|
||||
encrypted offline backup before first signed ship bacon.
|
||||
|
||||
## Wire (US-S2 — after keys exist)
|
||||
|
||||
In the bacon environment (not committed secrets):
|
||||
|
||||
```bash
|
||||
export PRODUCT_DEFAULT_DEV_CERTIFICATE=$HOME/.android-certs/releasekey
|
||||
# after root relocate: /srv/rom/secrets/android-certs/releasekey
|
||||
# lunch lineage_sunfish-userdebug # first signed build
|
||||
# later: lineage_sunfish-user
|
||||
```
|
||||
|
||||
`009-bacon-axp-stage1-combo4.sh` auto-exports when `$HOME/.android-certs/releasekey.pk8` exists.
|
||||
## AVB (US-S3)
|
||||
|
||||
Default tree falls back to AOSP `external/avb/test/data/testkey_rsa2048.pem`
|
||||
(and LAB has been observed with `testkey_rsa4096`) plus
|
||||
`BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS += --flags 3` unless `WITH_AVB=true`
|
||||
(`device/google/sunfish/BoardConfigLineage.mk`).
|
||||
|
||||
Project key generation is in `009-generate-release-keys.sh`
|
||||
(`avb.pem` + `avb_pkmd.bin`). **Wire in tree** (soong-safe path), not only env:
|
||||
|
||||
`vendor/sunfish-a16/BoardConfig.mk` sets `BOARD_AVB_KEY_PATH` /
|
||||
`BOARD_AVB_ALGORITHM=SHA256_RSA4096` when `certs/avb.pem` exists. Keep
|
||||
`WITH_AVB` unset → vbmeta **flags 3** =
|
||||
`HASHTREE_DISABLED|VERIFICATION_DISABLED` (libavb) → Magisk preroot on
|
||||
unlocked/orange. That is **signing infrastructure**, not runtime AVB harden.
|
||||
|
||||
Validate after bacon (script fail-closed) on **target_files `IMAGES/`** (the
|
||||
OTA pair). Do not use `out/target/product/$DEVICE/{boot,vbmeta}.img` alone —
|
||||
those make images can be stock and disagree with the Magisk payload in the zip.
|
||||
Gates: pubkey sha1 == `avb_pkmd.bin` (not AOSP testkey); flags 3;
|
||||
`verify_image --key` + `--expected_chain_partition vbmeta_system:1:avb_pkmd.bin`;
|
||||
`magiskboot cpio test` ≠ 0; LAB stays `flash.locked=0` + Magisk works.
|
||||
|
||||
**OEM unlocking:** leave enabled as a best-effort escape hatch (not a recovery
|
||||
guarantee). Do not relock the bootloader on this Magisk track.
|
||||
|
||||
## Branding
|
||||
|
||||
`TARGET_UNOFFICIAL_BUILD_ID=AXP-Resurection-Pro` is set at the **top** of
|
||||
`device/google/sunfish/lineage_sunfish.mk` (before inheriting
|
||||
`vendor/lineage` → `version.mk`). Helper:
|
||||
`apply_009_unofficial_build_id.py`. **Pro** = full Magisk resurrection track
|
||||
(not a future slim/minimal variant). Mirrors GOLDEN’s `…-sunfish-pro` /
|
||||
releasetype `PRO` intent without patching `vendor/lineage/config/version.mk`.
|
||||
|
||||
`branding.mk` adds `ro.axp.resurection.track=pro`. Ship scripts also publish
|
||||
`AXP-Resurection-Pro-<ver>-<date>-sunfish.zip` as a hardlink/copy of the
|
||||
Lineage `bacon` zip (no rebuild solely to rename).
|
||||
|
||||
|
||||
## Never
|
||||
|
||||
- Commit `*.pk8`, private `*.pem`, or pass files.
|
||||
- Relock LAB/GOLDEN as a project requirement (OEM unlock-always-on does not
|
||||
make Magisk+relock safe).
|
||||
- Flash old `kh-cve` / `kh-full` zips from 2026-09-18.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Stage1 build fixes (FR-017)
|
||||
|
||||
> **2026-09-26 audit:** The FORTIFY BUG stubs below are a historical link
|
||||
> workaround, **not an accepted fix**. The latest ksync FORTIFY image fails
|
||||
> boot according to the owner. Clang exclusion in Kconfig references an
|
||||
> undefined CC_IS_CLANG symbol. See
|
||||
> [the FORTIFY audit](../../../../docs/009-fortify-boot-audit-20260926.md)
|
||||
> before reusing this workaround.
|
||||
|
||||
Applied on host `msm-4.14` when Stage1 Graphene/AH hit compile/link issues:
|
||||
|
||||
1. **slab 0014 misfuzz** — Graphene patch targeted `slab_equal_or_root`;
|
||||
fuzz applied to `is_root_cache`. Reverted `is_root_cache` to `return true`.
|
||||
LOS already has `slab_equal_or_root` → `s == p`.
|
||||
2. **FORTIFY + Clang LTO (historical, invalid as ship fix)** —
|
||||
`CONFIG_FORTIFY_SOURCE=y` caused modpost undefined `__read_overflow*` /
|
||||
`__write_overflow` in qcacld/techpack. Temporary `BUG()` stubs were
|
||||
added in `lib/string.c` to force a link; LAB then failed to boot.
|
||||
**Do not reuse.** Real work: Clang FORTIFY port — see
|
||||
`docs/009-fortify-clang-port.md` and `docs/009-fortify-boot-audit-20260926.md`.
|
||||
|
||||
See `docs/009-kernel-hardening-map.md`.
|
||||
@@ -0,0 +1,83 @@
|
||||
# 009 kernel hardening Stage 1 (FR-017)
|
||||
|
||||
**Source**: AXP `kernel_patches` @ `df3cab2155b3` (GrapheneOS / AndroidHardening
|
||||
series in Divest-era layout).
|
||||
**Base**: LOS `kernel/google/msm-4.14` @ `28f9290ae067` (`4.14.357-openela`).
|
||||
**Map**: `docs/009-kernel-hardening-map.md`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `stage1.list` | Ordered allowlist (30 patches) |
|
||||
| `apply_stage1.sh` | Applies list onto a kernel tree |
|
||||
|
||||
## Host usage (`rom-dev01`)
|
||||
|
||||
```bash
|
||||
# dry-run
|
||||
bash vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1.sh \
|
||||
/srv/rom/src/lineage/kernel/google/msm-4.14 --dry-run
|
||||
|
||||
# apply (dirties the lineage kernel checkout)
|
||||
bash vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1.sh \
|
||||
/srv/rom/src/lineage/kernel/google/msm-4.14
|
||||
```
|
||||
|
||||
Optional: `AXP_KERNEL_PATCHES=/path/to/kernel_patches`.
|
||||
|
||||
After apply, flip `sunfish_defconfig` options that the new Kconfig allows
|
||||
(at least `CONFIG_FORTIFY_SOURCE=y`); see map `KH-CFG`.
|
||||
|
||||
## Boot-OK pack (2026-09-28 LAB) — prefer for Magisk bacon
|
||||
|
||||
Stage1 Graphene alone historically hung at the Google logo on LOS23/Clang.
|
||||
The pack that boots with Magisk-track `boot-make` is **combo4 + Clang FORTIFY**
|
||||
(no Stage1 mega-pack):
|
||||
|
||||
```bash
|
||||
# on a reset msm-4.14 @ 28f9290ae067:
|
||||
bash vendor/sunfish-a16/patches/009-kernel-hardening/apply_combo4_fortify.sh \
|
||||
/path/to/msm-4.14
|
||||
```
|
||||
|
||||
That applies `fortify-clang/` (incl. nested `__underlying_strlen` fix) +
|
||||
driver bounds + defconfig:
|
||||
`FORTIFY_SOURCE`, `INIT_ON_*`, `SECURITY_DMESG_RESTRICT`,
|
||||
`SLAB_FREELIST_HARDENED`. Bacon entrypoint:
|
||||
`scripts/009-bacon-axp-combo4-fortify.sh`.
|
||||
|
||||
## Stage1 + combo4 (full bacon, Wi‑Fi coherent)
|
||||
|
||||
```bash
|
||||
# reset msm-4.14 @ 28f9290ae067, then:
|
||||
bash vendor/sunfish-a16/patches/009-kernel-hardening/apply_stage1_combo4.sh \
|
||||
/path/to/msm-4.14
|
||||
# bacon: scripts/009-bacon-axp-stage1-combo4.sh
|
||||
```
|
||||
|
||||
Order: Stage1 (30) → slab BUILD-FIXES if needed → combo4+FORTIFY.
|
||||
Ship via **sideload of the zip** (matching vendor/`wlan.ko`). Do not flash
|
||||
only the new boot onto an old slot.
|
||||
|
||||
**LAB accepted 2026-09-29:** see `docs/009-gate-g-kernel-attribution.md`.
|
||||
|
||||
## GPS / location (FR-018 — do not regress)
|
||||
|
||||
Owner wants **precise, fast GPS** (stock LOS behaviour). **Never** apply AXP
|
||||
location lockdown, SUPL/IMSI stripping that hurts TTFF, or extra location
|
||||
caps vs LOS 23.2. Stage1 list, `cve-strict.list`, and denylist must stay
|
||||
free of location-lockdown series (`KH-LOC` = skip). If a future CVE hunk
|
||||
touches GNSS/GPS paths only for a real security fix, keep LOS-equivalent
|
||||
behaviour and document; do not “harden location” as a side goal.
|
||||
|
||||
## Not in Stage 1 alone
|
||||
|
||||
- CVE mega — now staged via `apply_stage1_combo4_cve.sh` + `cve-strict.list`
|
||||
(~503 AXP allowlist from 2026-09-18 strict pass; `cve-denylist.txt` skipped).
|
||||
Bacon: `scripts/009-bacon-axp-stage1-combo4-cve.sh` (test-keys; after
|
||||
boot-OK Stage1 pack). **Do not** flash `20260918*-axp-kh-cve/full`.
|
||||
- LinuxIncrementals
|
||||
- Failed probe patches (port later)
|
||||
- Location lockdown (FR-018)
|
||||
- Iodé kernel (no sunfish 4.14 fork found)
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# Apply the LAB-verified combo4 + Clang FORTIFY pack onto a clean msm-4.14 tree.
|
||||
#
|
||||
# Boot-OK on sunfish LAB 2026-09-28 (ksync combo4-fortify-fix). This is NOT
|
||||
# the full Graphene Stage1 pack (Stage1 alone historically hung at Google logo).
|
||||
#
|
||||
# Usage: apply_combo4_fortify.sh <kernel-tree>
|
||||
# Expects a virgin / reset tree (apply_fortify_clang.py is not idempotent).
|
||||
set -e
|
||||
|
||||
K=${1:?kernel tree}
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
FC="$HERE/fortify-clang"
|
||||
|
||||
test -d "$K/include/linux"
|
||||
test -f "$FC/apply_fortify_clang.py"
|
||||
test -f "$FC/0001-driver-bounds-rtac-fils.patch"
|
||||
|
||||
python3 "$FC/apply_fortify_clang.py" "$K"
|
||||
patch -p1 --forward --batch -d "$K" < "$FC/0001-driver-bounds-rtac-fils.patch"
|
||||
|
||||
DEF="$K/arch/arm64/configs/sunfish_defconfig"
|
||||
test -f "$DEF"
|
||||
|
||||
# Drop any prior toggles we manage, then enable the boot-OK set.
|
||||
for k in \
|
||||
FORTIFY_SOURCE \
|
||||
INIT_ON_ALLOC_DEFAULT_ON \
|
||||
INIT_ON_FREE_DEFAULT_ON \
|
||||
SECURITY_DMESG_RESTRICT \
|
||||
SLAB_FREELIST_HARDENED \
|
||||
SLAB_HARDENED
|
||||
do
|
||||
sed -i "/CONFIG_${k}/d" "$DEF"
|
||||
done
|
||||
|
||||
# Keep KernelSU off on this Magisk track.
|
||||
sed -i '/CONFIG_KSU/d' "$DEF"
|
||||
echo '# CONFIG_KSU is not set' >> "$DEF"
|
||||
|
||||
for k in \
|
||||
CONFIG_FORTIFY_SOURCE \
|
||||
CONFIG_INIT_ON_ALLOC_DEFAULT_ON \
|
||||
CONFIG_INIT_ON_FREE_DEFAULT_ON \
|
||||
CONFIG_SECURITY_DMESG_RESTRICT \
|
||||
CONFIG_SLAB_FREELIST_HARDENED
|
||||
do
|
||||
echo "${k}=y" >> "$DEF"
|
||||
done
|
||||
|
||||
echo "OK: combo4+FORTIFY applied on $K"
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
# Apply AXP CVE allowlist onto msm-4.14 (after Stage1+combo4).
|
||||
# Source: AXP kernel_patches + cve_checker strict list / bisect slices.
|
||||
#
|
||||
# Safety (2026-09-29 review):
|
||||
# - Default: ABORT on first patch failure (no continue-with-partial-tree).
|
||||
# - Keep *.rej / *.orig under CVE_REJECT_DIR (do not silently delete).
|
||||
# - Treat large line-offsets / fuzz as WARN or FAIL (mis-apply risk).
|
||||
# - Set CVE_STRICT_CONTINUE=1 only for forensic runs (explicit).
|
||||
set -euo pipefail
|
||||
|
||||
KP="${AXP_KERNEL_PATCHES:-/srv/rom/references/axp/kernel_patches}"
|
||||
KERNEL_DIR="${1:-/srv/rom/src/lineage/kernel/google/msm-4.14}"
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
LIST="${CVE_STRICT_LIST:-$HERE/cve-strict.list}"
|
||||
DENY="${CVE_DENYLIST:-$HERE/cve-denylist.txt}"
|
||||
LOG_DIR="${CVE_APPLY_LOG_DIR:-/srv/rom/artifacts/009-axp-los23-port/cve-stage}"
|
||||
CONTINUE="${CVE_STRICT_CONTINUE:-0}"
|
||||
# Reject apply if GNU patch reports fuzz >= this (0 = disable fuzz fail)
|
||||
MAX_FUZZ="${CVE_MAX_FUZZ:-1}"
|
||||
# Reject if any hunk offset abs(lines) >= this (0 = disable)
|
||||
MAX_ABS_OFFSET="${CVE_MAX_ABS_OFFSET:-200}"
|
||||
DRY_RUN=0
|
||||
[[ "${2:-}" == "--dry-run" ]] && DRY_RUN=1
|
||||
|
||||
if [[ ! -d "$KERNEL_DIR/include/linux" ]]; then
|
||||
echo "error: kernel dir missing: $KERNEL_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$KP" ]]; then
|
||||
echo "error: AXP kernel_patches missing: $KP" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$LIST" ]]; then
|
||||
echo "error: list missing: $LIST" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
LOG="$LOG_DIR/apply-cve-strict-${STAMP}.log"
|
||||
FAIL_LIST="$LOG_DIR/apply-cve-strict-${STAMP}.fail.txt"
|
||||
REJECT_DIR="${CVE_REJECT_DIR:-$LOG_DIR/rejects-${STAMP}}"
|
||||
mkdir -p "$REJECT_DIR"
|
||||
: >"$FAIL_LIST"
|
||||
|
||||
declare -A DENY_MAP=()
|
||||
if [[ -f "$DENY" ]]; then
|
||||
while IFS= read -r d || [[ -n "$d" ]]; do
|
||||
[[ -z "$d" || "$d" =~ ^# ]] && continue
|
||||
if [[ "$d" == *"/kernel_patches/"* ]]; then
|
||||
DENY_MAP["${d##*/kernel_patches/}"]=1
|
||||
else
|
||||
DENY_MAP["$d"]=1
|
||||
fi
|
||||
done <"$DENY"
|
||||
fi
|
||||
|
||||
ok=0
|
||||
fail=0
|
||||
skip=0
|
||||
miss=0
|
||||
quality_fail=0
|
||||
|
||||
echo "=== CVE strict apply kernel=$KERNEL_DIR dry_run=$DRY_RUN continue=$CONTINUE max_fuzz=$MAX_FUZZ max_abs_offset=$MAX_ABS_OFFSET ===" | tee "$LOG"
|
||||
|
||||
while IFS= read -r rel || [[ -n "$rel" ]]; do
|
||||
[[ -z "$rel" || "$rel" =~ ^# ]] && continue
|
||||
if [[ -n "${DENY_MAP[$rel]:-}" ]]; then
|
||||
echo "SKIP_DENY $rel" | tee -a "$LOG"
|
||||
skip=$((skip + 1))
|
||||
continue
|
||||
fi
|
||||
p="$KP/$rel"
|
||||
if [[ ! -f "$p" ]]; then
|
||||
echo "MISS $rel" | tee -a "$LOG"
|
||||
miss=$((miss + 1))
|
||||
echo "$rel" >>"$FAIL_LIST"
|
||||
if [[ "$CONTINUE" != "1" ]]; then
|
||||
echo "error: missing patch (abort)" >&2
|
||||
exit 1
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
args=(-p1 --batch -d "$KERNEL_DIR" --forward --no-backup-if-mismatch)
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
args+=(--dry-run)
|
||||
fi
|
||||
|
||||
patch_log=$(mktemp)
|
||||
set +e
|
||||
patch "${args[@]}" <"$p" >"$patch_log" 2>&1
|
||||
prc=$?
|
||||
set -e
|
||||
cat "$patch_log" >>"$LOG"
|
||||
|
||||
# Quality: fuzz / large offsets even when exit 0
|
||||
fuzz_max=0
|
||||
abs_off_max=0
|
||||
eval "$(python3 -c '
|
||||
import re, sys
|
||||
text = open(sys.argv[1], errors="replace").read()
|
||||
fuzz = off = 0
|
||||
for m in re.finditer(r"with fuzz (\d+)", text):
|
||||
fuzz = max(fuzz, int(m.group(1)))
|
||||
for m in re.finditer(r"\(offset ([+-]?\d+) lines\)", text):
|
||||
off = max(off, abs(int(m.group(1))))
|
||||
print(f"fuzz_max={fuzz}")
|
||||
print(f"abs_off_max={off}")
|
||||
' "$patch_log")"
|
||||
rm -f "$patch_log"
|
||||
|
||||
qbad=0
|
||||
if [[ "$MAX_FUZZ" -gt 0 && "$fuzz_max" -ge "$MAX_FUZZ" ]]; then
|
||||
echo "QUALITY_FAIL fuzz=$fuzz_max>=$MAX_FUZZ $rel" | tee -a "$LOG"
|
||||
qbad=1
|
||||
fi
|
||||
if [[ "$MAX_ABS_OFFSET" -gt 0 && "$abs_off_max" -ge "$MAX_ABS_OFFSET" ]]; then
|
||||
echo "QUALITY_FAIL abs_offset=$abs_off_max>=$MAX_ABS_OFFSET $rel" | tee -a "$LOG"
|
||||
qbad=1
|
||||
fi
|
||||
|
||||
if [[ "$prc" -eq 0 && "$qbad" -eq 0 ]]; then
|
||||
echo "OK $rel (fuzz_max=$fuzz_max abs_off_max=$abs_off_max)" | tee -a "$LOG"
|
||||
ok=$((ok + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Failure path: preserve rejects
|
||||
echo "FAIL $rel patch_rc=$prc fuzz_max=$fuzz_max abs_off_max=$abs_off_max" | tee -a "$LOG"
|
||||
echo "$rel" >>"$FAIL_LIST"
|
||||
fail=$((fail + 1))
|
||||
[[ "$qbad" -eq 1 ]] && quality_fail=$((quality_fail + 1))
|
||||
|
||||
safe=$(echo "$rel" | tr '/' '_')
|
||||
dest="$REJECT_DIR/$safe"
|
||||
mkdir -p "$dest"
|
||||
# move any rej/orig created under kernel tree
|
||||
while IFS= read -r -d '' rej; do
|
||||
mv "$rej" "$dest/" 2>/dev/null || cp -a "$rej" "$dest/" || true
|
||||
done < <(find "$KERNEL_DIR" -name '*.rej' -print0 2>/dev/null)
|
||||
while IFS= read -r -d '' orig; do
|
||||
mv "$orig" "$dest/" 2>/dev/null || cp -a "$orig" "$dest/" || true
|
||||
done < <(find "$KERNEL_DIR" -name '*.orig' -print0 2>/dev/null)
|
||||
cp -a "$p" "$dest/patch" 2>/dev/null || true
|
||||
echo "rejects_kept=$dest" | tee -a "$LOG"
|
||||
|
||||
if [[ "$CONTINUE" != "1" ]]; then
|
||||
echo "error: abort on FAIL (set CVE_STRICT_CONTINUE=1 to keep going)" >&2
|
||||
echo "CVE strict ABORT OK=$ok FAIL=$fail QUALITY_FAIL=$quality_fail SKIP_DENY=$skip MISS=$miss log=$LOG" | tee -a "$LOG"
|
||||
exit 1
|
||||
fi
|
||||
done <"$LIST"
|
||||
|
||||
echo "CVE strict done OK=$ok FAIL=$fail QUALITY_FAIL=$quality_fail SKIP_DENY=$skip MISS=$miss dry_run=$DRY_RUN continue=$CONTINUE log=$LOG rejects=$REJECT_DIR" | tee -a "$LOG"
|
||||
|
||||
if [[ "$fail" -gt 0 && "$CONTINUE" != "1" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$ok" -eq 0 && "$DRY_RUN" -eq 0 ]]; then
|
||||
echo "error: zero CVE patches applied" >&2
|
||||
exit 1
|
||||
fi
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Apply FR-017 Stage 1 AXP Graphene/AH patches to LOS msm-4.14.
|
||||
# Attribute: AXP kernel_patches (GrapheneOS / AndroidHardening series via Divest-era layout).
|
||||
set -euo pipefail
|
||||
|
||||
KP="${AXP_KERNEL_PATCHES:-/srv/rom/references/axp/kernel_patches}"
|
||||
KERNEL_DIR="${1:-/srv/rom/src/lineage/kernel/google/msm-4.14}"
|
||||
LIST="$(cd "$(dirname "$0")" && pwd)/stage1.list"
|
||||
DRY_RUN=0
|
||||
if [[ "${2:-}" == "--dry-run" ]]; then
|
||||
DRY_RUN=1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$KERNEL_DIR" ]]; then
|
||||
echo "error: kernel dir missing: $KERNEL_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$KP" ]]; then
|
||||
echo "error: AXP kernel_patches missing: $KP" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ok=0
|
||||
fail=0
|
||||
while IFS= read -r rel || [[ -n "$rel" ]]; do
|
||||
[[ -z "$rel" || "$rel" =~ ^# ]] && continue
|
||||
p="$KP/$rel"
|
||||
if [[ ! -f "$p" ]]; then
|
||||
echo "FAIL missing $rel"
|
||||
fail=$((fail + 1))
|
||||
continue
|
||||
fi
|
||||
args=(-p1 --batch -d "$KERNEL_DIR")
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
args+=(--dry-run)
|
||||
fi
|
||||
if patch "${args[@]}" < "$p"; then
|
||||
echo "OK $rel"
|
||||
ok=$((ok + 1))
|
||||
else
|
||||
echo "FAIL $rel"
|
||||
fail=$((fail + 1))
|
||||
find "$KERNEL_DIR" -name '*.rej' -delete 2>/dev/null || true
|
||||
find "$KERNEL_DIR" -name '*.orig' -delete 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
done < "$LIST"
|
||||
|
||||
echo "Stage1 done OK=$ok FAIL=$fail dry_run=$DRY_RUN"
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# Stage1 Graphene/AH (30 patches) + combo4 Clang FORTIFY pack on a clean msm-4.14.
|
||||
#
|
||||
# Order: Stage1 first (virgin tree), then apply_combo4_fortify.sh (Clang POS +
|
||||
# nested __underlying_strlen + driver bounds + combo4 defconfig).
|
||||
# Expects reset tree @ 28f9290ae067 (apply_fortify_clang.py is not idempotent).
|
||||
#
|
||||
# Full bacon with this pack ships matching vendor modules (Wi-Fi). Boot-only
|
||||
# flash onto an older vendor can break wlan CRC — prefer sideload of the zip.
|
||||
set -e
|
||||
|
||||
K=${1:?kernel tree}
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
|
||||
test -d "$K/include/linux"
|
||||
test -x "$HERE/apply_stage1.sh" || chmod +x "$HERE/apply_stage1.sh"
|
||||
test -x "$HERE/apply_combo4_fortify.sh" || chmod +x "$HERE/apply_combo4_fortify.sh"
|
||||
|
||||
bash "$HERE/apply_stage1.sh" "$K"
|
||||
|
||||
# Historical Stage1 slab/0014 misfuzz: if is_root_cache was corrupted, restore.
|
||||
python3 - <<'PY' "$K"
|
||||
from pathlib import Path
|
||||
import sys
|
||||
p = Path(sys.argv[1]) / "mm/slab.h"
|
||||
t = p.read_text()
|
||||
bad = """static inline bool is_root_cache(struct kmem_cache *s)
|
||||
{
|
||||
#ifdef CONFIG_SLAB_HARDENED
|
||||
\treturn p == s;
|
||||
#else
|
||||
\treturn true;
|
||||
#endif
|
||||
}"""
|
||||
good = """static inline bool is_root_cache(struct kmem_cache *s)
|
||||
{
|
||||
\treturn true;
|
||||
}"""
|
||||
if bad in t:
|
||||
p.write_text(t.replace(bad, good, 1))
|
||||
print("OK: reverted Stage1 slab/0014 misfuzz in is_root_cache")
|
||||
else:
|
||||
print("OK: is_root_cache looks unmisfuzzed (no BUILD-FIXES edit)")
|
||||
PY
|
||||
|
||||
bash "$HERE/apply_combo4_fortify.sh" "$K"
|
||||
echo "OK: Stage1 + combo4+FORTIFY applied on $K"
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# Stage1 + combo4+FORTIFY + AXP CVE strict allowlist on clean msm-4.14.
|
||||
# Boot-OK baseline first (LAB 2026-09-29), then CVE mega that compiled 2026-09-18.
|
||||
# FR-018: no location lockdown — keep GPS precise/fast (LOS defaults).
|
||||
set -e
|
||||
K=${1:?kernel tree}
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
|
||||
test -d "$K/include/linux"
|
||||
bash "$HERE/apply_stage1_combo4.sh" "$K"
|
||||
bash "$HERE/apply_cve_strict.sh" "$K"
|
||||
echo "OK: Stage1 + combo4+FORTIFY + CVE-strict applied on $K (no location lockdown)"
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# US-S5-1 — enable remaining Graphene/AXP-class defconfig knobs on msm-4.14.
|
||||
#
|
||||
# Oracle: AXP/Graphene kernel hardening expects Yama + slab freelist random
|
||||
# (combo4 already ships SLAB_FREELIST_HARDENED). LOS sunfish_defconfig left both
|
||||
# off; CONFIG_LSM already lists yama but SECURITY_YAMA was unset so the LSM
|
||||
# never built.
|
||||
#
|
||||
# Does NOT apply high-offset CVE leftovers (nf_tables deliberately skipped) or
|
||||
# CVE-2022-49980 (denylist until lock-scope port).
|
||||
#
|
||||
# Usage: apply_uss5_1_defconfig.sh <kernel-tree>
|
||||
set -euo pipefail
|
||||
|
||||
K=${1:?kernel tree}
|
||||
DEF="$K/arch/arm64/configs/sunfish_defconfig"
|
||||
test -f "$DEF"
|
||||
test -f "$K/security/yama/Kconfig"
|
||||
|
||||
for k in SECURITY_YAMA SLAB_FREELIST_RANDOM; do
|
||||
sed -i "/CONFIG_${k}/d" "$DEF"
|
||||
# drop "# CONFIG_FOO is not set" lines too (sed above only matches CONFIG_FOO=)
|
||||
sed -i "/# CONFIG_${k} is not set/d" "$DEF"
|
||||
done
|
||||
|
||||
{
|
||||
echo "CONFIG_SECURITY_YAMA=y"
|
||||
echo "CONFIG_SLAB_FREELIST_RANDOM=y"
|
||||
} >> "$DEF"
|
||||
|
||||
echo "OK: US-S5-1 defconfig (YAMA + SLAB_FREELIST_RANDOM) on $K"
|
||||
@@ -0,0 +1 @@
|
||||
CVE-2022-49980/ANY/0001.patch
|
||||
Loaded 100 of 129 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user