DF-4386 / trigger.c
/* * DF-4386 trigger replica: hw.oceN.firmware_version served by strlen(). * * oce_mbox.c:289 bcopy(fw_ver_str, sc->fw_version, 32); // 32 * device bytes, NUL not guaranteed * oce_sysctl.c:84-89 SYSCTL_ADD_STRING(.. &sc->fw_version, * sizeof(sc->fw_version) ..) * kern_sysctl.c:1171 SYSCTL_OUT(req, arg1, strlen(arg1)+1); * ^^^^ * unbounded strlen on a buffer whose 32 bytes * may all be non-NUL -> walks past fw_version * into the rest of struct oce_softc (macaddr, * OCE_DMA_MEM bsmbz with kernel pointers) and * hands the bytes to any unprivileged reader. * * Guard-page model: 32 readable bytes (the hostile device string), * then more readable bytes modeling the adjacent softc fields; the * strlen walk is demonstrated by counting how far it goes. * * Build: cc -O2 -o trigger trigger.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <sys/mman.h> int main(void) { size_t page = 4096; uint8_t *region = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (region == MAP_FAILED) { perror("mmap"); return 1; } /* softc model: [0..31] = fw_version filled with 32 non-NUL bytes * by the device; [32..] = following softc fields, non-zero */ memset(region, 'A', 32); memset(region + 32, 0xB1, 256); /* macaddr, bsmbx, ... */ /* one NUL eventually, modeling a pointer's zero byte */ region[32 + 55] = 0; volatile size_t len = strlen((char *)region); /* :1171 */ printf("fw_version capacity : 32 bytes (all non-NUL from device)\n"); printf("strlen() walked : %zu bytes (+%zu past the buffer)\n", len, len - 32); if (len > 32) { printf("RESULT: strlen OOB confirmed; kernel copies len+1 " "bytes (incl. adjacent softc fields) to userspace\n"); return 0; } printf("RESULT: bounded (unexpected)\n"); return 1; } |