52 lines
2.5 KiB
Python
52 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate Debian's ARM64 binfmt definition; install only with --install.
|
|
|
|
Run in the existing vm-builder container with the host binfmt filesystem mounted
|
|
at /host-binfmt. Keep the registering process alive for readback and rollback.
|
|
Never pass decoded binary NUL bytes to the kernel's registration text parser.
|
|
"""
|
|
import argparse
|
|
import codecs
|
|
from pathlib import Path
|
|
import subprocess
|
|
|
|
|
|
def registration(definition, native_header):
|
|
fields=dict(line.split(' ',1) for line in definition.splitlines() if ' ' in line)
|
|
magic=codecs.decode(fields['magic'],'unicode_escape').encode('latin1')
|
|
mask=codecs.decode(fields['mask'],'unicode_escape').encode('latin1')
|
|
if len(magic)!=20 or len(mask)!=20 or magic[18:20]!=b'\xb7\x00' or mask[18:20]!=b'\xff\xff':
|
|
raise ValueError('Definition must explicitly match the complete AArch64 ELF machine field')
|
|
def matches(header):return all((a&m)==(b&m) for a,b,m in zip(header,magic,mask))
|
|
if len(native_header)<20 or matches(native_header):raise ValueError('Definition matches the native interpreter host')
|
|
for machine,elf_class in ((62,2),(3,1),(40,1)):
|
|
other=bytearray(magic);other[4]=elf_class;other[18:20]=machine.to_bytes(2,'little')
|
|
if matches(other):raise ValueError('Definition matches another architecture')
|
|
value=f":verstack_arm64:M:0:{fields['magic']}:{fields['mask']}:{fields['interpreter']}:PF"
|
|
if '\0' in value or len(value.split(':'))!=8:raise ValueError('Invalid registration encoding')
|
|
return value,magic,mask
|
|
|
|
|
|
def main():
|
|
parser=argparse.ArgumentParser();parser.add_argument('--install',action='store_true')
|
|
args=parser.parse_args()
|
|
definition=Path('/usr/share/binfmts/qemu-aarch64').read_text()
|
|
value,magic,mask=registration(definition,Path('/bin/true').read_bytes()[:20])
|
|
print('Validated full ARM64 signature; x86-64, x86 and ARM32 excluded.',flush=True)
|
|
if not args.install:return
|
|
root=Path('/host-binfmt');entry=root/'verstack_arm64'
|
|
if entry.exists():raise SystemExit('Existing registration retained; inspect it before replacing.')
|
|
try:
|
|
(root/'register').write_text(value)
|
|
actual=entry.read_text()
|
|
if f'magic {magic.hex()}' not in actual or f'mask {mask.hex()}' not in actual:
|
|
raise RuntimeError('Kernel readback differs from validated signature')
|
|
subprocess.run(['/bin/true'],check=True)
|
|
except BaseException:
|
|
if entry.exists():entry.write_text('-1')
|
|
raise
|
|
print(actual,flush=True)
|
|
|
|
|
|
if __name__=='__main__':main()
|