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:
sunfish-admin committed 2026-10-05 10:42:00 +02:00
1 parent fd793b9471
commit deaaf42caa
129 files changed
+11769 -141

No files matched your search

@@ -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,36 @@
# FORTIFY Clang port for msm-4.14 (LOS sunfish)
Based on Kees Cook *fortify: Add Clang support* (upstream ~2022), adapted
to 4.14’s in-`string.h` FORTIFY (no `fortify-string.h` yet).
**Not** AXP `0004` (strict-string). **Not** `BUG()` link stubs.
See `docs/009-fortify-clang-port.md`.
## Apply
```bash
# on rom-dev01, after git reset of msm-4.14:
python3 apply_fortify_clang.py /path/to/msm-4.14
patch -p1 -d /path/to/msm-4.14 < 0001-driver-bounds-rtac-fils.patch
```
`ksync-one.sh` with `CONFIG_FORTIFY_SOURCE` runs both automatically.
Then enable `CONFIG_FORTIFY_SOURCE=y` and build **without**
`ALLOW_FORTIFY_BUG_STUBS`.
## Nested strlen (required)
With Clang `__pass_object_size`, fortified `strlcpy`/`strcpy` must call
`__underlying_strlen(q)`, not fortified `strlen(q)`. Otherwise a known
source object size makes `strlen` panic at boot (LAB: `strlen+strlcpy`
fail; `strlen+strncpy` OK). `apply_fortify_clang.py` rewrites both.
## Diag capture (v4)
`apply_fortify_diag.py` — `early_ioremap` before `parse_early_param`, ordinary
`ioremap` only after `mm_init`, never map from the failure handler; failure
and milestone zones separated. See `docs/009-fortify-diag-capture-plan.md`
and `docs/009-fortify-diag-v3-review-20260927.md`. Control:
`PSTORE_ALT_PLAIN=1` / `scripts/009-bisect-ksync-pstore-alt-plain.sh`.
@@ -0,0 +1,244 @@
#!/usr/bin/env python3
"""Apply minimal Clang FORTIFY adaptations to msm-4.14 (Kees-style).
Edits:
- include/linux/compiler-clang.h — __pass_object_size / __overloadable / __diagnose_as
- include/linux/string.h — __FORTIFY_INLINE + POS/POS0 on fortified params
- security/Kconfig — allow FORTIFY on Clang when this port is present
(tree lacks CC_IS_CLANG Kconfig symbols; !CC_IS_CLANG was a no-op)
Idempotent. Exit 0 on success.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
MARKER = "/* AXP_Resurection: fortify-clang port (Kees-style) */"
def patch_compiler_clang(path: Path) -> None:
t = path.read_text()
if MARKER in t and "__pass_object_size" in t:
print(f"skip {path} (already patched)")
return
if "__pass_object_size" in t:
print(f"skip {path} (attrs already present)")
return
block = f"""
{MARKER}
/*
* Clang FORTIFY helpers (upstream fortify Clang support / Kees Cook).
* pass_object_size makes __builtin_object_size work through fortified inlines.
*/
#if __has_attribute(pass_object_size)
# define __pass_object_size(type) __attribute__((__pass_object_size__(type)))
#else
# define __pass_object_size(type)
#endif
#if __has_attribute(overloadable)
# define __overloadable __attribute__((__overloadable__))
#else
# define __overloadable
#endif
#if __has_attribute(diagnose_as_builtin)
# define __diagnose_as(builtin...) __attribute__((__diagnose_as_builtin__(builtin)))
#else
# define __diagnose_as(builtin...)
#endif
"""
path.write_text(t.rstrip() + "\n" + block + "\n")
print(f"patched {path}")
def patch_kconfig(path: Path) -> None:
t = path.read_text()
old = (
"\t# https://bugs.llvm.org/show_bug.cgi?id=50322\n"
"\t# https://bugs.llvm.org/show_bug.cgi?id=41459\n"
"\tdepends on !CC_IS_CLANG\n"
)
new = (
"\t# Clang: upstream disabled FORTIFY until wrappers existed (LLVM 41459).\n"
"\t# This tree never defined CC_IS_CLANG, so !CC_IS_CLANG was a no-op.\n"
"\t# Fortify-clang port (vendor/.../fortify-clang) supplies Kees-style\n"
"\t# __pass_object_size / __overloadable wrappers for Clang 12+.\n"
"\t# https://bugs.llvm.org/show_bug.cgi?id=41459\n"
)
if MARKER.split()[2] in t and "Fortify-clang port" in t:
print(f"skip {path} (already patched)")
return
if old not in t:
if "depends on !CC_IS_CLANG" in t:
t2 = t.replace(
"\tdepends on !CC_IS_CLANG\n",
new,
1,
)
if t2 == t:
raise SystemExit(f"could not patch {path}")
path.write_text(t2)
print(f"patched {path} (depends line only)")
return
raise SystemExit(f"FORTIFY depends block not found in {path}")
path.write_text(t.replace(old, new, 1))
print(f"patched {path}")
def patch_string_h(path: Path) -> None:
t = path.read_text()
if "AXP_Resurection: fortify-clang" in t and "POS0" in t:
print(f"skip {path} (already patched)")
return
old_inline = (
"#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))\n"
)
# 4.14 fortify bodies all use __builtin_object_size(*, 0) (whole object).
# pass_object_size(N) must match that N or Clang returns -1 (no checking).
# Do NOT use pass_object_size(1) here — that is STRICT_STRING / type-1 policy
# (AXP 0004), a separate step. See docs/009-fortify-port-review-20260926.md.
new_inline = (
f"{MARKER}\n"
"/* Clang: __overloadable + __pass_object_size matching bos type 0. */\n"
"#ifdef __clang__\n"
"# define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) __overloadable\n"
"# define POS __pass_object_size(0)\n"
"# define POS0 __pass_object_size(0)\n"
"#else\n"
"# define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline))\n"
"# define POS\n"
"# define POS0\n"
"#endif\n"
)
if old_inline not in t:
raise SystemExit("__FORTIFY_INLINE define not found")
t = t.replace(old_inline, new_inline, 1)
# Rewrite fortified prototypes to pass object size (Kees-style POS/POS0).
replacements = [
(
"__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)",
"__FORTIFY_INLINE char *strncpy(char * const POS0 p, const char * const POS q, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE char *strcat(char *p, const char *q)",
"__FORTIFY_INLINE char *strcat(char * const POS0 p, const char * const POS q)",
),
(
"__FORTIFY_INLINE __kernel_size_t strlen(const char *p)",
"__FORTIFY_INLINE __kernel_size_t strlen(const char * const POS p)",
),
(
"__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)",
"__FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size_t maxlen)",
),
(
"__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)",
"__FORTIFY_INLINE size_t strlcpy(char * const POS0 p, const char * const POS q, size_t size)",
),
(
"__FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)",
"__FORTIFY_INLINE char *strncat(char * const POS0 p, const char * const POS q, __kernel_size_t count)",
),
(
"__FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)",
"__FORTIFY_INLINE void *memset(void * const POS0 p, int c, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)",
"__FORTIFY_INLINE void *memcpy(void * const POS0 p, const void * const POS0 q, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size)",
"__FORTIFY_INLINE void *memmove(void * const POS0 p, const void * const POS0 q, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size)",
"__FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size)",
"__FORTIFY_INLINE int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)",
"__FORTIFY_INLINE void *memchr(const void * const POS0 p, int c, __kernel_size_t size)",
),
(
"__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size)",
"__FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size)",
),
(
"__FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp)",
"__FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp)",
),
(
"__FORTIFY_INLINE char *strcpy(char *p, const char *q)",
"__FORTIFY_INLINE char *strcpy(char * const POS0 p, const char * const POS q)",
),
]
for a, b in replacements:
if a not in t:
raise SystemExit(f"missing fortify prototype:\n{a}")
t = t.replace(a, b, 1)
# With Clang __pass_object_size, fortified strlen(q) sees a known object
# size and panics when the C string is not NUL-terminated within that
# bound. strlcpy/strcpy intentionally need the unbounded source length
# (same as the GCC path when bos was usually -1). Use the underlying
# strlen so enabling both wrappers does not brick boot.
# LAB bisect 2026-09-28: strlen+strlcpy fails; strlen+strncpy boots.
old_strlcpy_len = "\tret = strlen(q);\n"
new_strlcpy_len = (
"\t/* AXP_Resurection: fortify-clang — do not nest fortified strlen */\n"
"\tret = __underlying_strlen(q);\n"
)
if "ret = __underlying_strlen(q);" not in t:
if old_strlcpy_len not in t:
raise SystemExit("strlcpy strlen(q) probe not found")
t = t.replace(old_strlcpy_len, new_strlcpy_len, 1)
old_strcpy_len = "\tmemcpy(p, q, strlen(q) + 1);\n"
new_strcpy_len = (
"\tmemcpy(p, q, __underlying_strlen(q) + 1);\n"
)
if "memcpy(p, q, __underlying_strlen(q) + 1);" not in t:
if old_strcpy_len not in t:
raise SystemExit("strcpy strlen(q) probe not found")
t = t.replace(old_strcpy_len, new_strcpy_len, 1)
# Undef POS macros at end of fortify block (before #endif of FORTIFY_SOURCE)
end_marker = (
"#undef __underlying_strncpy\n"
"#endif\n"
)
end_repl = (
"#undef __underlying_strncpy\n"
"#undef POS\n"
"#undef POS0\n"
"#endif\n"
)
if end_marker not in t:
raise SystemExit("fortify #endif marker not found")
t = t.replace(end_marker, end_repl, 1)
path.write_text(t)
print(f"patched {path}")
def main() -> int:
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} /path/to/msm-4.14", file=sys.stderr)
return 2
root = Path(sys.argv[1])
patch_compiler_clang(root / "include/linux/compiler-clang.h")
patch_string_h(root / "include/linux/string.h")
patch_kconfig(root / "security/Kconfig")
print("fortify-clang apply OK")
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,597 @@
#!/usr/bin/env python3
"""Diagnostic overlays for FORTIFY / early boot capture (msm-4.14 sunfish LAB).
v4 — docs/009-fortify-diag-v3-review-20260927.md:
- Never map from the failure handler.
- Early map: early_ioremap (FIXMAP_PAGE_IO) before setup_arch
parse_early_param — same device attrs as permanent/access-ramoops.
- Keep early map until after mm_init; ordinary ioremap only then
(needs slab/vmalloc). Clear VA before retiring early map.
- First-failure at offset 0; milestones at offset 2048 (no shared slots).
- Adopt prior failure only if a complete record (header + \\n + mirror).
- Atomic claim for first-failure; milestones never touch failure zone.
Readable: dd if=/dev/access-ramoops | strings | grep AXPDIAG
Idempotent via markers. Attempt id is bake-time only; wipe failure zone
before repeating the same image (see capture plan).
"""
from __future__ import annotations
import re
import sys
import time
from pathlib import Path
MARKER_PANIC = "/* AXP_Resurection: fortify-diag capture v4 */"
MARKER_MAIN_MM = "/* AXP_Resurection: axp-diag mm_init */"
MARKER_SETUP_EARLY = "/* AXP_Resurection: axp-diag early_map */"
MARKER_MAKEFILE = "AXP_Resurection axp_diag_capture"
ATTEMPT = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
# Sunfish DT: alt_ramoops_region@A4C1F000 size 0x400000 (no-map).
SUNFISH_ALT_PHYS = "0xA4C1F000ULL"
CAPTURE_C = r"""
/* AXP_Resurection: axp_diag_capture — LAB early plaintext alt ramoops (v4) */
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/notifier.h>
#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <asm/bug.h>
#include <asm/early_ioremap.h>
#define AXP_ALT_PHYS __SUNFISH_ALT_PHYS__
#define AXP_MAP_SIZE PAGE_SIZE
#define AXP_ATTEMPT "__ATTEMPT__"
/* Layout within the first mapped page (no shared slots). */
#define AXP_FAIL_OFF 0U
#define AXP_FAIL_MIRROR 128U
#define AXP_FAIL_SPAN 1024U /* primary + mirrors */
#define AXP_MILE_OFF 2048U
#define AXP_REC_MAX 120U
static void __iomem *axp_alt_va;
static bool axp_va_is_early;
static atomic_t axp_first_latch = ATOMIC_INIT(0);
static void notrace axp_bytes_out(void __iomem *dst, const char *src, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
writeb((u8)src[i], dst + i);
}
static void notrace axp_bytes_in(char *dst, const void __iomem *src, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
dst[i] = (char)readb(src + i);
}
static void axp_hex_u64(char *dst, unsigned long v)
{
static const char hex[] = "0123456789abcdef";
int i;
dst[0] = '0';
dst[1] = 'x';
for (i = 0; i < 16; i++)
dst[2 + i] = hex[(v >> (60 - 4 * i)) & 0xf];
dst[18] = '\0';
}
/*
* Complete first-failure: AXPDIAG1,...\n at FAIL_OFF and matching mirror.
* A truncated header alone must NOT suppress later captures.
*/
static bool notrace axp_first_complete(void)
{
char buf[AXP_REC_MAX];
char mir[AXP_REC_MAX];
size_t i, n;
if (!axp_alt_va)
return false;
axp_bytes_in(buf, axp_alt_va + AXP_FAIL_OFF, AXP_REC_MAX);
if (buf[0] != 'A' || buf[1] != 'X' || buf[2] != 'P' || buf[3] != 'D' ||
buf[4] != 'I' || buf[5] != 'A' || buf[6] != 'G' || buf[7] != '1' ||
buf[8] != ',')
return false;
n = 0;
for (i = 9; i < AXP_REC_MAX; i++) {
if (buf[i] == '\n') {
n = i + 1;
break;
}
}
if (!n)
return false;
axp_bytes_in(mir, axp_alt_va + AXP_FAIL_MIRROR, n);
for (i = 0; i < n; i++) {
if (mir[i] != buf[i])
return false;
}
return true;
}
static void notrace axp_adopt_prior_first(void)
{
if (axp_first_complete())
atomic_set(&axp_first_latch, 1);
}
/* Failure-zone write: mirrors first, primary last (commit). */
static void notrace axp_fail_commit(const char *rec, size_t n)
{
size_t i;
if (!axp_alt_va || !rec || !n)
return;
if (n > AXP_REC_MAX)
n = AXP_REC_MAX;
for (i = AXP_FAIL_MIRROR; i + n <= AXP_FAIL_SPAN; i += AXP_FAIL_MIRROR)
axp_bytes_out(axp_alt_va + i, rec, n);
wmb();
axp_bytes_out(axp_alt_va + AXP_FAIL_OFF, rec, n);
wmb();
(void)readb(axp_alt_va + AXP_FAIL_OFF);
}
static void notrace axp_mile_write(const char *rec, size_t n)
{
if (!axp_alt_va || !rec || !n)
return;
if (n > AXP_REC_MAX)
n = AXP_REC_MAX;
if (AXP_MILE_OFF + n > AXP_MAP_SIZE)
return;
axp_bytes_out(axp_alt_va + AXP_MILE_OFF, rec, n);
wmb();
(void)readb(axp_alt_va + AXP_MILE_OFF);
}
/*
* First durable failure. Format:
* AXPDIAG1,<type>,<attempt>,<caller_hex>,<token>\n
* Never maps. Null VA => lost (blind / transition window).
*/
void notrace __attribute__((no_sanitize("cfi")))
axp_diag_mark_event(char type, const char *token, void *caller)
{
char rec[128];
char hex[20];
size_t n = 0;
size_t ti;
const char *tok;
void __iomem *va = READ_ONCE(axp_alt_va);
if (!va)
return;
if (atomic_read(&axp_first_latch))
return;
if (axp_first_complete()) {
atomic_set(&axp_first_latch, 1);
return;
}
if (atomic_cmpxchg(&axp_first_latch, 0, 1) != 0)
return;
/* Re-check after claim (prior complete may have raced). */
if (axp_first_complete())
return;
axp_hex_u64(hex, (unsigned long)caller);
tok = token ? token : "?";
{
static const char pfx[] = "AXPDIAG1,";
size_t i;
for (i = 0; i < sizeof(pfx) - 1; i++)
rec[n++] = pfx[i];
}
rec[n++] = type;
rec[n++] = ',';
{
size_t i;
for (i = 0; AXP_ATTEMPT[i] && n + 1 < sizeof(rec); i++)
rec[n++] = AXP_ATTEMPT[i];
}
rec[n++] = ',';
{
size_t i;
for (i = 0; i < 18 && n + 1 < sizeof(rec); i++)
rec[n++] = hex[i];
}
rec[n++] = ',';
for (ti = 0; tok[ti] && n + 1 < sizeof(rec); ti++)
rec[n++] = tok[ti];
rec[n++] = '\n';
{
int k;
for (k = 0; k < 4; k++)
axp_fail_commit(rec, n);
}
}
EXPORT_SYMBOL_GPL(axp_diag_mark_event);
void notrace __attribute__((no_sanitize("cfi")))
axp_diag_mark_panic(const char *why)
{
axp_diag_mark_event('P', why, __builtin_return_address(0));
}
EXPORT_SYMBOL_GPL(axp_diag_mark_panic);
/* Milestones: separate offset; never touch failure zone. */
void notrace __attribute__((no_sanitize("cfi")))
axp_diag_milestone(const char *name)
{
char rec[96];
size_t n = 0;
size_t i;
static const char pfx[] = "AXPDIAG0,M,";
void __iomem *va = READ_ONCE(axp_alt_va);
if (!va)
return;
if (atomic_read(&axp_first_latch) || axp_first_complete()) {
axp_adopt_prior_first();
return;
}
for (i = 0; i < sizeof(pfx) - 1; i++)
rec[n++] = pfx[i];
for (i = 0; AXP_ATTEMPT[i] && n + 1 < sizeof(rec); i++)
rec[n++] = AXP_ATTEMPT[i];
rec[n++] = ',';
if (!name)
name = "?";
for (i = 0; name[i] && n + 1 < sizeof(rec); i++)
rec[n++] = name[i];
rec[n++] = '\n';
/* Abort if a first-failure claimed while we composed. */
if (atomic_read(&axp_first_latch) || axp_first_complete()) {
axp_adopt_prior_first();
return;
}
axp_mile_write(rec, n);
}
EXPORT_SYMBOL_GPL(axp_diag_milestone);
/*
* Early: early_ioremap (device/IO attrs), before parse_early_param.
* Kept across early_ioremap_reset until mm_init retires it.
* Permanent: ordinary ioremap ONLY after mm_init (slab + vmalloc ready).
* Failure handlers never call these.
*/
void __init axp_diag_map_early(void)
{
void __iomem *va;
if (axp_alt_va)
return;
/* FIXMAP_PAGE_IO — matches permanent ioremap / access-ramoops attrs. */
va = early_ioremap(AXP_ALT_PHYS, AXP_MAP_SIZE);
if (!va)
return;
WRITE_ONCE(axp_alt_va, va);
axp_va_is_early = true;
axp_adopt_prior_first();
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("early_map");
}
void __init axp_diag_map_permanent(void)
{
void __iomem *va;
void __iomem *old;
/*
* Ordinary ioremap needs get_vm_area → kzalloc / vmalloc.
* Call only after mm_init(). Never from setup_arch/paging_init.
*/
va = ioremap(AXP_ALT_PHYS, AXP_MAP_SIZE);
if (!va)
return;
old = READ_ONCE(axp_alt_va);
/* Publish permanent first so writers never see a stale early VA. */
WRITE_ONCE(axp_alt_va, va);
wmb();
if (axp_va_is_early && old) {
early_iounmap(old, AXP_MAP_SIZE);
axp_va_is_early = false;
} else if (old && old != va) {
iounmap(old);
}
axp_adopt_prior_first();
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("perm_map");
}
void __init axp_diag_after_mm_init(void)
{
axp_diag_map_permanent();
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("mm_init");
}
static int __init axp_diag_pure_init(void)
{
if (!READ_ONCE(axp_alt_va))
axp_diag_map_permanent();
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("pure_init");
return 0;
}
pure_initcall(axp_diag_pure_init);
static int __init axp_diag_core_init(void)
{
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("core_init");
return 0;
}
core_initcall(axp_diag_core_init);
static int notrace axp_panic_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
axp_diag_mark_event('P', data ? (const char *)data : "notifier",
__builtin_return_address(0));
return NOTIFY_OK;
}
static struct notifier_block axp_panic_nb = {
.notifier_call = axp_panic_notifier,
.priority = INT_MAX,
};
static int __init axp_diag_panic_reg(void)
{
atomic_notifier_chain_register(&panic_notifier_list, &axp_panic_nb);
if (!atomic_read(&axp_first_latch))
axp_diag_milestone("panic_reg");
return 0;
}
postcore_initcall(axp_diag_panic_reg);
"""
def write_capture_c(root: Path) -> None:
path = root / "kernel" / "axp_diag_capture.c"
body = (
CAPTURE_C.replace("__SUNFISH_ALT_PHYS__", SUNFISH_ALT_PHYS)
.replace("__ATTEMPT__", ATTEMPT)
)
if body.startswith("\n"):
body = body[1:]
path.write_text(body)
print(f"wrote {path} attempt={ATTEMPT}")
def patch_makefile(path: Path) -> None:
t = path.read_text()
if "axp_diag_capture.o" in t:
print(f"skip {path} (axp_diag_capture already listed)")
return
old = "obj-y = fork.o exec_domain.o panic.o \\"
new = f"obj-y = fork.o exec_domain.o panic.o axp_diag_capture.o \\" # {MARKER_MAKEFILE}
if old not in t:
raise SystemExit(f"kernel/Makefile obj-y panic.o line not found in {path}")
path.write_text(t.replace(old, new, 1))
print(f"patched {path}")
def patch_main_mm(path: Path) -> None:
t = path.read_text()
if "axp_diag_after_mm_init" in t:
print(f"skip {path} (already patched)")
return
old = "\tmm_init();\n"
if t.count(old) < 1:
raise SystemExit(f"mm_init(); not found in {path}")
new = f"""\tmm_init();
{MARKER_MAIN_MM}
{{
extern void axp_diag_after_mm_init(void);
axp_diag_after_mm_init();
}}
"""
path.write_text(t.replace(old, new, 1))
print(f"patched mm_init hook in {path}")
def patch_arm64_setup(path: Path) -> None:
"""Early IO map only — no ioremap before mm_init."""
t = path.read_text()
# Strip obsolete v3 permanent hook after paging_init if present.
perm_block = re.compile(
r"\tpaging_init\(\);\n"
r"/\* AXP_Resurection: axp-diag perm_map \*/\n"
r"\t\{\n"
r"\t\textern void axp_diag_map_permanent\(void\);\n"
r"\t\taxp_diag_map_permanent\(\);\n"
r"\t\}\n",
)
t2, n = perm_block.subn("\tpaging_init();\n", t, count=1)
if n:
t = t2
print(f"removed obsolete paging_init ioremap hook from {path}")
if "axp_diag_map_early" in t:
path.write_text(t)
print(f"skip early hook in {path} (already present)")
return
early_old = "\tjump_label_init();\n\tparse_early_param();\n"
early_new = f"""\tjump_label_init();
{MARKER_SETUP_EARLY}
{{
extern void axp_diag_map_early(void);
axp_diag_map_early();
}}
parse_early_param();
"""
if early_old not in t:
raise SystemExit(f"jump_label_init/parse_early_param block not found in {path}")
path.write_text(t.replace(early_old, early_new, 1))
print(f"patched arm64 setup early_ioremap in {path}")
def _replace_fortify_panic(t: str) -> str:
if "fortify-diag capture v4" in t:
return t
new = f"""{MARKER_PANIC}
extern void axp_diag_mark_event(char type, const char *token, void *caller);
void fortify_panic(const char *name)
{{
void *caller = __builtin_return_address(0);
/* Durable record FIRST — before printk/stack (may fault). Never maps. */
axp_diag_mark_event('F', name, caller);
pr_emerg("FORTIFY_DIAG: overflow in %s caller=%pS attempt=%s\\n",
name, caller, "{ATTEMPT}");
dump_stack();
BUG();
}}
"""
stock = """void fortify_panic(const char *name)
{
pr_emerg("detected buffer overflow in %s\\n", name);
BUG();
}
"""
if "AXP_Resurection: fortify-diag capture" in t:
pat = re.compile(
r"/\* AXP_Resurection: fortify-diag capture(?: v[0-9]+)? \*/.*?^void fortify_panic\(const char \*name\)\n\{.*?\n\}\n",
re.S | re.M,
)
m = pat.search(t)
if m:
return t[: m.start()] + new + t[m.end() :]
if stock in t:
return t.replace(stock, new, 1)
raise SystemExit("fortify_panic body not found / unrecognized")
def patch_fortify_panic(path: Path) -> None:
t = path.read_text()
if "fortify-diag capture v4" in t:
print(f"skip {path} (already v4)")
return
path.write_text(_replace_fortify_panic(t))
print(f"patched fortify_panic v4 in {path}")
def patch_sysrq(path: Path) -> None:
t = path.read_text()
if "axp-diag-sysrq-v4" in t:
print(f"skip {path} (already v4)")
return
if "sysrq_handle_crash" not in t:
raise SystemExit(f"sysrq_handle_crash missing in {path}")
new_crash = """/* AXP_Resurection: axp-diag-sysrq-v4 */
extern void axp_diag_mark_event(char type, const char *token, void *caller);
static void sysrq_handle_crash(int key)
{
rcu_read_unlock();
axp_diag_mark_event('C', "sysrq-c", __builtin_return_address(0));
panic("sysrq triggered crash\\n");
}
static void sysrq_handle_axp_mark(int key)
{
axp_diag_mark_event('X', "sysrq-x", __builtin_return_address(0));
}
static struct sysrq_key_op sysrq_axp_mark_op = {
.handler = sysrq_handle_axp_mark,
.help_msg = "axp-mark(x)",
.action_msg = "AXP alt diag mark",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
"""
if "AXP_Resurection: axp-diag-sysrq" in t or "pstore-alt-plain-sysrq" in t:
pat = re.compile(
r"/\* AXP_Resurection: (?:axp-diag-sysrq-v[0-9]+|pstore-alt-plain-sysrq) \*/.*?"
r"(?:static struct sysrq_key_op sysrq_axp_mark_op = \{.*?\};\n|"
r"panic\(\"sysrq triggered crash\\n\"\);\n\})",
re.S,
)
m = pat.search(t)
if m:
t = t[: m.start()] + new_crash + t[m.end() :]
else:
raise SystemExit(f"could not replace prior sysrq axp block in {path}")
else:
stock = """static void sysrq_handle_crash(int key)
{
/* release the RCU read lock before crashing */
rcu_read_unlock();
panic("sysrq triggered crash\\n");
}
"""
if stock not in t:
raise SystemExit(f"unrecognized sysrq_handle_crash form in {path}")
t = t.replace(stock, new_crash, 1)
if "axp_sysrq_mark_init" not in t:
t += """
/* AXP_Resurection: axp-diag-sysrq-v4-reg */
static int __init axp_sysrq_mark_init(void)
{
register_sysrq_key('x', &sysrq_axp_mark_op);
return 0;
}
device_initcall(axp_sysrq_mark_init);
"""
else:
t = re.sub(
r"axp-diag-sysrq-v[0-9]+-reg",
"axp-diag-sysrq-v4-reg",
t,
count=1,
)
path.write_text(t)
print(f"patched sysrq v4 in {path}")
def main() -> int:
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} /path/to/msm-4.14", file=sys.stderr)
return 2
root = Path(sys.argv[1])
write_capture_c(root)
patch_makefile(root / "kernel" / "Makefile")
patch_arm64_setup(root / "arch" / "arm64" / "kernel" / "setup.c")
patch_main_mm(root / "init" / "main.c")
patch_fortify_panic(root / "lib" / "string.c")
patch_sysrq(root / "drivers" / "tty" / "sysrq.c")
print(f"fortify-diag v4 apply OK attempt={ATTEMPT}")
return 0
if __name__ == "__main__":
raise SystemExit(main())