Files
AXP-Resurection/scripts/009-fortify-select-family.py
sunfish-admin deaaf42caa 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.
2026-10-05 10:42:00 +02:00

79 lines
3.1 KiB
Python

#!/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())