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