#!/usr/bin/env python3 """Fill the source provider's normal POST HMAC field after final kernel link. Implements the source fipspost_get_hmac/hmacfiletool build contract: HMAC-SHA256 with a one-byte zero key over the first __TEXT[ _EXEC ]/__text section. No selftest or integrity check is disabled. Only locally compiled input is used. static_if_init rewrites __text before the POST runs. It stores absolute instructions (b or nop), so the sites of keys that boot flips are written here in their final state and the boot rewrite leaves the hashed bytes unchanged. --kernel-args names the boot arguments the kernel starts with. """ import argparse import hashlib import hmac import json from pathlib import Path import struct from kernel_target import ARCH, SUBTYPE parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('kernel', type=Path) parser.add_argument('--kernel-args', default='', help='boot arguments, to refuse ones that flip more static_if keys') args = parser.parse_args() # kern_feature_override_apply flips assert and sched debug keys only for these arguments. for argument in args.kernel_args.split(): if argument.lstrip('-').split('=', 1)[0] in ('validation_disables', 'serverperfmode', 'lcks'): raise SystemExit(f'{argument} flips static_if keys at boot that this seal does not model') data = bytearray(args.kernel.read_bytes()) magic, cpu, subtype, kind = struct.unpack_from('<4I', data) header = 0 if (magic, cpu, subtype & 0xff) == (0xfeedfacf, 0x100000c, SUBTYPE) and kind == 12: # A boot kernel collection: seal its com.apple.kernel entry. Section offsets are collection file offsets. # The emitter moves the native text, so the HMAC is computed here, after emission. The static_if sites # were prepatched when the native kernel was sealed before emission. offset = 32 for _ in range(struct.unpack_from('> 2) & 0x03ffffff) expected, final = (branch, 0xd503201f) if link & 1 else (0xd503201f, branch) if current == final: # Sealed before: the kernel build seals, and packaging seals again with the boot arguments. patched += 1 continue if current != expected: raise SystemExit(f'static_if site {point:#x} holds {current:#010x}, not the emitted instruction') struct.pack_into('