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
Vendored
+27
@@ -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`.
|
||||
+244
@@ -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())
|
||||
Vendored
Executable
+597
@@ -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())
|
||||
Reference in new issue
Block a user