DF-3812 / vpidx_oob_arith.c
/* * DF-3812 — offset-arithmetic demonstrator (host-compiled, no kernel, no HW). * * Replicates the exact index chain of the bug to show how far out of the * kmalloc'd isp_param array a firmware-controlled in_vpidx lands: * * isp_freebsd.c:2627 chan = ISP_GET_VPIDX(isp, inot->in_vpidx); * ISP_GET_VPIDX(isp, tag) = (MULTIID fw) ? tag : 0 * (ispmbox.h:861-862) -> chan is a RAW 8-bit value * isp_freebsd.c:2677 isp_add_wwn_entry(isp, chan, wwn, nphdl, portid); * isp_library.c:2398 fcp = FCPARAM(isp, chan); * ispvar.h:644 FCPARAM(isp, chan) = &((fcparam *)isp->isp_param)[chan] * isp_pci.c:824-832 isp_param = kmalloc(sizeof(fcparam) * isp_nchan), * isp_nchan in {1, 2} (isp_pci.c:662/732/749) * * The struct below is a size-faithful replica of ispvar.h's fcparam * (MAX_FC_TARG = 512, MAX_NPORT_HANDLE = 2048) only for the arithmetic; every * field is char padding. Build: cc -o vpidx_oob_arith vpidx_oob_arith.c */ #include <stdio.h> #include <stdint.h> #include <stddef.h> #define MAX_FC_TARG 512 #define MAX_NPORT_HANDLE 2048 typedef struct { char _[8 + 4 + 4 + 4 + 2 + 2 + 1 + 1 + 8 + 8 + 4 + 4 + 4 + 4 + 4]; } fcportdb_t; /* ~58+ B; real one is >= this */ typedef struct { char head[64]; /* scalars, pointers, maps */ uint16_t isp_tgt_map[MAX_NPORT_HANDLE]; /* 4096 B — real offset ~64KB into fcp */ char portdb[MAX_FC_TARG * 128]; /* >= 512 * 128 = 64KB (real fcportdb_t is larger than 128B) */ } fcparam_replica; int main(void) { int nchan, chan; size_t alloc_sz; printf("sizeof(fcparam) replica (LOWER BOUND; real is larger): %zu\n", sizeof(fcparam_replica)); for (nchan = 1; nchan <= 2; nchan++) { alloc_sz = sizeof(fcparam_replica) * nchan; printf("\nisp_nchan=%d kmalloc size >= %zu bytes\n", nchan, alloc_sz); for (chan = 1; chan <= 255; chan += 51) { ptrdiff_t off = (ptrdiff_t)sizeof(fcparam_replica) * chan; printf(" in_vpidx=%3d -> FCPARAM offset %11td bytes -> %s by %td\n", chan, off, off >= (ptrdiff_t)alloc_sz ? "OUT OF BOUNDS" : "in bounds", off - (ptrdiff_t)alloc_sz); } printf(" in_vpidx=255 (max uint8_t) -> offset %td bytes past a %zu-byte block\n", (ptrdiff_t)sizeof(fcparam_replica) * 255, alloc_sz); } printf("\nWritable via that OOB pointer (isp_library.c:2407-2497):\n"); printf(" fcp->isp_tgt_map[nphdl] (read + write i+1)\n"); printf(" lp->portid = s_id (write, remote-controlled)\n"); printf(" lp->port_wwn = ini (write, remote-controlled 8B)\n"); printf(" lp->target_mode/handle/etc.\n"); return 0; } |