Release-keys/AVB, CVE clean+hi batches, Yama/slabrand, Pro branding, bundled apps, and AXP-class product surface docs/scripts.
79 lines
3.1 KiB
Python
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())
|