DF-5276 / vpd_shim.h
/*- * vpd_shim.h -- userspace shim that lets the VERBATIM-extracted VPD parser * from sys/bus/pci/pci.c compile and run in a user process. * * The kernel API surface (kmalloc/kprintf/KASSERT/DELAY/le32toh, the * PCIB_READ_CONFIG/PCIB_WRITE_CONFIG dispatch, pcicfgregs) is mapped onto: * - a guard-page allocator (every allocation is followed by a PROT_NONE * page, so the first out-of-bounds byte write past a chunk faults at a * precisely known offset), with allocation accounting; * - a simulated malicious PCI device that serves an attacker-controlled * VPD byte stream and completes every VPD data transfer immediately * (bit 15 of the VPD address register), which is exactly the behaviour * of an emulated/compromised device. * * DF-5276 / DF-5277 / DF-5278 evidence harness. Not part of the kernel. */ #ifndef VPD_SHIM_H #define VPD_SHIM_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <sys/mman.h> #include <sys/endian.h> /* ---------------- kernel API surface ---------------- */ struct shim_dev { int unused; }; typedef struct shim_dev *device_t; struct shim_malloc_type; #define M_DEVBUF ((struct shim_malloc_type *)0) #define M_WAITOK 0 #define M_NOWAIT 1 #define M_ZERO 2 #ifndef KASSERT #define KASSERT(x, y) ((void)0) #endif #define DELAY(us) do { } while (0) /* malicious device: no delay */ #define kprintf printf /* pcicfgregs is mapped by vpd_harness.c AFTER the verbatim vpd structs * (vpd_structs.h) have been included; same for pci_devinfo. */ /* ---------------- guard-page allocator + accounting ---------------- */ struct sh_blk { void *base; /* mmap base */ void *p; /* returned pointer (== base) */ size_t sz; /* requested size */ size_t mapsz; /* total mapped (incl. guard page) */ struct sh_blk *next; }; extern size_t sh_nalloc, sh_nrealloc, sh_bytes, sh_maxblk; extern const char *sh_phase; /* current test phase, for the SEGV report */ void *sh_kmalloc(size_t sz, int flags); void *sh_krealloc(void *p, size_t sz); void sh_kfree(void *p); struct sh_blk *sh_find_block(const void *addr); #define kmalloc(sz, type, flags) sh_kmalloc((sz), (flags)) #define krealloc(p, sz, type, flags) sh_krealloc((p), (sz)) #define kfree(p, type) sh_kfree((p)) /* ---------------- simulated malicious PCI device ---------------- */ #define SIM_VPDBASE 0x30 /* offset of the forged VPD capability */ #define SIM_PCIR_VPD_ADDR 0x2 #define SIM_PCIR_VPD_DATA 0x4 /* verbatim sys/bus/pci/pcireg.h:527-528 */ #define PCIR_VPD_ADDR 0x2 #define PCIR_VPD_DATA 0x4 extern uint8_t sim_stream[1 << 20]; extern size_t sim_len; /* crafted prefix length */ extern size_t sim_repeat_off, sim_repeat_len; extern int sim_endless; /* wrap the repeat region forever */ extern size_t sim_serve_cap; /* stop completing past this offset */ extern size_t sim_reads, sim_addr_writes; void sim_reset(void); uint32_t sim_read_config(int reg, int width); void sim_write_config(int reg, uint32_t val, int width); #define PCIB_READ_CONFIG(pcib, b, s, f, n, w) sim_read_config(n, w) #define PCIB_WRITE_CONFIG(pcib, b, s, f, n, v, w) sim_write_config(n, v, w) /* These two macros are live in pci.c from pci_read_capabilities() down * through pci_read_vpd() ("REG and WREG use carry through"), so the shim * defines them exactly as sys/bus/pci/pci.c:850-851 does. */ #define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) #define WREG(n, v, w) PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w) #endif /* VPD_SHIM_H */ |